summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorChunseok Lee <chunseok.lee@samsung.com>2020-12-14 14:43:04 +0900
committerChunseok Lee <chunseok.lee@samsung.com>2020-12-14 14:43:04 +0900
commit12d88feea8573f8490629cf62fc342b152e57d65 (patch)
tree3c734cc4d629834d2d523f4575ef84cd64684e57 /runtime
parentd6b371e095d737922187a518b8faba1ef6f3a2b1 (diff)
downloadnnfw-12d88feea8573f8490629cf62fc342b152e57d65.tar.gz
nnfw-12d88feea8573f8490629cf62fc342b152e57d65.tar.bz2
nnfw-12d88feea8573f8490629cf62fc342b152e57d65.zip
Imported Upstream version 1.11.0upstream/1.11.0
Diffstat (limited to 'runtime')
-rw-r--r--runtime/3rdparty/.FORMATDENY0
-rw-r--r--runtime/3rdparty/CMakeLists.txt4
-rw-r--r--runtime/3rdparty/half/CMakeLists.txt2
-rw-r--r--runtime/3rdparty/half/include/Half.h24
-rw-r--r--runtime/3rdparty/half/include/half/.FORMATDENY0
-rw-r--r--runtime/3rdparty/half/include/half/ChangeLog.txt205
-rw-r--r--runtime/3rdparty/half/include/half/LICENSE.txt21
-rw-r--r--runtime/3rdparty/half/include/half/README.txt317
-rw-r--r--runtime/3rdparty/half/include/half/include/half.hpp4575
-rw-r--r--runtime/3rdparty/jsoncpp/CMakeLists.txt6
-rw-r--r--runtime/3rdparty/jsoncpp/README.md11
-rw-r--r--runtime/3rdparty/jsoncpp/json/json-forwards.h315
-rw-r--r--runtime/3rdparty/jsoncpp/json/json.h2133
-rw-r--r--runtime/3rdparty/jsoncpp/jsoncpp.cpp5651
-rw-r--r--runtime/3rdparty/lcov-to-cobertura-xml/README.md5
-rwxr-xr-xruntime/3rdparty/lcov-to-cobertura-xml/lcov_cobertura.py414
-rw-r--r--runtime/CMakeLists.txt1
-rw-r--r--runtime/contrib/CMakeLists.txt1
-rw-r--r--runtime/contrib/TFLiteSharp/README.md92
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteNative/CMakeLists.txt67
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteNative/include/tflite_log.h69
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteNative/include/tflite_nativewrapper.h55
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteNative/src/tflite_nativewrapper.cpp142
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteNative/tflite-native.pc.in13
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp.sln25
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/Interop/Interop.Libraries.cs23
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/Interop/Interop.TFLite.cs37
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/TFLiteSharp.csproj52
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/src/Datatype.cs31
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/src/Interpreter.cs263
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest.sln31
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest/Program.cs38
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest/TFLiteSharpTest.csproj12
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp.csproj54
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp_App.cs65
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp_Main.cs20
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mobilenet_v1_1.0_224.tflitebin0 -> 16900960 bytes
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mouse1.bmpbin0 -> 2764854 bytes
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mouse_224.bmpbin0 -> 150582 bytes
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteTestApp/shared/res/TFLiteTestApp.pngbin0 -> 10097 bytes
-rw-r--r--runtime/contrib/TFLiteSharp/TFLiteTestApp/tizen-manifest.xml14
-rw-r--r--runtime/contrib/TFLiteSharp/packaging/TFLiteSharp.manifest5
-rw-r--r--runtime/contrib/TFLiteSharp/packaging/TFLiteSharp.spec103
-rw-r--r--runtime/contrib/TFLiteSharp/packaging/tflite-native.manifest5
-rw-r--r--runtime/contrib/android/.gitignore6
-rw-r--r--runtime/contrib/android/README.md76
-rw-r--r--runtime/contrib/android/api/Android.mk8
-rw-r--r--runtime/contrib/android/api/Application.mk3
-rw-r--r--runtime/contrib/android/api/Prebuilt.mk70
-rw-r--r--runtime/contrib/android/api/build.gradle69
-rw-r--r--runtime/contrib/android/api/proguard-rules.pro21
-rw-r--r--runtime/contrib/android/api/src/main/AndroidManifest.xml2
-rw-r--r--runtime/contrib/android/api/src/main/java/com/samsung/onert/Helper.java128
-rw-r--r--runtime/contrib/android/api/src/main/java/com/samsung/onert/NativeSessionWrapper.java139
-rw-r--r--runtime/contrib/android/api/src/main/java/com/samsung/onert/Session.java61
-rw-r--r--runtime/contrib/android/api/src/main/java/com/samsung/onert/Tensor.java73
-rw-r--r--runtime/contrib/android/api/src/main/java/com/samsung/onert/TensorInfo.java75
-rw-r--r--runtime/contrib/android/api/src/main/native/Android.mk18
-rw-r--r--runtime/contrib/android/api/src/main/native/onert-native-api.cpp299
-rw-r--r--runtime/contrib/android/api/src/main/native/onert-native-api.h145
-rw-r--r--runtime/contrib/android/api/src/main/native/onert-native-helper.cpp226
-rw-r--r--runtime/contrib/android/api/src/main/native/onert-native-helper.h34
-rw-r--r--runtime/contrib/android/api/src/main/native/onert-native-internal.cpp157
-rw-r--r--runtime/contrib/android/api/src/main/native/onert-native-internal.h64
-rw-r--r--runtime/contrib/android/build.gradle31
-rw-r--r--runtime/contrib/android/gradle.properties2
-rw-r--r--runtime/contrib/android/gradle/wrapper/gradle-wrapper.jarbin0 -> 58694 bytes
-rw-r--r--runtime/contrib/android/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xruntime/contrib/android/gradlew183
-rw-r--r--runtime/contrib/android/gradlew.bat103
-rw-r--r--runtime/contrib/android/settings.gradle2
-rwxr-xr-xruntime/contrib/android/update_jni_header.sh12
-rw-r--r--runtime/contrib/android_benchmark_app/AndroidManifest.xml21
-rw-r--r--runtime/contrib/android_benchmark_app/CMakeLists.txt97
-rw-r--r--runtime/contrib/android_benchmark_app/README.md58
-rw-r--r--runtime/contrib/android_benchmark_app/cpp/ndk_main.cpp244
-rw-r--r--runtime/contrib/android_benchmark_app/cpp/ndk_main.h108
-rw-r--r--runtime/contrib/android_benchmark_app/java/com/ndk/tflbench/MainActivity.java110
-rw-r--r--runtime/contrib/android_benchmark_app/res/drawable-hdpi/ic_launcher.pngbin0 -> 9397 bytes
-rw-r--r--runtime/contrib/android_benchmark_app/res/drawable-mdpi/ic_launcher.pngbin0 -> 5237 bytes
-rw-r--r--runtime/contrib/android_benchmark_app/res/drawable-xhdpi/ic_launcher.pngbin0 -> 14383 bytes
-rw-r--r--runtime/contrib/android_benchmark_app/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 19388 bytes
-rw-r--r--runtime/contrib/android_benchmark_app/res/layout/activity_main.xml38
-rw-r--r--runtime/contrib/android_benchmark_app/res/values-v21/styles.xml5
-rw-r--r--runtime/contrib/android_benchmark_app/res/values/strings.xml6
-rw-r--r--runtime/contrib/android_tflite/CMakeLists.txt31
-rw-r--r--runtime/contrib/android_tflite/builtin_ops_jni.cc30
-rw-r--r--runtime/contrib/benchmark_acl/.FORMATDENY0
-rw-r--r--runtime/contrib/benchmark_acl/CMakeLists.txt24
-rw-r--r--runtime/contrib/benchmark_acl/src/Benchmark.cpp74
-rw-r--r--runtime/contrib/benchmark_acl/src/Benchmark.h82
-rw-r--r--runtime/contrib/benchmark_acl/src/benchmark_googlenet.cpp242
-rw-r--r--runtime/contrib/benchmark_acl/src/benchmark_inception_v3.cpp891
-rw-r--r--runtime/contrib/benchmark_acl/src/benchmark_mobilenet.cpp265
-rw-r--r--runtime/contrib/custom_op/README.md25
-rw-r--r--runtime/contrib/detection/CMakeLists.txt11
-rw-r--r--runtime/contrib/detection/detection.cpp74
-rw-r--r--runtime/contrib/heap_trace/CMakeLists.txt23
-rw-r--r--runtime/contrib/heap_trace/src/aligned_alloc_stub.cc45
-rw-r--r--runtime/contrib/heap_trace/src/calloc_stub.cc46
-rw-r--r--runtime/contrib/heap_trace/src/cl_create_buffer_stub.cc44
-rw-r--r--runtime/contrib/heap_trace/src/cl_release_mem_object.cc43
-rw-r--r--runtime/contrib/heap_trace/src/cl_retain_mem_object_stub.cc43
-rw-r--r--runtime/contrib/heap_trace/src/free_stub.cc42
-rw-r--r--runtime/contrib/heap_trace/src/function_resolver.h29
-rw-r--r--runtime/contrib/heap_trace/src/malloc_stub.cc45
-rw-r--r--runtime/contrib/heap_trace/src/memory_pool_for_symbol_searcher_internals.cc21
-rw-r--r--runtime/contrib/heap_trace/src/memory_pool_for_symbol_searcher_internals.h78
-rw-r--r--runtime/contrib/heap_trace/src/posix_memalign_stub.cc46
-rw-r--r--runtime/contrib/heap_trace/src/realloc_stub.cc46
-rw-r--r--runtime/contrib/heap_trace/src/symbol_searcher.cc102
-rw-r--r--runtime/contrib/heap_trace/src/symbol_searcher.h26
-rw-r--r--runtime/contrib/heap_trace/src/trace.cc115
-rw-r--r--runtime/contrib/heap_trace/src/trace.h86
-rw-r--r--runtime/contrib/heap_trace/src/valloc_stub.cc45
-rw-r--r--runtime/contrib/heap_trace/tests/CMakeLists.txt48
-rw-r--r--runtime/contrib/heap_trace/tests/src/aligned_alloc_interception_test.cc90
-rw-r--r--runtime/contrib/heap_trace/tests/src/calloc_interception_test.cc91
-rw-r--r--runtime/contrib/heap_trace/tests/src/cl_create_buffer_interception_test.cc89
-rw-r--r--runtime/contrib/heap_trace/tests/src/cl_release_mem_object_interception_test.cc114
-rw-r--r--runtime/contrib/heap_trace/tests/src/cl_retain_mem_object_interception_test.cc85
-rw-r--r--runtime/contrib/heap_trace/tests/src/common_test_environment.cc51
-rw-r--r--runtime/contrib/heap_trace/tests/src/common_test_environment.h38
-rw-r--r--runtime/contrib/heap_trace/tests/src/file_content_manipulations.cc25
-rw-r--r--runtime/contrib/heap_trace/tests/src/file_content_manipulations.h24
-rw-r--r--runtime/contrib/heap_trace/tests/src/free_interception_test.cc77
-rw-r--r--runtime/contrib/heap_trace/tests/src/main.cc23
-rw-r--r--runtime/contrib/heap_trace/tests/src/malloc_interception_test.cc103
-rw-r--r--runtime/contrib/heap_trace/tests/src/memory_pool_for_symbol_searcher_internals_test.cc69
-rw-r--r--runtime/contrib/heap_trace/tests/src/posix_memalign_interception_test.cc101
-rw-r--r--runtime/contrib/heap_trace/tests/src/realloc_interception_test.cc126
-rw-r--r--runtime/contrib/heap_trace/tests/src/symbol_searcher_test.cc99
-rw-r--r--runtime/contrib/heap_trace/tests/src/test_sample1.h25
-rw-r--r--runtime/contrib/heap_trace/tests/src/test_sample1/test_sample1.cc27
-rw-r--r--runtime/contrib/heap_trace/tests/src/test_sample2.h26
-rw-r--r--runtime/contrib/heap_trace/tests/src/test_sample2/test_sample2.cc24
-rw-r--r--runtime/contrib/heap_trace/tests/src/test_sample3.h25
-rw-r--r--runtime/contrib/heap_trace/tests/src/test_sample3/test_sample3.cc20
-rw-r--r--runtime/contrib/heap_trace/tests/src/test_sample4.h25
-rw-r--r--runtime/contrib/heap_trace/tests/src/test_sample4/test_sample4.cc21
-rw-r--r--runtime/contrib/heap_trace/tests/src/trace_test.cc175
-rw-r--r--runtime/contrib/heap_trace/tests/src/valloc_interception_test.cc89
-rw-r--r--runtime/contrib/labs/CMakeLists.txt5
-rw-r--r--runtime/contrib/labs/jniacl/CMakeLists.txt18
-rw-r--r--runtime/contrib/labs/jniacl/src/io_accessor.cc96
-rw-r--r--runtime/contrib/labs/jniacl/src/io_accessor.h93
-rw-r--r--runtime/contrib/labs/jniacl/src/jniacl_main.cc52
-rw-r--r--runtime/contrib/labs/opencl_test/CMakeLists.txt11
-rw-r--r--runtime/contrib/labs/opencl_test/README.md8
-rw-r--r--runtime/contrib/labs/opencl_test/src/opencl_test.cc386
-rw-r--r--runtime/contrib/labs/tflite_examples/CMakeLists.txt2
-rw-r--r--runtime/contrib/labs/tflite_examples/src/conv.cpp330
-rw-r--r--runtime/contrib/logging/CMakeLists.txt12
-rw-r--r--runtime/contrib/logging/include/operand.def12
-rw-r--r--runtime/contrib/logging/include/operation.def15
-rw-r--r--runtime/contrib/logging/src/nnapi_logging.cc415
-rw-r--r--runtime/contrib/mlapse/CMakeLists.txt8
-rw-r--r--runtime/contrib/mlapse/README.md3
-rw-r--r--runtime/contrib/mlapse/tfl/CMakeLists.txt11
-rw-r--r--runtime/contrib/mlapse/tfl/driver.cc279
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/CSV_report_generator.cc67
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/CSV_report_generator.h50
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/benchmark_observer.cc24
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/benchmark_observer.h77
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/benchmark_runner.cc124
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/benchmark_runner.h63
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/multicast_observer.cc17
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/multicast_observer.h75
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/tfl/load.cc55
-rw-r--r--runtime/contrib/mlapse/tfl/mlapse/tfl/load.h40
-rw-r--r--runtime/contrib/style_transfer_app/CMakeLists.txt40
-rw-r--r--runtime/contrib/style_transfer_app/README.md23
-rw-r--r--runtime/contrib/style_transfer_app/src/args.cc96
-rw-r--r--runtime/contrib/style_transfer_app/src/args.h53
-rw-r--r--runtime/contrib/style_transfer_app/src/bitmap_helper.cc236
-rw-r--r--runtime/contrib/style_transfer_app/src/bitmap_helper.h61
-rw-r--r--runtime/contrib/style_transfer_app/src/jpeg_helper.cc132
-rw-r--r--runtime/contrib/style_transfer_app/src/jpeg_helper.h43
-rw-r--r--runtime/contrib/style_transfer_app/src/style_transfer_app.cc301
-rw-r--r--runtime/contrib/tflite_classify/CMakeLists.txt22
-rw-r--r--runtime/contrib/tflite_classify/src/ImageClassifier.cc107
-rw-r--r--runtime/contrib/tflite_classify/src/ImageClassifier.h99
-rw-r--r--runtime/contrib/tflite_classify/src/InferenceInterface.cc114
-rw-r--r--runtime/contrib/tflite_classify/src/InferenceInterface.h93
-rw-r--r--runtime/contrib/tflite_classify/src/tflite_classify.cc122
-rw-r--r--runtime/contrib/tflite_test/CMakeLists.txt16
-rw-r--r--runtime/contrib/tflite_test/tflite_test.cpp234
-rw-r--r--runtime/contrib/uben/CMakeLists.txt29
-rw-r--r--runtime/contrib/uben/Convolution.cpp429
-rw-r--r--runtime/contrib/uben/Softmax.cpp54
-rw-r--r--runtime/libs/CMakeLists.txt4
-rw-r--r--runtime/libs/benchmark/CMakeLists.txt5
-rw-r--r--runtime/libs/benchmark/include/benchmark.h23
-rw-r--r--runtime/libs/benchmark/include/benchmark/CsvHeader.lst19
-rw-r--r--runtime/libs/benchmark/include/benchmark/CsvWriter.h62
-rw-r--r--runtime/libs/benchmark/include/benchmark/MemoryInfo.h40
-rw-r--r--runtime/libs/benchmark/include/benchmark/MemoryPoller.h81
-rw-r--r--runtime/libs/benchmark/include/benchmark/Phase.h62
-rw-r--r--runtime/libs/benchmark/include/benchmark/Phases.h70
-rw-r--r--runtime/libs/benchmark/include/benchmark/Result.h50
-rw-r--r--runtime/libs/benchmark/include/benchmark/Types.h133
-rw-r--r--runtime/libs/benchmark/src/CsvWriter.cpp123
-rw-r--r--runtime/libs/benchmark/src/MemoryInfo.cpp169
-rw-r--r--runtime/libs/benchmark/src/MemoryPoller.cpp175
-rw-r--r--runtime/libs/benchmark/src/Phases.cpp111
-rw-r--r--runtime/libs/benchmark/src/Result.cpp240
-rw-r--r--runtime/libs/misc/CMakeLists.txt11
-rw-r--r--runtime/libs/misc/examples/tensor_index_iterator.cpp74
-rw-r--r--runtime/libs/misc/include/misc/EnvVar.h120
-rw-r--r--runtime/libs/misc/include/misc/RandomGenerator.h87
-rw-r--r--runtime/libs/misc/include/misc/benchmark.h87
-rw-r--r--runtime/libs/misc/include/misc/feature/Index.h137
-rw-r--r--runtime/libs/misc/include/misc/feature/IndexIterator.h105
-rw-r--r--runtime/libs/misc/include/misc/feature/Object.h117
-rw-r--r--runtime/libs/misc/include/misc/feature/Reader.h69
-rw-r--r--runtime/libs/misc/include/misc/feature/Shape.h77
-rw-r--r--runtime/libs/misc/include/misc/feature/TextFormatter.h116
-rw-r--r--runtime/libs/misc/include/misc/fp32.h99
-rw-r--r--runtime/libs/misc/include/misc/kernel/IndexIterator.h102
-rw-r--r--runtime/libs/misc/include/misc/kernel/Reader.h60
-rw-r--r--runtime/libs/misc/include/misc/kernel/Shape.h68
-rw-r--r--runtime/libs/misc/include/misc/matrix/IndexIterator.h99
-rw-r--r--runtime/libs/misc/include/misc/matrix/Reader.h59
-rw-r--r--runtime/libs/misc/include/misc/matrix/Shape.h63
-rw-r--r--runtime/libs/misc/include/misc/polymorphic_downcast.h43
-rw-r--r--runtime/libs/misc/include/misc/string_helpers.h81
-rw-r--r--runtime/libs/misc/include/misc/tensor/Comparator.h95
-rw-r--r--runtime/libs/misc/include/misc/tensor/Diff.h70
-rw-r--r--runtime/libs/misc/include/misc/tensor/Index.h107
-rw-r--r--runtime/libs/misc/include/misc/tensor/IndexEnumerator.h131
-rw-r--r--runtime/libs/misc/include/misc/tensor/IndexFormatter.h75
-rw-r--r--runtime/libs/misc/include/misc/tensor/IndexIterator.h107
-rw-r--r--runtime/libs/misc/include/misc/tensor/NonIncreasingStride.h88
-rw-r--r--runtime/libs/misc/include/misc/tensor/Object.h110
-rw-r--r--runtime/libs/misc/include/misc/tensor/Reader.h58
-rw-r--r--runtime/libs/misc/include/misc/tensor/Shape.h150
-rw-r--r--runtime/libs/misc/include/misc/tensor/Zipper.h104
-rw-r--r--runtime/libs/misc/include/misc/vector.h52
-rw-r--r--runtime/libs/misc/include/misc/vector/Object.h92
-rw-r--r--runtime/libs/misc/include/misc/vector/Reader.h58
-rw-r--r--runtime/libs/misc/src/RandomGenerator.cpp83
-rw-r--r--runtime/libs/misc/src/tensor/Comparator.cpp54
-rw-r--r--runtime/libs/misc/src/tensor/IndexFormatter.cpp49
-rw-r--r--runtime/libs/misc/src/tensor/NonIncreasingStride.cpp46
-rw-r--r--runtime/libs/misc/src/tensor/Shape.cpp107
-rw-r--r--runtime/libs/nnapi/CMakeLists.txt4
-rw-r--r--runtime/libs/nnapi/include/NeuralNetworksExShim.h65
-rw-r--r--runtime/libs/nnapi/include/NeuralNetworksLoadHelpers.h138
-rw-r--r--runtime/libs/nnapi/include/NeuralNetworksShim.h1554
-rw-r--r--runtime/libs/nnapi/include/NeuralNetworksTypes.h216
-rw-r--r--runtime/libs/profiling/CMakeLists.txt7
-rw-r--r--runtime/libs/profiling/include/profiling/profile_buffer.h170
-rw-r--r--runtime/libs/profiling/include/profiling/profiler.h203
-rw-r--r--runtime/libs/profiling/include/profiling/profiling.h57
-rw-r--r--runtime/libs/profiling/include/profiling/time.h37
-rw-r--r--runtime/libs/profiling/src/profiling/time.cpp57
-rw-r--r--runtime/libs/rua/CMakeLists.txt4
-rw-r--r--runtime/libs/rua/README.md4
-rw-r--r--runtime/libs/rua/anchor/CMakeLists.txt9
-rw-r--r--runtime/libs/rua/anchor/include/rua/Anchor.h38
-rw-r--r--runtime/libs/rua/anchor/src/Anchor.cpp33
-rw-r--r--runtime/libs/rua/core/CMakeLists.txt3
-rw-r--r--runtime/libs/rua/core/include/rua/Service.h159
-rw-r--r--runtime/libs/rua/dyn/CMakeLists.txt8
-rw-r--r--runtime/libs/rua/dyn/include/rua/DynamicBinder.h35
-rw-r--r--runtime/libs/rua/dyn/src/DynamicBinder.cpp354
-rw-r--r--runtime/libs/rua/shim/CMakeLists.txt4
-rw-r--r--runtime/libs/rua/shim/include/rua/Shim.h193
-rw-r--r--runtime/libs/tflite/CMakeLists.txt27
-rw-r--r--runtime/libs/tflite/include/tflite/Assert.h45
-rw-r--r--runtime/libs/tflite/include/tflite/Diff.h88
-rw-r--r--runtime/libs/tflite/include/tflite/FeatureView.h108
-rw-r--r--runtime/libs/tflite/include/tflite/InputIndex.h60
-rw-r--r--runtime/libs/tflite/include/tflite/InterpreterSession.h99
-rw-r--r--runtime/libs/tflite/include/tflite/NNAPISession.h102
-rw-r--r--runtime/libs/tflite/include/tflite/OutputIndex.h60
-rw-r--r--runtime/libs/tflite/include/tflite/Quantization.h44
-rw-r--r--runtime/libs/tflite/include/tflite/RandomTestRunner.h103
-rw-r--r--runtime/libs/tflite/include/tflite/Session.h69
-rw-r--r--runtime/libs/tflite/include/tflite/TensorLogger.h168
-rw-r--r--runtime/libs/tflite/include/tflite/TensorShapeUtils.h64
-rw-r--r--runtime/libs/tflite/include/tflite/TensorUtils.h54
-rw-r--r--runtime/libs/tflite/include/tflite/TensorView.h120
-rw-r--r--runtime/libs/tflite/include/tflite/interp/Builder.h53
-rw-r--r--runtime/libs/tflite/include/tflite/interp/FlatBufferBuilder.h64
-rw-r--r--runtime/libs/tflite/include/tflite/interp/FunctionBuilder.h67
-rw-r--r--runtime/libs/tflite/port/1.13.1/CMakeLists.txt14
-rw-r--r--runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/CustomOps.h56
-rw-r--r--runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/SquaredDifference.h76
-rw-r--r--runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/register.h46
-rw-r--r--runtime/libs/tflite/port/1.13.1/include/tflite/ext/nnapi_delegate.h92
-rw-r--r--runtime/libs/tflite/port/1.13.1/src/kernels/SquaredDifference.cpp109
-rw-r--r--runtime/libs/tflite/port/1.13.1/src/kernels/register.cpp314
-rw-r--r--runtime/libs/tflite/port/1.13.1/src/nnapi_delegate.cpp1262
-rw-r--r--runtime/libs/tflite/port/1.13.1/src/nnapi_delegate_ex_AddOpsAndParams_lambda.inc153
-rw-r--r--runtime/libs/tflite/port/CMakeLists.txt7
-rw-r--r--runtime/libs/tflite/src/Diff.cpp255
-rw-r--r--runtime/libs/tflite/src/FeatureView.cpp70
-rw-r--r--runtime/libs/tflite/src/Quantization.cpp22
-rw-r--r--runtime/libs/tflite/src/RandomTestRunner.cpp363
-rw-r--r--runtime/libs/tflite/src/TensorShapeUtils.cpp45
-rw-r--r--runtime/libs/tflite/src/TensorView.test.cpp53
-rw-r--r--runtime/libs/tflite/src/interp/FlatBufferBuilder.cpp40
-rw-r--r--runtime/libs/tflite/src/interp/FunctionBuilder.cpp34
-rw-r--r--runtime/nnapi-header/CMakeLists.txt8
-rw-r--r--runtime/nnapi-header/include/NeuralNetworks.h8166
-rw-r--r--runtime/nnapi-header/include/NeuralNetworksEx.h611
-rw-r--r--runtime/nnapi-header/include/NeuralNetworksExtensions.h117
-rw-r--r--runtime/onert/CMakeLists.txt15
-rw-r--r--runtime/onert/api/CMakeLists.txt32
-rw-r--r--runtime/onert/api/include/nnfw.h497
-rw-r--r--runtime/onert/api/include/nnfw_experimental.h99
-rw-r--r--runtime/onert/api/include/nnfw_internal.h38
-rw-r--r--runtime/onert/api/include/nnfw_version.h26
-rw-r--r--runtime/onert/api/src/CustomKernel.cc114
-rw-r--r--runtime/onert/api/src/CustomKernel.h60
-rw-r--r--runtime/onert/api/src/CustomKernelRegistry.cc64
-rw-r--r--runtime/onert/api/src/CustomKernelRegistry.h64
-rw-r--r--runtime/onert/api/src/OpMap.lst152
-rw-r--r--runtime/onert/api/src/nnfw_api.cc363
-rw-r--r--runtime/onert/api/src/nnfw_api_internal.cc895
-rw-r--r--runtime/onert/api/src/nnfw_api_internal.h161
-rw-r--r--runtime/onert/api/src/nnfw_debug.cc38
-rw-r--r--runtime/onert/backend/CMakeLists.txt6
-rw-r--r--runtime/onert/backend/acl_cl/Backend.h71
-rw-r--r--runtime/onert/backend/acl_cl/CLTimer.h108
-rw-r--r--runtime/onert/backend/acl_cl/CMakeLists.txt24
-rw-r--r--runtime/onert/backend/acl_cl/Config.cc67
-rw-r--r--runtime/onert/backend/acl_cl/Config.h50
-rw-r--r--runtime/onert/backend/acl_cl/ConstantInitializer.cc146
-rw-r--r--runtime/onert/backend/acl_cl/ConstantInitializer.h48
-rw-r--r--runtime/onert/backend/acl_cl/KernelGenerator.cc1622
-rw-r--r--runtime/onert/backend/acl_cl/KernelGenerator.h102
-rw-r--r--runtime/onert/backend/acl_cl/Optimizer.cc59
-rw-r--r--runtime/onert/backend/acl_cl/Optimizer.h47
-rw-r--r--runtime/onert/backend/acl_cl/TensorBuilder.h39
-rw-r--r--runtime/onert/backend/acl_cl/TensorManager.h78
-rw-r--r--runtime/onert/backend/acl_cl/acl_cl.cc33
-rw-r--r--runtime/onert/backend/acl_cl/operand/CLSubTensor.cc44
-rw-r--r--runtime/onert/backend/acl_cl/operand/CLSubTensor.h63
-rw-r--r--runtime/onert/backend/acl_cl/operand/CLTensor.cc58
-rw-r--r--runtime/onert/backend/acl_cl/operand/CLTensor.h73
-rw-r--r--runtime/onert/backend/acl_cl/operand/ICLTensor.cc60
-rw-r--r--runtime/onert/backend/acl_cl/operand/ICLTensor.h55
-rw-r--r--runtime/onert/backend/acl_common/AclActivationBuilder.h125
-rw-r--r--runtime/onert/backend/acl_common/AclConstantInitializer.cc131
-rw-r--r--runtime/onert/backend/acl_common/AclConstantInitializer.h61
-rw-r--r--runtime/onert/backend/acl_common/AclFunction.h54
-rw-r--r--runtime/onert/backend/acl_common/AclInternalBufferManager.h97
-rw-r--r--runtime/onert/backend/acl_common/AclKernelGen.h343
-rw-r--r--runtime/onert/backend/acl_common/AclLinearMemoryManager.h110
-rw-r--r--runtime/onert/backend/acl_common/AclMemoryManager.h98
-rw-r--r--runtime/onert/backend/acl_common/AclSubTensorAnalyzer.h120
-rw-r--r--runtime/onert/backend/acl_common/AclTensorBuilder.h438
-rw-r--r--runtime/onert/backend/acl_common/AclTensorManager.h306
-rw-r--r--runtime/onert/backend/acl_common/AclTensorRegistry.h53
-rw-r--r--runtime/onert/backend/acl_common/CMakeLists.txt19
-rw-r--r--runtime/onert/backend/acl_common/Convert.cc373
-rw-r--r--runtime/onert/backend/acl_common/Convert.h96
-rw-r--r--runtime/onert/backend/acl_common/IACLTensor.cc77
-rw-r--r--runtime/onert/backend/acl_common/IACLTensor.h69
-rw-r--r--runtime/onert/backend/acl_common/ParentInfo.h44
-rw-r--r--runtime/onert/backend/acl_common/Swizzle.h160
-rw-r--r--runtime/onert/backend/acl_neon/Backend.h71
-rw-r--r--runtime/onert/backend/acl_neon/CMakeLists.txt24
-rw-r--r--runtime/onert/backend/acl_neon/Config.cc47
-rw-r--r--runtime/onert/backend/acl_neon/Config.h48
-rw-r--r--runtime/onert/backend/acl_neon/ConstantInitializer.cc90
-rw-r--r--runtime/onert/backend/acl_neon/ConstantInitializer.h44
-rw-r--r--runtime/onert/backend/acl_neon/KernelGenerator.cc1429
-rw-r--r--runtime/onert/backend/acl_neon/KernelGenerator.h96
-rw-r--r--runtime/onert/backend/acl_neon/Optimizer.cc58
-rw-r--r--runtime/onert/backend/acl_neon/Optimizer.h47
-rw-r--r--runtime/onert/backend/acl_neon/TensorBuilder.h39
-rw-r--r--runtime/onert/backend/acl_neon/TensorManager.h77
-rw-r--r--runtime/onert/backend/acl_neon/acl_neon.cc33
-rw-r--r--runtime/onert/backend/acl_neon/operand/INETensor.cc40
-rw-r--r--runtime/onert/backend/acl_neon/operand/INETensor.h46
-rw-r--r--runtime/onert/backend/acl_neon/operand/NESubTensor.cc44
-rw-r--r--runtime/onert/backend/acl_neon/operand/NESubTensor.h63
-rw-r--r--runtime/onert/backend/acl_neon/operand/NETensor.cc45
-rw-r--r--runtime/onert/backend/acl_neon/operand/NETensor.h64
-rw-r--r--runtime/onert/backend/cpu/Backend.h70
-rw-r--r--runtime/onert/backend/cpu/BackendContext.h60
-rw-r--r--runtime/onert/backend/cpu/CMakeLists.txt23
-rw-r--r--runtime/onert/backend/cpu/Config.cc32
-rw-r--r--runtime/onert/backend/cpu/Config.h48
-rw-r--r--runtime/onert/backend/cpu/ConstantInitializer.cc94
-rw-r--r--runtime/onert/backend/cpu/ConstantInitializer.h63
-rw-r--r--runtime/onert/backend/cpu/ExternalContext.h61
-rw-r--r--runtime/onert/backend/cpu/KernelGenerator.cc1499
-rw-r--r--runtime/onert/backend/cpu/KernelGenerator.h114
-rw-r--r--runtime/onert/backend/cpu/StaticTensorManager.cc107
-rw-r--r--runtime/onert/backend/cpu/StaticTensorManager.h64
-rw-r--r--runtime/onert/backend/cpu/Tensor.cc32
-rw-r--r--runtime/onert/backend/cpu/Tensor.h122
-rw-r--r--runtime/onert/backend/cpu/TensorBuilder.cc90
-rw-r--r--runtime/onert/backend/cpu/TensorBuilder.h74
-rw-r--r--runtime/onert/backend/cpu/cpu.cc33
-rw-r--r--runtime/onert/backend/cpu/ops/AddNLayer.cc71
-rw-r--r--runtime/onert/backend/cpu/ops/AddNLayer.h53
-rw-r--r--runtime/onert/backend/cpu/ops/ArgMinMaxLayer.cc118
-rw-r--r--runtime/onert/backend/cpu/ops/ArgMinMaxLayer.h56
-rw-r--r--runtime/onert/backend/cpu/ops/BatchMatMulLayer.cc85
-rw-r--r--runtime/onert/backend/cpu/ops/BatchMatMulLayer.h72
-rw-r--r--runtime/onert/backend/cpu/ops/BatchToSpaceNDLayer.cc83
-rw-r--r--runtime/onert/backend/cpu/ops/BatchToSpaceNDLayer.h59
-rw-r--r--runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.cc249
-rw-r--r--runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.h69
-rw-r--r--runtime/onert/backend/cpu/ops/BroadcastToLayer.cc74
-rw-r--r--runtime/onert/backend/cpu/ops/BroadcastToLayer.h56
-rw-r--r--runtime/onert/backend/cpu/ops/CompareLayer.cc175
-rw-r--r--runtime/onert/backend/cpu/ops/CompareLayer.h57
-rw-r--r--runtime/onert/backend/cpu/ops/ConcatLayer.cc143
-rw-r--r--runtime/onert/backend/cpu/ops/ConcatLayer.h59
-rw-r--r--runtime/onert/backend/cpu/ops/ConvolutionLayer.cc211
-rw-r--r--runtime/onert/backend/cpu/ops/ConvolutionLayer.h96
-rw-r--r--runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc131
-rw-r--r--runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h81
-rw-r--r--runtime/onert/backend/cpu/ops/EinsumLayer.cc84
-rw-r--r--runtime/onert/backend/cpu/ops/EinsumLayer.h72
-rw-r--r--runtime/onert/backend/cpu/ops/ElementwiseActivationLayer.cc173
-rw-r--r--runtime/onert/backend/cpu/ops/ElementwiseActivationLayer.h67
-rw-r--r--runtime/onert/backend/cpu/ops/ElementwiseBinaryLayer.cc151
-rw-r--r--runtime/onert/backend/cpu/ops/ElementwiseBinaryLayer.h67
-rw-r--r--runtime/onert/backend/cpu/ops/ElementwiseUnaryLayer.cc390
-rw-r--r--runtime/onert/backend/cpu/ops/ElementwiseUnaryLayer.h77
-rw-r--r--runtime/onert/backend/cpu/ops/ExpandDimsLayer.cc51
-rw-r--r--runtime/onert/backend/cpu/ops/ExpandDimsLayer.h55
-rw-r--r--runtime/onert/backend/cpu/ops/FillLayer.cc81
-rw-r--r--runtime/onert/backend/cpu/ops/FillLayer.h54
-rw-r--r--runtime/onert/backend/cpu/ops/FullyConnectedLayer.cc286
-rw-r--r--runtime/onert/backend/cpu/ops/FullyConnectedLayer.h94
-rw-r--r--runtime/onert/backend/cpu/ops/FusedBatchNormLayer.cc94
-rw-r--r--runtime/onert/backend/cpu/ops/FusedBatchNormLayer.h73
-rw-r--r--runtime/onert/backend/cpu/ops/GatherLayer.cc95
-rw-r--r--runtime/onert/backend/cpu/ops/GatherLayer.h63
-rw-r--r--runtime/onert/backend/cpu/ops/L2NormLayer.cc71
-rw-r--r--runtime/onert/backend/cpu/ops/L2NormLayer.h55
-rw-r--r--runtime/onert/backend/cpu/ops/LSTMLayer.cc326
-rw-r--r--runtime/onert/backend/cpu/ops/LSTMLayer.h132
-rw-r--r--runtime/onert/backend/cpu/ops/LogSoftMaxLayer.cc102
-rw-r--r--runtime/onert/backend/cpu/ops/LogSoftMaxLayer.h64
-rw-r--r--runtime/onert/backend/cpu/ops/MatrixBandPartLayer.cc94
-rw-r--r--runtime/onert/backend/cpu/ops/MatrixBandPartLayer.h60
-rw-r--r--runtime/onert/backend/cpu/ops/MeanLayer.cc81
-rw-r--r--runtime/onert/backend/cpu/ops/MeanLayer.h60
-rw-r--r--runtime/onert/backend/cpu/ops/OneHotLayer.cc69
-rw-r--r--runtime/onert/backend/cpu/ops/OneHotLayer.h67
-rw-r--r--runtime/onert/backend/cpu/ops/OperationUtils.cc266
-rw-r--r--runtime/onert/backend/cpu/ops/OperationUtils.h215
-rw-r--r--runtime/onert/backend/cpu/ops/PackLayer.cc96
-rw-r--r--runtime/onert/backend/cpu/ops/PackLayer.h56
-rw-r--r--runtime/onert/backend/cpu/ops/PadLayer.cc80
-rw-r--r--runtime/onert/backend/cpu/ops/PadLayer.h63
-rw-r--r--runtime/onert/backend/cpu/ops/PoolLayer.cc132
-rw-r--r--runtime/onert/backend/cpu/ops/PoolLayer.h68
-rw-r--r--runtime/onert/backend/cpu/ops/PowLayer.cc73
-rw-r--r--runtime/onert/backend/cpu/ops/PowLayer.h63
-rw-r--r--runtime/onert/backend/cpu/ops/RangeLayer.cc70
-rw-r--r--runtime/onert/backend/cpu/ops/RangeLayer.h54
-rw-r--r--runtime/onert/backend/cpu/ops/RankLayer.cc50
-rw-r--r--runtime/onert/backend/cpu/ops/RankLayer.h53
-rw-r--r--runtime/onert/backend/cpu/ops/ReduceLayer.cc227
-rw-r--r--runtime/onert/backend/cpu/ops/ReduceLayer.h85
-rw-r--r--runtime/onert/backend/cpu/ops/ReshapeLayer.cc53
-rw-r--r--runtime/onert/backend/cpu/ops/ReshapeLayer.h57
-rw-r--r--runtime/onert/backend/cpu/ops/ResizeBilinearLayer.cc119
-rw-r--r--runtime/onert/backend/cpu/ops/ResizeBilinearLayer.h62
-rw-r--r--runtime/onert/backend/cpu/ops/ReverseLayer.cc68
-rw-r--r--runtime/onert/backend/cpu/ops/ReverseLayer.h58
-rw-r--r--runtime/onert/backend/cpu/ops/SelectLayer.cc89
-rw-r--r--runtime/onert/backend/cpu/ops/SelectLayer.h56
-rw-r--r--runtime/onert/backend/cpu/ops/ShapeLayer.cc72
-rw-r--r--runtime/onert/backend/cpu/ops/ShapeLayer.h53
-rw-r--r--runtime/onert/backend/cpu/ops/SliceLayer.cc109
-rw-r--r--runtime/onert/backend/cpu/ops/SliceLayer.h64
-rw-r--r--runtime/onert/backend/cpu/ops/SoftMaxLayer.cc148
-rw-r--r--runtime/onert/backend/cpu/ops/SoftMaxLayer.h59
-rw-r--r--runtime/onert/backend/cpu/ops/SpaceToBatchNDLayer.cc114
-rw-r--r--runtime/onert/backend/cpu/ops/SpaceToBatchNDLayer.h60
-rw-r--r--runtime/onert/backend/cpu/ops/SpaceToDepthLayer.cc74
-rw-r--r--runtime/onert/backend/cpu/ops/SpaceToDepthLayer.h54
-rw-r--r--runtime/onert/backend/cpu/ops/SplitLayer.cc103
-rw-r--r--runtime/onert/backend/cpu/ops/SplitLayer.h58
-rw-r--r--runtime/onert/backend/cpu/ops/SplitVLayer.cc99
-rw-r--r--runtime/onert/backend/cpu/ops/SplitVLayer.h60
-rw-r--r--runtime/onert/backend/cpu/ops/SquaredDiffLayer.cc66
-rw-r--r--runtime/onert/backend/cpu/ops/SquaredDiffLayer.h57
-rw-r--r--runtime/onert/backend/cpu/ops/StatelessRandomUniformLayer.cc68
-rw-r--r--runtime/onert/backend/cpu/ops/StatelessRandomUniformLayer.h59
-rw-r--r--runtime/onert/backend/cpu/ops/StridedSliceLayer.cc94
-rw-r--r--runtime/onert/backend/cpu/ops/StridedSliceLayer.h68
-rw-r--r--runtime/onert/backend/cpu/ops/TileLayer.cc77
-rw-r--r--runtime/onert/backend/cpu/ops/TileLayer.h59
-rw-r--r--runtime/onert/backend/cpu/ops/TransposeLayer.cc111
-rw-r--r--runtime/onert/backend/cpu/ops/TransposeLayer.h59
-rw-r--r--runtime/onert/backend/cpu/ops/UnpackLayer.cc91
-rw-r--r--runtime/onert/backend/cpu/ops/UnpackLayer.h58
-rw-r--r--runtime/onert/core/CMakeLists.txt54
-rw-r--r--runtime/onert/core/include/backend/Backend.h50
-rw-r--r--runtime/onert/core/include/backend/BackendContext.h92
-rw-r--r--runtime/onert/core/include/backend/CustomKernelBuilder.h76
-rw-r--r--runtime/onert/core/include/backend/IConfig.h77
-rw-r--r--runtime/onert/core/include/backend/IConstantInitializer.h230
-rw-r--r--runtime/onert/core/include/backend/IDynamicTensorManager.h60
-rw-r--r--runtime/onert/core/include/backend/IExternalContext.h34
-rw-r--r--runtime/onert/core/include/backend/IKernelGenerator.h76
-rw-r--r--runtime/onert/core/include/backend/IMemoryManager.h49
-rw-r--r--runtime/onert/core/include/backend/IOptimizer.h51
-rw-r--r--runtime/onert/core/include/backend/IPortableTensor.h58
-rw-r--r--runtime/onert/core/include/backend/IStaticTensorManager.h35
-rw-r--r--runtime/onert/core/include/backend/ITensor.h122
-rw-r--r--runtime/onert/core/include/backend/ITensorBuilder.h108
-rw-r--r--runtime/onert/core/include/backend/ITensorManager.h52
-rw-r--r--runtime/onert/core/include/backend/ITensorRegister.h97
-rw-r--r--runtime/onert/core/include/backend/ITensorRegistry.h146
-rw-r--r--runtime/onert/core/include/backend/cpu_common/Allocator.h56
-rw-r--r--runtime/onert/core/include/backend/cpu_common/DynamicTensorManager.h76
-rw-r--r--runtime/onert/core/include/backend/cpu_common/IMemoryPlanner.h74
-rw-r--r--runtime/onert/core/include/backend/cpu_common/MemoryManager.h76
-rw-r--r--runtime/onert/core/include/backend/cpu_common/StaticTensorManager.h68
-rw-r--r--runtime/onert/core/include/backend/cpu_common/Tensor.h184
-rw-r--r--runtime/onert/core/include/backend/cpu_common/TensorRegistry.h36
-rw-r--r--runtime/onert/core/include/compiler/BackendManager.h82
-rw-r--r--runtime/onert/core/include/compiler/BackendResolver.h60
-rw-r--r--runtime/onert/core/include/compiler/CodeMap.h45
-rw-r--r--runtime/onert/core/include/compiler/Compiler.h122
-rw-r--r--runtime/onert/core/include/compiler/ExecutionBuilder.h49
-rw-r--r--runtime/onert/core/include/compiler/LoweredGraph.h90
-rw-r--r--runtime/onert/core/include/compiler/StaticShapeInferer.h141
-rw-r--r--runtime/onert/core/include/exec/DynamicShapeInferer.h123
-rw-r--r--runtime/onert/core/include/exec/Execution.h162
-rw-r--r--runtime/onert/core/include/exec/FunctionSequence.h132
-rw-r--r--runtime/onert/core/include/exec/IExecutor.h75
-rw-r--r--runtime/onert/core/include/exec/IFunction.h36
-rw-r--r--runtime/onert/core/include/exec/IODescription.h72
-rw-r--r--runtime/onert/core/include/exec/NopFunction.h48
-rw-r--r--runtime/onert/core/include/ir/Coordinates.h128
-rw-r--r--runtime/onert/core/include/ir/Data.h107
-rw-r--r--runtime/onert/core/include/ir/DataType.h47
-rw-r--r--runtime/onert/core/include/ir/Graph.h124
-rw-r--r--runtime/onert/core/include/ir/Index.h45
-rw-r--r--runtime/onert/core/include/ir/InternalType.h59
-rw-r--r--runtime/onert/core/include/ir/Layout.h67
-rw-r--r--runtime/onert/core/include/ir/LowerInfoMap.h42
-rw-r--r--runtime/onert/core/include/ir/OpCode.h58
-rw-r--r--runtime/onert/core/include/ir/OpSequence.h102
-rw-r--r--runtime/onert/core/include/ir/OpSequences.h91
-rw-r--r--runtime/onert/core/include/ir/Operand.h117
-rw-r--r--runtime/onert/core/include/ir/OperandConstraint.h58
-rw-r--r--runtime/onert/core/include/ir/OperandIndexMap.h34
-rw-r--r--runtime/onert/core/include/ir/OperandIndexSequence.h95
-rw-r--r--runtime/onert/core/include/ir/OperandInfo.h151
-rw-r--r--runtime/onert/core/include/ir/Operands.h46
-rw-r--r--runtime/onert/core/include/ir/Operation.h76
-rw-r--r--runtime/onert/core/include/ir/OperationIndexMap.h34
-rw-r--r--runtime/onert/core/include/ir/OperationIndexSet.h65
-rw-r--r--runtime/onert/core/include/ir/OperationVisitor.h50
-rw-r--r--runtime/onert/core/include/ir/Operations.Include.h85
-rw-r--r--runtime/onert/core/include/ir/Operations.h43
-rw-r--r--runtime/onert/core/include/ir/Operations.lst88
-rw-r--r--runtime/onert/core/include/ir/Padding.h74
-rw-r--r--runtime/onert/core/include/ir/Shape.h151
-rw-r--r--runtime/onert/core/include/ir/Sparsity.h64
-rw-r--r--runtime/onert/core/include/ir/Subgraphs.h139
-rw-r--r--runtime/onert/core/include/ir/TypeInfo.h67
-rw-r--r--runtime/onert/core/include/ir/operand/LowerInfo.h69
-rw-r--r--runtime/onert/core/include/ir/operand/PermuteFactor.h130
-rw-r--r--runtime/onert/core/include/ir/operation/AddN.h43
-rw-r--r--runtime/onert/core/include/ir/operation/ArgMax.h62
-rw-r--r--runtime/onert/core/include/ir/operation/BCQFullyConnected.h67
-rw-r--r--runtime/onert/core/include/ir/operation/BCQGather.h66
-rw-r--r--runtime/onert/core/include/ir/operation/BatchMatMul.h63
-rw-r--r--runtime/onert/core/include/ir/operation/BatchToSpaceND.h51
-rw-r--r--runtime/onert/core/include/ir/operation/BinaryArithmetic.h73
-rw-r--r--runtime/onert/core/include/ir/operation/BroadcastTo.h52
-rw-r--r--runtime/onert/core/include/ir/operation/Comparison.h72
-rw-r--r--runtime/onert/core/include/ir/operation/Concat.h58
-rw-r--r--runtime/onert/core/include/ir/operation/Conv2D.h70
-rw-r--r--runtime/onert/core/include/ir/operation/ConvertFp16ToFp32.h49
-rw-r--r--runtime/onert/core/include/ir/operation/ConvertFp32ToFp16.h49
-rw-r--r--runtime/onert/core/include/ir/operation/Custom.h75
-rw-r--r--runtime/onert/core/include/ir/operation/DepthToSpace.h63
-rw-r--r--runtime/onert/core/include/ir/operation/DepthwiseConv2D.h71
-rw-r--r--runtime/onert/core/include/ir/operation/Einsum.h57
-rw-r--r--runtime/onert/core/include/ir/operation/ElementwiseActivation.h77
-rw-r--r--runtime/onert/core/include/ir/operation/ElementwiseBinary.h71
-rw-r--r--runtime/onert/core/include/ir/operation/ElementwiseUnary.h83
-rw-r--r--runtime/onert/core/include/ir/operation/EmbeddingLookup.h50
-rw-r--r--runtime/onert/core/include/ir/operation/ExpandDims.h52
-rw-r--r--runtime/onert/core/include/ir/operation/Fill.h50
-rw-r--r--runtime/onert/core/include/ir/operation/FullyConnected.h67
-rw-r--r--runtime/onert/core/include/ir/operation/FusedBatchNorm.h68
-rw-r--r--runtime/onert/core/include/ir/operation/Gather.h64
-rw-r--r--runtime/onert/core/include/ir/operation/HashtableLookup.h57
-rw-r--r--runtime/onert/core/include/ir/operation/If.h57
-rw-r--r--runtime/onert/core/include/ir/operation/InstanceNorm.h65
-rw-r--r--runtime/onert/core/include/ir/operation/L2Normalization.h49
-rw-r--r--runtime/onert/core/include/ir/operation/LSTM.h96
-rw-r--r--runtime/onert/core/include/ir/operation/LocalResponseNormalization.h66
-rw-r--r--runtime/onert/core/include/ir/operation/LogSoftmax.h64
-rw-r--r--runtime/onert/core/include/ir/operation/LowerInfo.h54
-rw-r--r--runtime/onert/core/include/ir/operation/MatrixBandPart.h53
-rw-r--r--runtime/onert/core/include/ir/operation/OneHot.h60
-rw-r--r--runtime/onert/core/include/ir/operation/PReLU.h50
-rw-r--r--runtime/onert/core/include/ir/operation/Pack.h52
-rw-r--r--runtime/onert/core/include/ir/operation/Pad.h51
-rw-r--r--runtime/onert/core/include/ir/operation/Permute.h65
-rw-r--r--runtime/onert/core/include/ir/operation/Pool2D.h78
-rw-r--r--runtime/onert/core/include/ir/operation/Pow.h51
-rw-r--r--runtime/onert/core/include/ir/operation/RNN.h70
-rw-r--r--runtime/onert/core/include/ir/operation/Range.h51
-rw-r--r--runtime/onert/core/include/ir/operation/Rank.h51
-rw-r--r--runtime/onert/core/include/ir/operation/Reduce.h77
-rw-r--r--runtime/onert/core/include/ir/operation/Reshape.h62
-rw-r--r--runtime/onert/core/include/ir/operation/ResizeBilinear.h68
-rw-r--r--runtime/onert/core/include/ir/operation/ResizeNearestNeighbor.h67
-rw-r--r--runtime/onert/core/include/ir/operation/Reverse.h50
-rw-r--r--runtime/onert/core/include/ir/operation/Select.h51
-rw-r--r--runtime/onert/core/include/ir/operation/Shape.h51
-rw-r--r--runtime/onert/core/include/ir/operation/Slice.h51
-rw-r--r--runtime/onert/core/include/ir/operation/Softmax.h63
-rw-r--r--runtime/onert/core/include/ir/operation/SpaceToBatchND.h53
-rw-r--r--runtime/onert/core/include/ir/operation/SpaceToDepth.h63
-rw-r--r--runtime/onert/core/include/ir/operation/Split.h58
-rw-r--r--runtime/onert/core/include/ir/operation/SplitV.h59
-rw-r--r--runtime/onert/core/include/ir/operation/SquaredDifference.h50
-rw-r--r--runtime/onert/core/include/ir/operation/Squeeze.h62
-rw-r--r--runtime/onert/core/include/ir/operation/StatelessRandomUniform.h52
-rw-r--r--runtime/onert/core/include/ir/operation/StridedSlice.h68
-rw-r--r--runtime/onert/core/include/ir/operation/Tile.h52
-rw-r--r--runtime/onert/core/include/ir/operation/TopKV2.h69
-rw-r--r--runtime/onert/core/include/ir/operation/Transpose.h52
-rw-r--r--runtime/onert/core/include/ir/operation/TransposeConv.h68
-rw-r--r--runtime/onert/core/include/ir/operation/Unpack.h58
-rw-r--r--runtime/onert/core/include/ir/operation/While.h58
-rw-r--r--runtime/onert/core/include/util/Config.lst46
-rw-r--r--runtime/onert/core/include/util/ConfigSource.h58
-rw-r--r--runtime/onert/core/include/util/EnvConfigSource.h41
-rw-r--r--runtime/onert/core/include/util/Exceptions.h48
-rw-r--r--runtime/onert/core/include/util/GeneralConfigSource.h44
-rw-r--r--runtime/onert/core/include/util/IConfigSource.h46
-rw-r--r--runtime/onert/core/include/util/ITimer.h59
-rw-r--r--runtime/onert/core/include/util/Index.h169
-rw-r--r--runtime/onert/core/include/util/ObjectManager.h148
-rw-r--r--runtime/onert/core/include/util/Set.h166
-rw-r--r--runtime/onert/core/include/util/ShapeInference.h153
-rw-r--r--runtime/onert/core/include/util/Utils.h108
-rw-r--r--runtime/onert/core/include/util/logging.h67
-rw-r--r--runtime/onert/core/src/backend/BackendContext.cc55
-rw-r--r--runtime/onert/core/src/backend/IConstantInitializer.cc114
-rw-r--r--runtime/onert/core/src/backend/IPortableTensor.cc29
-rw-r--r--runtime/onert/core/src/backend/ITensor.cc34
-rw-r--r--runtime/onert/core/src/backend/controlflow/Backend.h88
-rw-r--r--runtime/onert/core/src/backend/controlflow/BackendContext.h60
-rw-r--r--runtime/onert/core/src/backend/controlflow/Config.cc37
-rw-r--r--runtime/onert/core/src/backend/controlflow/Config.h53
-rw-r--r--runtime/onert/core/src/backend/controlflow/ConstantInitializer.h52
-rw-r--r--runtime/onert/core/src/backend/controlflow/DynamicTensorManager.h38
-rw-r--r--runtime/onert/core/src/backend/controlflow/ExternalContext.h80
-rw-r--r--runtime/onert/core/src/backend/controlflow/KernelGenerator.cc160
-rw-r--r--runtime/onert/core/src/backend/controlflow/KernelGenerator.h76
-rw-r--r--runtime/onert/core/src/backend/controlflow/Tensor.h35
-rw-r--r--runtime/onert/core/src/backend/controlflow/TensorBuilder.cc117
-rw-r--r--runtime/onert/core/src/backend/controlflow/TensorBuilder.h83
-rw-r--r--runtime/onert/core/src/backend/controlflow/TensorRegistry.h133
-rw-r--r--runtime/onert/core/src/backend/controlflow/UserTensor.cc53
-rw-r--r--runtime/onert/core/src/backend/controlflow/UserTensor.h85
-rw-r--r--runtime/onert/core/src/backend/controlflow/kernel/IfLayer.cc131
-rw-r--r--runtime/onert/core/src/backend/controlflow/kernel/IfLayer.h63
-rw-r--r--runtime/onert/core/src/backend/controlflow/kernel/PermuteLayer.cc311
-rw-r--r--runtime/onert/core/src/backend/controlflow/kernel/PermuteLayer.h150
-rw-r--r--runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.cc222
-rw-r--r--runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.h65
-rw-r--r--runtime/onert/core/src/backend/cpu_common/Allocator.cc38
-rw-r--r--runtime/onert/core/src/backend/cpu_common/DynamicTensorManager.cc80
-rw-r--r--runtime/onert/core/src/backend/cpu_common/MemoryManager.cc108
-rw-r--r--runtime/onert/core/src/backend/cpu_common/MemoryPlanner.cc209
-rw-r--r--runtime/onert/core/src/backend/cpu_common/MemoryPlanner.h160
-rw-r--r--runtime/onert/core/src/backend/cpu_common/MemoryPlanner.test.cc193
-rw-r--r--runtime/onert/core/src/backend/cpu_common/MemoryPlannerFactory.cc53
-rw-r--r--runtime/onert/core/src/backend/cpu_common/MemoryPlannerFactory.h47
-rw-r--r--runtime/onert/core/src/backend/cpu_common/StaticTensorManager.cc118
-rw-r--r--runtime/onert/core/src/backend/cpu_common/Tensor.cc97
-rw-r--r--runtime/onert/core/src/compiler/BackendManager.cc146
-rw-r--r--runtime/onert/core/src/compiler/BackendResolver.cc25
-rw-r--r--runtime/onert/core/src/compiler/Compiler.cc318
-rw-r--r--runtime/onert/core/src/compiler/ExecutorFactory.cc501
-rw-r--r--runtime/onert/core/src/compiler/ExecutorFactory.h73
-rw-r--r--runtime/onert/core/src/compiler/Fp32ToFp16Converter.cc954
-rw-r--r--runtime/onert/core/src/compiler/Fp32ToFp16Converter.h101
-rw-r--r--runtime/onert/core/src/compiler/HEScheduler.cc600
-rw-r--r--runtime/onert/core/src/compiler/HEScheduler.h186
-rw-r--r--runtime/onert/core/src/compiler/IScheduler.h38
-rw-r--r--runtime/onert/core/src/compiler/Linear.cc251
-rw-r--r--runtime/onert/core/src/compiler/Linear.h54
-rw-r--r--runtime/onert/core/src/compiler/LoweredGraph.cc580
-rw-r--r--runtime/onert/core/src/compiler/ManualScheduler.cc124
-rw-r--r--runtime/onert/core/src/compiler/ManualScheduler.h47
-rw-r--r--runtime/onert/core/src/compiler/ParamChecker.cc33
-rw-r--r--runtime/onert/core/src/compiler/ParamChecker.h73
-rw-r--r--runtime/onert/core/src/compiler/ShapeValidator.cc1038
-rw-r--r--runtime/onert/core/src/compiler/ShapeValidator.h102
-rw-r--r--runtime/onert/core/src/compiler/StaticShapeInferer.cc1302
-rw-r--r--runtime/onert/core/src/compiler/TensorBuilders.h78
-rw-r--r--runtime/onert/core/src/compiler/TensorRegistries.h91
-rw-r--r--runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc93
-rw-r--r--runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h76
-rw-r--r--runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc56
-rw-r--r--runtime/onert/core/src/compiler/pass/ConstantLoweringPass.h46
-rw-r--r--runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc68
-rw-r--r--runtime/onert/core/src/compiler/pass/ConstantOutputPass.h63
-rw-r--r--runtime/onert/core/src/compiler/pass/LoweredOperandPass.h52
-rw-r--r--runtime/onert/core/src/compiler/pass/LoweredOperationPass.h52
-rw-r--r--runtime/onert/core/src/compiler/pass/OddOutputPass.cc90
-rw-r--r--runtime/onert/core/src/compiler/pass/OddOutputPass.h89
-rw-r--r--runtime/onert/core/src/compiler/pass/OperandPass.cc36
-rw-r--r--runtime/onert/core/src/compiler/pass/OperandPass.h54
-rw-r--r--runtime/onert/core/src/compiler/pass/OperationPass.cc38
-rw-r--r--runtime/onert/core/src/compiler/pass/OperationPass.h77
-rw-r--r--runtime/onert/core/src/compiler/pass/Pass.h55
-rw-r--r--runtime/onert/core/src/compiler/pass/PassRunner.cc45
-rw-r--r--runtime/onert/core/src/compiler/pass/PassRunner.h53
-rw-r--r--runtime/onert/core/src/compiler/pass/PermutationEliminationPass.cc167
-rw-r--r--runtime/onert/core/src/compiler/pass/PermutationEliminationPass.h65
-rw-r--r--runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc216
-rw-r--r--runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h58
-rw-r--r--runtime/onert/core/src/compiler/pass/PermutationOperationPass.cc351
-rw-r--r--runtime/onert/core/src/compiler/pass/PermutationOperationPass.h65
-rw-r--r--runtime/onert/core/src/dumper/dot/DotBuilder.cc83
-rw-r--r--runtime/onert/core/src/dumper/dot/DotBuilder.h62
-rw-r--r--runtime/onert/core/src/dumper/dot/DotDumper.cc201
-rw-r--r--runtime/onert/core/src/dumper/dot/DotDumper.h69
-rw-r--r--runtime/onert/core/src/dumper/dot/DotSubgraphInfo.cc58
-rw-r--r--runtime/onert/core/src/dumper/dot/DotSubgraphInfo.h61
-rw-r--r--runtime/onert/core/src/dumper/dot/Node.cc56
-rw-r--r--runtime/onert/core/src/dumper/dot/Node.h127
-rw-r--r--runtime/onert/core/src/dumper/dot/OperandNode.cc60
-rw-r--r--runtime/onert/core/src/dumper/dot/OperandNode.h79
-rw-r--r--runtime/onert/core/src/dumper/dot/OperationNode.cc46
-rw-r--r--runtime/onert/core/src/dumper/dot/OperationNode.h62
-rw-r--r--runtime/onert/core/src/exec/BackendSet.h40
-rw-r--r--runtime/onert/core/src/exec/DataflowExecutor.cc183
-rw-r--r--runtime/onert/core/src/exec/DataflowExecutor.h96
-rw-r--r--runtime/onert/core/src/exec/DynamicShapeInferer.cc1236
-rw-r--r--runtime/onert/core/src/exec/ExecTime.cc137
-rw-r--r--runtime/onert/core/src/exec/ExecTime.h112
-rw-r--r--runtime/onert/core/src/exec/Execution.cc182
-rw-r--r--runtime/onert/core/src/exec/ExecutionObservee.cc64
-rw-r--r--runtime/onert/core/src/exec/ExecutionObservee.h56
-rw-r--r--runtime/onert/core/src/exec/ExecutionObservers.cc135
-rw-r--r--runtime/onert/core/src/exec/ExecutionObservers.h88
-rw-r--r--runtime/onert/core/src/exec/ExecutorBase.cc203
-rw-r--r--runtime/onert/core/src/exec/ExecutorBase.h107
-rw-r--r--runtime/onert/core/src/exec/FunctionSequence.cc93
-rw-r--r--runtime/onert/core/src/exec/IPermuteFunction.h354
-rw-r--r--runtime/onert/core/src/exec/JSONExecTime.cc231
-rw-r--r--runtime/onert/core/src/exec/JSONExecTime.h97
-rw-r--r--runtime/onert/core/src/exec/Job.cc33
-rw-r--r--runtime/onert/core/src/exec/Job.h69
-rw-r--r--runtime/onert/core/src/exec/LinearExecutor.cc67
-rw-r--r--runtime/onert/core/src/exec/LinearExecutor.h72
-rw-r--r--runtime/onert/core/src/exec/ParallelExecutor.cc156
-rw-r--r--runtime/onert/core/src/exec/ParallelExecutor.h69
-rw-r--r--runtime/onert/core/src/exec/ParallelScheduler.cc55
-rw-r--r--runtime/onert/core/src/exec/ParallelScheduler.h60
-rw-r--r--runtime/onert/core/src/exec/ShapeConverter.cc60
-rw-r--r--runtime/onert/core/src/exec/ShapeConverter.h39
-rw-r--r--runtime/onert/core/src/exec/ThreadPool.cc65
-rw-r--r--runtime/onert/core/src/exec/ThreadPool.h73
-rw-r--r--runtime/onert/core/src/exec/WorkQueue.cc104
-rw-r--r--runtime/onert/core/src/exec/WorkQueue.h87
-rw-r--r--runtime/onert/core/src/exec/feature/IndexIterator.h104
-rw-r--r--runtime/onert/core/src/exec/feature/Reader.h68
-rw-r--r--runtime/onert/core/src/exec/feature/nchw/Reader.h117
-rw-r--r--runtime/onert/core/src/exec/feature/nchw/View.h71
-rw-r--r--runtime/onert/core/src/exec/feature/nhwc/Reader.h118
-rw-r--r--runtime/onert/core/src/exec/feature/nhwc/View.h72
-rw-r--r--runtime/onert/core/src/interp/Buffer.h91
-rw-r--r--runtime/onert/core/src/interp/ExecEnv.h212
-rw-r--r--runtime/onert/core/src/interp/InterpExecutor.cc126
-rw-r--r--runtime/onert/core/src/interp/InterpExecutor.h70
-rw-r--r--runtime/onert/core/src/interp/InterpOps.lst73
-rw-r--r--runtime/onert/core/src/interp/Interpreter.cc184
-rw-r--r--runtime/onert/core/src/interp/Interpreter.h64
-rw-r--r--runtime/onert/core/src/interp/Registration.h43
-rw-r--r--runtime/onert/core/src/interp/Tensor.cc53
-rw-r--r--runtime/onert/core/src/interp/Tensor.h183
-rw-r--r--runtime/onert/core/src/interp/operations/BinaryArithmeticOps.cc205
-rw-r--r--runtime/onert/core/src/interp/operations/Concat.cc147
-rw-r--r--runtime/onert/core/src/interp/operations/Conv2D.cc151
-rw-r--r--runtime/onert/core/src/interp/operations/DepthwiseConv2D.cc156
-rw-r--r--runtime/onert/core/src/interp/operations/ElementwiseActivations.cc161
-rw-r--r--runtime/onert/core/src/interp/operations/FullyConnected.cc134
-rw-r--r--runtime/onert/core/src/interp/operations/Gather.cc138
-rw-r--r--runtime/onert/core/src/interp/operations/InstanceNorm.cc121
-rw-r--r--runtime/onert/core/src/interp/operations/OperationUtil.h203
-rw-r--r--runtime/onert/core/src/interp/operations/Pad.cc106
-rw-r--r--runtime/onert/core/src/interp/operations/Pool2D.cc140
-rw-r--r--runtime/onert/core/src/interp/operations/Reshape.cc63
-rw-r--r--runtime/onert/core/src/interp/operations/Softmax.cc123
-rw-r--r--runtime/onert/core/src/interp/operations/TransposeConv.cc141
-rw-r--r--runtime/onert/core/src/ir/Coordinates.cc50
-rw-r--r--runtime/onert/core/src/ir/DataType.cc58
-rw-r--r--runtime/onert/core/src/ir/Graph.cc158
-rw-r--r--runtime/onert/core/src/ir/GraphIterator.cc121
-rw-r--r--runtime/onert/core/src/ir/GraphIterator.h90
-rw-r--r--runtime/onert/core/src/ir/LayoutSet.cc66
-rw-r--r--runtime/onert/core/src/ir/LayoutSet.h58
-rw-r--r--runtime/onert/core/src/ir/OpCode.cc47
-rw-r--r--runtime/onert/core/src/ir/OpSequence.cc95
-rw-r--r--runtime/onert/core/src/ir/OpSequences.cc124
-rw-r--r--runtime/onert/core/src/ir/Operand.cc50
-rw-r--r--runtime/onert/core/src/ir/OperandIndexSequence.cc77
-rw-r--r--runtime/onert/core/src/ir/Operands.cc36
-rw-r--r--runtime/onert/core/src/ir/Operation.cc66
-rw-r--r--runtime/onert/core/src/ir/OperationCloner.cc42
-rw-r--r--runtime/onert/core/src/ir/OperationCloner.h46
-rw-r--r--runtime/onert/core/src/ir/OperationDumper.cc521
-rw-r--r--runtime/onert/core/src/ir/OperationDumper.h96
-rw-r--r--runtime/onert/core/src/ir/OperationIndexSet.cc37
-rw-r--r--runtime/onert/core/src/ir/OperationValidator.cc339
-rw-r--r--runtime/onert/core/src/ir/OperationValidator.h90
-rw-r--r--runtime/onert/core/src/ir/Operations.cc37
-rw-r--r--runtime/onert/core/src/ir/Padding.cc160
-rw-r--r--runtime/onert/core/src/ir/Shape.cc114
-rw-r--r--runtime/onert/core/src/ir/TypeInfo.cc47
-rw-r--r--runtime/onert/core/src/ir/operation/AddN.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/ArgMax.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/BCQFullyConnected.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/BCQGather.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/BatchMatMul.cc37
-rw-r--r--runtime/onert/core/src/ir/operation/BatchToSpaceND.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/BinaryArithmetic.cc52
-rw-r--r--runtime/onert/core/src/ir/operation/BroadcastTo.cc38
-rw-r--r--runtime/onert/core/src/ir/operation/Comparison.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Concat.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Conv2D.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/ConvertFp16ToFp32.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/ConvertFp32ToFp16.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Custom.cc44
-rw-r--r--runtime/onert/core/src/ir/operation/DepthToSpace.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/DepthwiseConv2D.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Einsum.cc37
-rw-r--r--runtime/onert/core/src/ir/operation/ElementwiseActivation.cc72
-rw-r--r--runtime/onert/core/src/ir/operation/ElementwiseBinary.cc52
-rw-r--r--runtime/onert/core/src/ir/operation/ElementwiseUnary.cc67
-rw-r--r--runtime/onert/core/src/ir/operation/EmbeddingLookup.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/ExpandDims.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/Fill.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/FullyConnected.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/FusedBatchNorm.cc37
-rw-r--r--runtime/onert/core/src/ir/operation/Gather.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/HashtableLookup.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/If.cc32
-rw-r--r--runtime/onert/core/src/ir/operation/InstanceNorm.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/L2Normalization.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/LSTM.cc48
-rw-r--r--runtime/onert/core/src/ir/operation/LocalResponseNormalization.cc41
-rw-r--r--runtime/onert/core/src/ir/operation/LogSoftmax.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/LowerInfo.cc34
-rw-r--r--runtime/onert/core/src/ir/operation/MatrixBandPart.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/OneHot.cc37
-rw-r--r--runtime/onert/core/src/ir/operation/PReLU.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/Pack.cc33
-rw-r--r--runtime/onert/core/src/ir/operation/Pad.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/Permute.cc41
-rw-r--r--runtime/onert/core/src/ir/operation/Pool2D.cc51
-rw-r--r--runtime/onert/core/src/ir/operation/Pow.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/RNN.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Range.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/Rank.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/Reduce.cc56
-rw-r--r--runtime/onert/core/src/ir/operation/Reshape.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/ResizeBilinear.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/ResizeNearestNeighbor.cc41
-rw-r--r--runtime/onert/core/src/ir/operation/Reverse.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/Select.cc37
-rw-r--r--runtime/onert/core/src/ir/operation/Shape.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/Slice.cc36
-rw-r--r--runtime/onert/core/src/ir/operation/Softmax.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/SpaceToBatchND.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/SpaceToDepth.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Split.cc33
-rw-r--r--runtime/onert/core/src/ir/operation/SplitV.cc33
-rw-r--r--runtime/onert/core/src/ir/operation/SquaredDifference.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Squeeze.cc37
-rw-r--r--runtime/onert/core/src/ir/operation/StatelessRandomUniform.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/StridedSlice.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Tile.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/TopKV2.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Transpose.cc39
-rw-r--r--runtime/onert/core/src/ir/operation/TransposeConv.cc40
-rw-r--r--runtime/onert/core/src/ir/operation/Unpack.cc33
-rw-r--r--runtime/onert/core/src/ir/operation/While.cc33
-rw-r--r--runtime/onert/core/src/ir/verifier/Verifier.cc146
-rw-r--r--runtime/onert/core/src/ir/verifier/Verifier.h77
-rw-r--r--runtime/onert/core/src/library_info.cc17
-rw-r--r--runtime/onert/core/src/util/ConfigSource.cc122
-rw-r--r--runtime/onert/core/src/util/EnvConfigSource.cc40
-rw-r--r--runtime/onert/core/src/util/EventCollector.cc109
-rw-r--r--runtime/onert/core/src/util/EventCollector.h51
-rw-r--r--runtime/onert/core/src/util/EventCollectorGlobal.cc94
-rw-r--r--runtime/onert/core/src/util/EventCollectorGlobal.h155
-rw-r--r--runtime/onert/core/src/util/EventRecorder.cc31
-rw-r--r--runtime/onert/core/src/util/EventRecorder.h69
-rw-r--r--runtime/onert/core/src/util/EventWriter.cc574
-rw-r--r--runtime/onert/core/src/util/EventWriter.h51
-rw-r--r--runtime/onert/core/src/util/GeneralConfigSource.cc45
-rw-r--r--runtime/onert/core/src/util/ShapeInference.cc1131
-rw-r--r--runtime/onert/core/src/util/logging.cc23
-rw-r--r--runtime/onert/frontend/CMakeLists.txt1
-rw-r--r--runtime/onert/frontend/base_loader/CMakeLists.txt11
-rw-r--r--runtime/onert/frontend/base_loader/include/base_loader.h1589
-rw-r--r--runtime/onert/frontend/circle/CMakeLists.txt20
-rw-r--r--runtime/onert/frontend/circle/include/circle_loader.h33
-rw-r--r--runtime/onert/frontend/circle/src/circle_loader.cc222
-rw-r--r--runtime/onert/frontend/circle_schema/CMakeLists.txt7
-rw-r--r--runtime/onert/frontend/circle_schema/include/circle_schema_generated.h10709
-rw-r--r--runtime/onert/frontend/nnapi/CMakeLists.txt27
-rw-r--r--runtime/onert/frontend/nnapi/compilation.cc106
-rw-r--r--runtime/onert/frontend/nnapi/event.cc36
-rw-r--r--runtime/onert/frontend/nnapi/execution.cc504
-rw-r--r--runtime/onert/frontend/nnapi/memory.cc42
-rw-r--r--runtime/onert/frontend/nnapi/model.cc416
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc45
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h47
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc42
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.h44
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc335
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h77
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.cc46
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.h39
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc287
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h75
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.test.cc25
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc100
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.h79
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc1919
-rw-r--r--runtime/onert/frontend/nnapi/wrapper/OperationFactory.h60
-rw-r--r--runtime/onert/frontend/tflite/CMakeLists.txt19
-rw-r--r--runtime/onert/frontend/tflite/include/tflite_loader.h34
-rw-r--r--runtime/onert/frontend/tflite/src/tflite_loader.cc127
-rw-r--r--runtime/onert/frontend/tflite/src/tflite_schema_generated.h9553
-rw-r--r--runtime/onert/frontend/tflite/tflite_schema-1.13.1.fbs795
-rw-r--r--runtime/onert/frontend/tflite/tflite_schema.fbs1095
-rw-r--r--runtime/onert/sample/CMakeLists.txt1
-rw-r--r--runtime/onert/sample/minimal/CMakeLists.txt10
-rw-r--r--runtime/onert/sample/minimal/README.md13
-rw-r--r--runtime/onert/sample/minimal/src/minimal.cc71
-rw-r--r--runtime/onert/test/CMakeLists.txt15
-rw-r--r--runtime/onert/test/core/compiler/Scheduler.cc587
-rw-r--r--runtime/onert/test/core/exec/ExecInstance.cc297
-rw-r--r--runtime/onert/test/core/exec/ExecTime.test.cc105
-rw-r--r--runtime/onert/test/core/interp/ExecManager.cc361
-rw-r--r--runtime/onert/test/graph/Graph.cc150
-rw-r--r--runtime/onert/test/graph/Index.cc34
-rw-r--r--runtime/onert/test/graph/MockNode.h47
-rw-r--r--runtime/onert/test/graph/operand/IndexSet.cc52
-rw-r--r--runtime/onert/test/graph/operand/LayoutSet.cc58
-rw-r--r--runtime/onert/test/graph/operand/Set.cc45
-rw-r--r--runtime/onert/test/graph/operand/UseDef.cc85
-rw-r--r--runtime/onert/test/graph/operation/Set.cc41
-rw-r--r--runtime/onert/test/graph/operation/SetIO.cc99
-rw-r--r--runtime/onert/test/graph/verifier/Verifier.cc98
-rw-r--r--runtime/onert/test/ir/Shape.cc58
-rw-r--r--runtime/onert/test/util/ObjectManager.cc97
-rw-r--r--runtime/onert/test/util/ShapeInference.cc545
969 files changed, 142366 insertions, 0 deletions
diff --git a/runtime/3rdparty/.FORMATDENY b/runtime/3rdparty/.FORMATDENY
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/runtime/3rdparty/.FORMATDENY
diff --git a/runtime/3rdparty/CMakeLists.txt b/runtime/3rdparty/CMakeLists.txt
new file mode 100644
index 000000000..99d2028f4
--- /dev/null
+++ b/runtime/3rdparty/CMakeLists.txt
@@ -0,0 +1,4 @@
+# Add all subdirectories.
+# Each library in sub-directory must have it's own CMakeLists.txt
+# to build library's binaries or to support interface.
+add_subdirectories()
diff --git a/runtime/3rdparty/half/CMakeLists.txt b/runtime/3rdparty/half/CMakeLists.txt
new file mode 100644
index 000000000..0f8218c09
--- /dev/null
+++ b/runtime/3rdparty/half/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(half INTERFACE)
+target_include_directories(half INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
diff --git a/runtime/3rdparty/half/include/Half.h b/runtime/3rdparty/half/include/Half.h
new file mode 100644
index 000000000..409def5a6
--- /dev/null
+++ b/runtime/3rdparty/half/include/Half.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __HALF_H__
+#define __HALF_H__
+
+#include <half/include/half.hpp>
+
+using Half = half_float::half;
+
+#endif // __HALF_H__
diff --git a/runtime/3rdparty/half/include/half/.FORMATDENY b/runtime/3rdparty/half/include/half/.FORMATDENY
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/runtime/3rdparty/half/include/half/.FORMATDENY
diff --git a/runtime/3rdparty/half/include/half/ChangeLog.txt b/runtime/3rdparty/half/include/half/ChangeLog.txt
new file mode 100644
index 000000000..d9fc2bbbb
--- /dev/null
+++ b/runtime/3rdparty/half/include/half/ChangeLog.txt
@@ -0,0 +1,205 @@
+Release Notes
+=============
+
+2.1.0 release (2019-08-05):
+---------------------------
+
+- Added detection of IEEE floating-point exceptions to operators and functions.
+- Added configuration options for automatic exception handling.
+- Added functions for explicitly managing floating-point exception flags.
+- Improved accuracy of `pow` and `atan2` functions.
+
+
+2.0.0 release (2019-07-23):
+---------------------------
+
+- Made internal implementation independent from built-in floating point
+ facilities for increased reliability and IEEE-conformance.
+- Changed default rounding mode to rounding to nearest.
+- Always round ties to even when rounding to nearest.
+- Extended `constexpr` support to comparison and classification functions.
+- Added support for F16C compiler intrinsics for conversions.
+- Enabled C++11 feature detection for Intel compilers.
+
+
+1.12.0 release (2017-03-06):
+----------------------------
+
+- Changed behaviour of `half_cast` to perform conversions to/from `double`
+ and `long double` directly according to specified rounding mode, without an
+ intermediate `float` conversion.
+- Added `noexcept` specifiers to constructors.
+- Fixed minor portability problem with `logb` and `ilogb`.
+- Tested for *VC++ 2015*.
+
+
+1.11.0 release (2013-11-16):
+----------------------------
+
+- Made tie-breaking behaviour in round to nearest configurable by
+ `HALF_ROUND_TIES_TO_EVEN` macro.
+- Completed support for all C++11 mathematical functions even if single-
+ precision versions from `<cmath>` are unsupported.
+- Fixed inability to disable support for C++11 mathematical functions on
+ *VC++ 2013*.
+
+
+1.10.0 release (2013-11-09):
+----------------------------
+
+- Made default rounding mode configurable by `HALF_ROUND_STYLE` macro.
+- Added support for non-IEEE single-precision implementations.
+- Added `HALF_ENABLE_CPP11_TYPE_TRAITS` preprocessor flag for checking
+ support for C++11 type traits and TMP features.
+- Restricted `half_cast` to support built-in arithmetic types only.
+- Changed behaviour of `half_cast` to respect rounding mode when casting
+ to/from integer types.
+
+
+1.9.2 release (2013-11-01):
+---------------------------
+
+- Tested for *gcc 4.8*.
+- Tested and fixed for *VC++ 2013*.
+- Removed unnecessary warnings in *MSVC*.
+
+
+1.9.1 release (2013-08-08):
+---------------------------
+
+- Fixed problems with older gcc and MSVC versions.
+- Small fix to non-C++11 implementations of `remainder` and `remquo`.
+
+
+1.9.0 release (2013-08-07):
+---------------------------
+
+- Changed behaviour of `nearbyint`, `rint`, `lrint` and `llrint` to use
+ rounding mode of half-precision implementation (which is
+ truncating/indeterminate) instead of single-precision rounding mode.
+- Added support for more C++11 mathematical functions even if single-
+ precision versions from `<cmath>` are unsupported, in particular
+ `remainder`, `remquo` and `cbrt`.
+- Minor implementation changes.
+
+
+1.8.1 release (2013-01-22):
+---------------------------
+
+- Fixed bug resulting in multiple definitions of the `nanh` function due to
+ a missing `inline` specification.
+
+
+1.8.0 release (2013-01-19):
+---------------------------
+
+- Added support for more C++11 mathematical functions even if single-
+ precision versions from `<cmath>` are unsupported, in particular
+ exponential and logarithm functions, hyperbolic area functions and the
+ hypotenuse function.
+- Made `fma` function use default implementation if single-precision version
+ from `<cmath>` is not faster and thus `FP_FAST_FMAH` to be defined always.
+- Fixed overload resolution issues when invoking certain mathematical
+ functions by unqualified calls.
+
+
+1.7.0 release (2012-10-26):
+---------------------------
+
+- Added support for C++11 `noexcept` specifiers.
+- Changed C++11 `long long` to be supported on *VC++ 2003* and up.
+
+
+1.6.1 release (2012-09-13):
+---------------------------
+
+- Made `fma` and `fdim` functions available even if corresponding
+ single-precision functions are not.
+
+
+1.6.0 release (2012-09-12):
+---------------------------
+
+- Added `HALF_ENABLE_CPP11_LONG_LONG` to control support for `long long`
+ integers and corresponding mathematical functions.
+- Fixed C++98 compatibility on non-VC compilers.
+
+
+1.5.1 release (2012-08-17):
+---------------------------
+
+- Recorrected `std::numeric_limits::round_style` to always return
+ `std::round_indeterminate`, due to overflow-handling deviating from
+ correct round-toward-zero behaviour.
+
+
+1.5.0 release (2012-08-16):
+---------------------------
+
+- Added `half_cast` for explicitly casting between half and any type
+ convertible to/from `float` and allowing the explicit specification of
+ the rounding mode to use.
+
+
+1.4.0 release (2012-08-12):
+---------------------------
+
+- Added support for C++11 generalized constant expressions (`constexpr`).
+
+
+1.3.1 release (2012-08-11):
+---------------------------
+
+- Fixed requirement for `std::signbit` and `std::isnan` (even if C++11
+ `<cmath>` functions disabled) on non-VC compilers.
+
+
+1.3.0 release (2012-08-10):
+---------------------------
+
+- Made requirement for `<cstdint>` and `static_assert` optional and thus
+ made the library C++98-compatible.
+- Made support for C++11 features user-overridable through explicit
+ definition of corresponding preprocessor symbols to either 0 or 1.
+- Renamed `HALF_ENABLE_HASH` to `HALF_ENABLE_CPP11_HASH` in correspondence
+ with other C++11 preprocessor symbols.
+
+
+1.2.0 release (2012-08-07):
+---------------------------
+
+- Added proper preprocessor definitions for `HUGE_VALH` and `FP_FAST_FMAH`
+ in correspondence with their single-precision counterparts from `<cmath>`.
+- Fixed internal preprocessor macros to be properly undefined after use.
+
+
+1.1.2 release (2012-08-07):
+---------------------------
+
+- Revised `std::numeric_limits::round_style` to return
+ `std::round_toward_zero` if the `float` version also does and
+ `std::round_indeterminate` otherwise.
+- Fixed `std::numeric_limits::round_error` to reflect worst-case round
+ toward zero behaviour.
+
+
+1.1.1 release (2012-08-06):
+---------------------------
+
+- Fixed `std::numeric_limits::min` to return smallest positive normal
+ number, instead of subnormal number.
+- Fixed `std::numeric_limits::round_style` to return
+ `std::round_indeterminate` due to mixture of separately rounded
+ single-precision arithmetics with truncating single-to-half conversions.
+
+
+1.1.0 release (2012-08-06):
+---------------------------
+
+- Added half-precision literals.
+
+
+1.0.0 release (2012-08-05):
+---------------------------
+
+- First release.
diff --git a/runtime/3rdparty/half/include/half/LICENSE.txt b/runtime/3rdparty/half/include/half/LICENSE.txt
new file mode 100644
index 000000000..36c20d1e4
--- /dev/null
+++ b/runtime/3rdparty/half/include/half/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2012-2019 Christian Rau
+
+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.
diff --git a/runtime/3rdparty/half/include/half/README.txt b/runtime/3rdparty/half/include/half/README.txt
new file mode 100644
index 000000000..b8ca7ead1
--- /dev/null
+++ b/runtime/3rdparty/half/include/half/README.txt
@@ -0,0 +1,317 @@
+HALF-PRECISION FLOATING-POINT LIBRARY (Version 2.1.0)
+-----------------------------------------------------
+
+This is a C++ header-only library to provide an IEEE 754 conformant 16-bit
+half-precision floating-point type along with corresponding arithmetic
+operators, type conversions and common mathematical functions. It aims for both
+efficiency and ease of use, trying to accurately mimic the behaviour of the
+built-in floating-point types at the best performance possible.
+
+
+INSTALLATION AND REQUIREMENTS
+-----------------------------
+
+Conveniently, the library consists of just a single header file containing all
+the functionality, which can be directly included by your projects, without the
+neccessity to build anything or link to anything.
+
+Whereas this library is fully C++98-compatible, it can profit from certain
+C++11 features. Support for those features is checked automatically at compile
+(or rather preprocessing) time, but can be explicitly enabled or disabled by
+predefining the corresponding preprocessor symbols to either 1 or 0 yourself
+before including half.hpp. This is useful when the automatic detection fails
+(for more exotic implementations) or when a feature should be explicitly
+disabled:
+
+ - 'long long' integer type for mathematical functions returning 'long long'
+ results (enabled for VC++ 2003 and icc 11.1 and newer, gcc and clang,
+ overridable with 'HALF_ENABLE_CPP11_LONG_LONG').
+
+ - Static assertions for extended compile-time checks (enabled for VC++ 2010,
+ gcc 4.3, clang 2.9, icc 11.1 and newer, overridable with
+ 'HALF_ENABLE_CPP11_STATIC_ASSERT').
+
+ - Generalized constant expressions (enabled for VC++ 2015, gcc 4.6, clang 3.1,
+ icc 14.0 and newer, overridable with 'HALF_ENABLE_CPP11_CONSTEXPR').
+
+ - noexcept exception specifications (enabled for VC++ 2015, gcc 4.6,
+ clang 3.0, icc 14.0 and newer, overridable with 'HALF_ENABLE_CPP11_NOEXCEPT').
+
+ - User-defined literals for half-precision literals to work (enabled for
+ VC++ 2015, gcc 4.7, clang 3.1, icc 15.0 and newer, overridable with
+ 'HALF_ENABLE_CPP11_USER_LITERALS').
+
+ - Thread-local storage for per-thread floating-point exception flags (enabled
+ for VC++ 2015, gcc 4.8, clang 3.3, icc 15.0 and newer, overridable with
+ 'HALF_ENABLE_CPP11_THREAD_LOCAL').
+
+ - Type traits and template meta-programming features from <type_traits>
+ (enabled for VC++ 2010, libstdc++ 4.3, libc++ and newer, overridable with
+ 'HALF_ENABLE_CPP11_TYPE_TRAITS').
+
+ - Special integer types from <cstdint> (enabled for VC++ 2010, libstdc++ 4.3,
+ libc++ and newer, overridable with 'HALF_ENABLE_CPP11_CSTDINT').
+
+ - Certain C++11 single-precision mathematical functions from <cmath> for
+ floating-point classification during conversions from higher precision types
+ (enabled for VC++ 2013, libstdc++ 4.3, libc++ and newer, overridable with
+ 'HALF_ENABLE_CPP11_CMATH').
+
+ - Floating-point environment control from <cfenv> for possible exception
+ propagation to the built-in floating-point platform (enabled for VC++ 2013,
+ libstdc++ 4.3, libc++ and newer, overridable with 'HALF_ENABLE_CPP11_CFENV').
+
+ - Hash functor 'std::hash' from <functional> (enabled for VC++ 2010,
+ libstdc++ 4.3, libc++ and newer, overridable with 'HALF_ENABLE_CPP11_HASH').
+
+The library has been tested successfully with Visual C++ 2005-2015, gcc 4-8
+and clang 3-8 on 32- and 64-bit x86 systems. Please contact me if you have any
+problems, suggestions or even just success testing it on other platforms.
+
+
+DOCUMENTATION
+-------------
+
+What follows are some general words about the usage of the library and its
+implementation. For a complete documentation of its interface consult the
+corresponding website http://half.sourceforge.net. You may also generate the
+complete developer documentation from the library's only include file's doxygen
+comments, but this is more relevant to developers rather than mere users.
+
+BASIC USAGE
+
+To make use of the library just include its only header file half.hpp, which
+defines all half-precision functionality inside the 'half_float' namespace. The
+actual 16-bit half-precision data type is represented by the 'half' type, which
+uses the standard IEEE representation with 1 sign bit, 5 exponent bits and 11
+mantissa bits (including the hidden bit) and supports all types of special
+values, like subnormal values, infinity and NaNs. This type behaves like the
+built-in floating-point types as much as possible, supporting the usual
+arithmetic, comparison and streaming operators, which makes its use pretty
+straight-forward:
+
+ using half_float::half;
+ half a(3.4), b(5);
+ half c = a * b;
+ c += 3;
+ if(c > a)
+ std::cout << c << std::endl;
+
+Additionally the 'half_float' namespace also defines half-precision versions
+for all mathematical functions of the C++ standard library, which can be used
+directly through ADL:
+
+ half a(-3.14159);
+ half s = sin(abs(a));
+ long l = lround(s);
+
+You may also specify explicit half-precision literals, since the library
+provides a user-defined literal inside the 'half_float::literal' namespace,
+which you just need to import (assuming support for C++11 user-defined literals):
+
+ using namespace half_float::literal;
+ half x = 1.0_h;
+
+Furthermore the library provides proper specializations for
+'std::numeric_limits', defining various implementation properties, and
+'std::hash' for hashing half-precision numbers (assuming support for C++11
+'std::hash'). Similar to the corresponding preprocessor symbols from <cmath>
+the library also defines the 'HUGE_VALH' constant and maybe the 'FP_FAST_FMAH'
+symbol.
+
+CONVERSIONS AND ROUNDING
+
+The half is explicitly constructible/convertible from a single-precision float
+argument. Thus it is also explicitly constructible/convertible from any type
+implicitly convertible to float, but constructing it from types like double or
+int will involve the usual warnings arising when implicitly converting those to
+float because of the lost precision. On the one hand those warnings are
+intentional, because converting those types to half neccessarily also reduces
+precision. But on the other hand they are raised for explicit conversions from
+those types, when the user knows what he is doing. So if those warnings keep
+bugging you, then you won't get around first explicitly converting to float
+before converting to half, or use the 'half_cast' described below. In addition
+you can also directly assign float values to halfs.
+
+In contrast to the float-to-half conversion, which reduces precision, the
+conversion from half to float (and thus to any other type implicitly
+convertible from float) is implicit, because all values represetable with
+half-precision are also representable with single-precision. This way the
+half-to-float conversion behaves similar to the builtin float-to-double
+conversion and all arithmetic expressions involving both half-precision and
+single-precision arguments will be of single-precision type. This way you can
+also directly use the mathematical functions of the C++ standard library,
+though in this case you will invoke the single-precision versions which will
+also return single-precision values, which is (even if maybe performing the
+exact same computation, see below) not as conceptually clean when working in a
+half-precision environment.
+
+The default rounding mode for conversions between half and more precise types
+as well as for rounding results of arithmetic operations and mathematical
+functions rounds to the nearest representable value. But by predefining the
+'HALF_ROUND_STYLE' preprocessor symbol this default can be overridden with one
+of the other standard rounding modes using their respective constants or the
+equivalent values of 'std::float_round_style' (it can even be synchronized with
+the built-in single-precision implementation by defining it to
+'std::numeric_limits<float>::round_style'):
+
+ - 'std::round_indeterminate' (-1) for the fastest rounding.
+
+ - 'std::round_toward_zero' (0) for rounding toward zero.
+
+ - 'std::round_to_nearest' (1) for rounding to the nearest value (default).
+
+ - 'std::round_toward_infinity' (2) for rounding toward positive infinity.
+
+ - 'std::round_toward_neg_infinity' (3) for rounding toward negative infinity.
+
+In addition to changing the overall default rounding mode one can also use the
+'half_cast'. This converts between half and any built-in arithmetic type using
+a configurable rounding mode (or the default rounding mode if none is
+specified). In addition to a configurable rounding mode, 'half_cast' has
+another big difference to a mere 'static_cast': Any conversions are performed
+directly using the given rounding mode, without any intermediate conversion
+to/from 'float'. This is especially relevant for conversions to integer types,
+which don't necessarily truncate anymore. But also for conversions from
+'double' or 'long double' this may produce more precise results than a
+pre-conversion to 'float' using the single-precision implementation's current
+rounding mode would.
+
+ half a = half_cast<half>(4.2);
+ half b = half_cast<half,std::numeric_limits<float>::round_style>(4.2f);
+ assert( half_cast<int, std::round_to_nearest>( 0.7_h ) == 1 );
+ assert( half_cast<half,std::round_toward_zero>( 4097 ) == 4096.0_h );
+ assert( half_cast<half,std::round_toward_infinity>( 4097 ) == 4100.0_h );
+ assert( half_cast<half,std::round_toward_infinity>( std::numeric_limits<double>::min() ) > 0.0_h );
+
+ACCURACY AND PERFORMANCE
+
+From version 2.0 onward the library is implemented without employing the
+underlying floating-point implementation of the system (except for conversions,
+of course), providing an entirely self-contained half-precision implementation
+with results independent from the system's existing single- or double-precision
+implementation and its rounding behaviour.
+
+As to accuracy, many of the operators and functions provided by this library
+are exact to rounding for all rounding modes, i.e. the error to the exact
+result is at most 0.5 ULP (unit in the last place) for rounding to nearest and
+less than 1 ULP for all other rounding modes. This holds for all the operations
+required by the IEEE 754 standard and many more. Specifically the following
+functions might exhibit a deviation from the correctly rounded exact result by
+1 ULP for a select few input values: 'expm1', 'log1p', 'pow', 'atan2', 'erf',
+'erfc', 'lgamma', 'tgamma' (for more details see the documentation of the
+individual functions). All other functions and operators are always exact to
+rounding or independent of the rounding mode altogether.
+
+The increased IEEE-conformance and cleanliness of this implementation comes
+with a certain performance cost compared to doing computations and mathematical
+functions in hardware-accelerated single-precision. On average and depending on
+the platform, the arithemtic operators are about 75% as fast and the
+mathematical functions about 33-50% as fast as performing the corresponding
+operations in single-precision and converting between the inputs and outputs.
+However, directly computing with half-precision values is a rather rare
+use-case and usually using actual 'float' values for all computations and
+temproraries and using 'half's only for storage is the recommended way. But
+nevertheless the goal of this library was to provide a complete and
+conceptually clean IEEE-confromant half-precision implementation and in the few
+cases when you do need to compute directly in half-precision you do so for a
+reason and want accurate results.
+
+If necessary, this internal implementation can be overridden by predefining the
+'HALF_ARITHMETIC_TYPE' preprocessor symbol to one of the built-in
+floating-point types ('float', 'double' or 'long double'), which will cause the
+library to use this type for computing arithmetic operations and mathematical
+functions (if available). However, due to using the platform's floating-point
+implementation (and its rounding behaviour) internally, this might cause
+results to deviate from the specified half-precision rounding mode. It will of
+course also inhibit the automatic exception detection described below.
+
+The conversion operations between half-precision and single-precision types can
+also make use of the F16C extension for x86 processors by using the
+corresponding compiler intrinsics from <immintrin.h>. Support for this is
+checked at compile-time by looking for the '__F16C__' macro which at least gcc
+and clang define based on the target platform. It can also be enabled manually
+by predefining the 'HALF_ENABLE_F16C_INTRINSICS' preprocessor symbol to 1, or 0
+for explicitly disabling it. However, this will directly use the corresponding
+intrinsics for conversion without checking if they are available at runtime
+(possibly crashing if they are not), so make sure they are supported on the
+target platform before enabling this.
+
+EXCEPTION HANDLING
+
+The half-precision implementation supports all 5 required floating-point
+exceptions from the IEEE standard to indicate erroneous inputs or inexact
+results during operations. These are represented by exception flags which
+actually use the same values as the corresponding 'FE_...' flags defined in
+C++11's <cfenv> header if supported, specifically:
+
+ - 'FE_INVALID' for invalid inputs to an operation.
+ - 'FE_DIVBYZERO' for finite inputs producing infinite results.
+ - 'FE_OVERFLOW' if a result is too large to represent finitely.
+ - 'FE_UNDERFLOW' for a subnormal or zero result after rounding.
+ - 'FE_INEXACT' if a result needed rounding to be representable.
+ - 'FE_ALL_EXCEPT' as a convenient OR of all possible exception flags.
+
+The internal exception flag state will start with all flags cleared and is
+maintained per thread if C++11 thread-local storage is supported, otherwise it
+will be maintained globally and will theoretically NOT be thread-safe (while
+practically being as thread-safe as a simple integer variable can be). These
+flags can be managed explicitly using the library's error handling functions,
+which again try to mimic the built-in functions for handling floating-point
+exceptions from <cfenv>. You can clear them with 'feclearexcept' (which is the
+only way a flag can be cleared), test them with 'fetestexcept', explicitly
+raise errors with 'feraiseexcept' and save and restore their state using
+'fegetexceptflag' and 'fesetexceptflag'. You can also throw corresponding C++
+exceptions based on the current flag state using 'fethrowexcept'.
+
+However, any automatic exception detection and handling during half-precision
+operations and functions is DISABLED by default, since it comes with a minor
+performance overhead due to runtime checks, and reacting to IEEE floating-point
+exceptions is rarely ever needed in application code. But the library fully
+supports IEEE-conformant detection of floating-point exceptions and various
+ways for handling them, which can be enabled by pre-defining the corresponding
+preprocessor symbols to 1. They can be enabled individually or all at once and
+they will be processed in the order they are listed here:
+
+ - 'HALF_ERRHANDLING_FLAGS' sets the internal exception flags described above
+ whenever the corresponding exception occurs.
+ - 'HALF_ERRHANDLING_ERRNO' sets the value of 'errno' from <cerrno> similar to
+ the behaviour of the built-in floating-point types when 'MATH_ERRNO' is used.
+ - 'HALF_ERRHANDLING_FENV' will propagate exceptions to the built-in
+ floating-point implementation using 'std::feraiseexcept' if support for
+ C++11 floating-point control is enabled. However, this does not synchronize
+ exceptions: neither will clearing propagate nor will it work in reverse.
+ - 'HALF_ERRHANDLING_THROW_...' can be defined to a string literal which will
+ be used as description message for a C++ exception that is thrown whenever
+ a 'FE_...' exception occurs, similar to the behaviour of 'fethrowexcept'.
+
+If any of the above error handling is activated, non-quiet operations on
+half-precision values will also raise a 'FE_INVALID' exception whenever
+they encounter a signaling NaN value, in addition to transforming the value
+into a quiet NaN. If error handling is disabled, signaling NaNs will be
+treated like quiet NaNs (while still getting explicitly quieted if propagated
+to the result). There can also be additional treatment of overflow and
+underflow errors after they have been processed as above, which is ENABLED by
+default (but of course only takes effect if any other exception handling is
+activated) unless overridden by pre-defining the corresponding preprocessor
+symbol to 0:
+
+ - 'HALF_ERRHANDLING_OVERFLOW_TO_INEXACT' will cause overflow errors to also
+ raise a 'FE_INEXACT' exception.
+ - 'HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT' will cause underflow errors to also
+ raise a 'FE_INEXACT' exception. This will also slightly change the
+ behaviour of the underflow exception, which will ONLY be raised if the
+ result is actually inexact due to underflow. If this is disabled, underflow
+ exceptions will be raised for ANY (possibly exact) subnormal result.
+
+
+CREDITS AND CONTACT
+-------------------
+
+This library is developed by CHRISTIAN RAU and released under the MIT License
+(see LICENSE.txt). If you have any questions or problems with it, feel free to
+contact me at rauy@users.sourceforge.net.
+
+Additional credit goes to JEROEN VAN DER ZIJP for his paper on "Fast Half Float
+Conversions", whose algorithms have been used in the library for converting
+between half-precision and single-precision values.
diff --git a/runtime/3rdparty/half/include/half/include/half.hpp b/runtime/3rdparty/half/include/half/include/half.hpp
new file mode 100644
index 000000000..0f60403e9
--- /dev/null
+++ b/runtime/3rdparty/half/include/half/include/half.hpp
@@ -0,0 +1,4575 @@
+// half - IEEE 754-based half-precision floating-point library.
+//
+// Copyright (c) 2012-2019 Christian Rau <rauy@users.sourceforge.net>
+//
+// 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.
+
+// Version 2.1.0
+
+/// \file
+/// Main header file for half-precision functionality.
+
+#ifndef HALF_HALF_HPP
+#define HALF_HALF_HPP
+
+#define HALF_GCC_VERSION (__GNUC__*100+__GNUC_MINOR__)
+
+#if defined(__INTEL_COMPILER)
+ #define HALF_ICC_VERSION __INTEL_COMPILER
+#elif defined(__ICC)
+ #define HALF_ICC_VERSION __ICC
+#elif defined(__ICL)
+ #define HALF_ICC_VERSION __ICL
+#else
+ #define HALF_ICC_VERSION 0
+#endif
+
+// check C++11 language features
+#if defined(__clang__) // clang
+ #if __has_feature(cxx_static_assert) && !defined(HALF_ENABLE_CPP11_STATIC_ASSERT)
+ #define HALF_ENABLE_CPP11_STATIC_ASSERT 1
+ #endif
+ #if __has_feature(cxx_constexpr) && !defined(HALF_ENABLE_CPP11_CONSTEXPR)
+ #define HALF_ENABLE_CPP11_CONSTEXPR 1
+ #endif
+ #if __has_feature(cxx_noexcept) && !defined(HALF_ENABLE_CPP11_NOEXCEPT)
+ #define HALF_ENABLE_CPP11_NOEXCEPT 1
+ #endif
+ #if __has_feature(cxx_user_literals) && !defined(HALF_ENABLE_CPP11_USER_LITERALS)
+ #define HALF_ENABLE_CPP11_USER_LITERALS 1
+ #endif
+ #if __has_feature(cxx_thread_local) && !defined(HALF_ENABLE_CPP11_THREAD_LOCAL)
+ #define HALF_ENABLE_CPP11_THREAD_LOCAL 1
+ #endif
+ #if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) && !defined(HALF_ENABLE_CPP11_LONG_LONG)
+ #define HALF_ENABLE_CPP11_LONG_LONG 1
+ #endif
+#elif HALF_ICC_VERSION && defined(__INTEL_CXX11_MODE__) // Intel C++
+ #if HALF_ICC_VERSION >= 1500 && !defined(HALF_ENABLE_CPP11_THREAD_LOCAL)
+ #define HALF_ENABLE_CPP11_THREAD_LOCAL 1
+ #endif
+ #if HALF_ICC_VERSION >= 1500 && !defined(HALF_ENABLE_CPP11_USER_LITERALS)
+ #define HALF_ENABLE_CPP11_USER_LITERALS 1
+ #endif
+ #if HALF_ICC_VERSION >= 1400 && !defined(HALF_ENABLE_CPP11_CONSTEXPR)
+ #define HALF_ENABLE_CPP11_CONSTEXPR 1
+ #endif
+ #if HALF_ICC_VERSION >= 1400 && !defined(HALF_ENABLE_CPP11_NOEXCEPT)
+ #define HALF_ENABLE_CPP11_NOEXCEPT 1
+ #endif
+ #if HALF_ICC_VERSION >= 1110 && !defined(HALF_ENABLE_CPP11_STATIC_ASSERT)
+ #define HALF_ENABLE_CPP11_STATIC_ASSERT 1
+ #endif
+ #if HALF_ICC_VERSION >= 1110 && !defined(HALF_ENABLE_CPP11_LONG_LONG)
+ #define HALF_ENABLE_CPP11_LONG_LONG 1
+ #endif
+#elif defined(__GNUC__) // gcc
+ #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
+ #if HALF_GCC_VERSION >= 408 && !defined(HALF_ENABLE_CPP11_THREAD_LOCAL)
+ #define HALF_ENABLE_CPP11_THREAD_LOCAL 1
+ #endif
+ #if HALF_GCC_VERSION >= 407 && !defined(HALF_ENABLE_CPP11_USER_LITERALS)
+ #define HALF_ENABLE_CPP11_USER_LITERALS 1
+ #endif
+ #if HALF_GCC_VERSION >= 406 && !defined(HALF_ENABLE_CPP11_CONSTEXPR)
+ #define HALF_ENABLE_CPP11_CONSTEXPR 1
+ #endif
+ #if HALF_GCC_VERSION >= 406 && !defined(HALF_ENABLE_CPP11_NOEXCEPT)
+ #define HALF_ENABLE_CPP11_NOEXCEPT 1
+ #endif
+ #if HALF_GCC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_STATIC_ASSERT)
+ #define HALF_ENABLE_CPP11_STATIC_ASSERT 1
+ #endif
+ #if !defined(HALF_ENABLE_CPP11_LONG_LONG)
+ #define HALF_ENABLE_CPP11_LONG_LONG 1
+ #endif
+ #endif
+ #define HALF_TWOS_COMPLEMENT_INT 1
+#elif defined(_MSC_VER) // Visual C++
+ #if _MSC_VER >= 1900 && !defined(HALF_ENABLE_CPP11_THREAD_LOCAL)
+ #define HALF_ENABLE_CPP11_THREAD_LOCAL 1
+ #endif
+ #if _MSC_VER >= 1900 && !defined(HALF_ENABLE_CPP11_USER_LITERALS)
+ #define HALF_ENABLE_CPP11_USER_LITERALS 1
+ #endif
+ #if _MSC_VER >= 1900 && !defined(HALF_ENABLE_CPP11_CONSTEXPR)
+ #define HALF_ENABLE_CPP11_CONSTEXPR 1
+ #endif
+ #if _MSC_VER >= 1900 && !defined(HALF_ENABLE_CPP11_NOEXCEPT)
+ #define HALF_ENABLE_CPP11_NOEXCEPT 1
+ #endif
+ #if _MSC_VER >= 1600 && !defined(HALF_ENABLE_CPP11_STATIC_ASSERT)
+ #define HALF_ENABLE_CPP11_STATIC_ASSERT 1
+ #endif
+ #if _MSC_VER >= 1310 && !defined(HALF_ENABLE_CPP11_LONG_LONG)
+ #define HALF_ENABLE_CPP11_LONG_LONG 1
+ #endif
+ #define HALF_TWOS_COMPLEMENT_INT 1
+ #define HALF_POP_WARNINGS 1
+ #pragma warning(push)
+ #pragma warning(disable : 4099 4127 4146) //struct vs class, constant in if, negative unsigned
+#endif
+
+// check C++11 library features
+#include <utility>
+#if defined(_LIBCPP_VERSION) // libc++
+ #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103
+ #ifndef HALF_ENABLE_CPP11_TYPE_TRAITS
+ #define HALF_ENABLE_CPP11_TYPE_TRAITS 1
+ #endif
+ #ifndef HALF_ENABLE_CPP11_CSTDINT
+ #define HALF_ENABLE_CPP11_CSTDINT 1
+ #endif
+ #ifndef HALF_ENABLE_CPP11_CMATH
+ #define HALF_ENABLE_CPP11_CMATH 1
+ #endif
+ #ifndef HALF_ENABLE_CPP11_HASH
+ #define HALF_ENABLE_CPP11_HASH 1
+ #endif
+ #ifndef HALF_ENABLE_CPP11_CFENV
+ #define HALF_ENABLE_CPP11_CFENV 1
+ #endif
+ #endif
+#elif defined(__GLIBCXX__) // libstdc++
+ #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103
+ #ifdef __clang__
+ #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_TYPE_TRAITS)
+ #define HALF_ENABLE_CPP11_TYPE_TRAITS 1
+ #endif
+ #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_CSTDINT)
+ #define HALF_ENABLE_CPP11_CSTDINT 1
+ #endif
+ #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_CMATH)
+ #define HALF_ENABLE_CPP11_CMATH 1
+ #endif
+ #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_HASH)
+ #define HALF_ENABLE_CPP11_HASH 1
+ #endif
+ #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_CFENV)
+ #define HALF_ENABLE_CPP11_CFENV 1
+ #endif
+ #else
+ #if HALF_GCC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_TYPE_TRAITS)
+ #define HALF_ENABLE_CPP11_TYPE_TRAITS 1
+ #endif
+ #if HALF_GCC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_CSTDINT)
+ #define HALF_ENABLE_CPP11_CSTDINT 1
+ #endif
+ #if HALF_GCC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_CMATH)
+ #define HALF_ENABLE_CPP11_CMATH 1
+ #endif
+ #if HALF_GCC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_HASH)
+ #define HALF_ENABLE_CPP11_HASH 1
+ #endif
+ #if HALF_GCC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_CFENV)
+ #define HALF_ENABLE_CPP11_CFENV 1
+ #endif
+ #endif
+ #endif
+#elif defined(_CPPLIB_VER) // Dinkumware/Visual C++
+ #if _CPPLIB_VER >= 520 && !defined(HALF_ENABLE_CPP11_TYPE_TRAITS)
+ #define HALF_ENABLE_CPP11_TYPE_TRAITS 1
+ #endif
+ #if _CPPLIB_VER >= 520 && !defined(HALF_ENABLE_CPP11_CSTDINT)
+ #define HALF_ENABLE_CPP11_CSTDINT 1
+ #endif
+ #if _CPPLIB_VER >= 520 && !defined(HALF_ENABLE_CPP11_HASH)
+ #define HALF_ENABLE_CPP11_HASH 1
+ #endif
+ #if _CPPLIB_VER >= 610 && !defined(HALF_ENABLE_CPP11_CMATH)
+ #define HALF_ENABLE_CPP11_CMATH 1
+ #endif
+ #if _CPPLIB_VER >= 610 && !defined(HALF_ENABLE_CPP11_CFENV)
+ #define HALF_ENABLE_CPP11_CFENV 1
+ #endif
+#endif
+#undef HALF_GCC_VERSION
+#undef HALF_ICC_VERSION
+
+// any error throwing C++ exceptions?
+#if defined(HALF_ERRHANDLING_THROW_INVALID) || defined(HALF_ERRHANDLING_THROW_DIVBYZERO) || defined(HALF_ERRHANDLING_THROW_OVERFLOW) || defined(HALF_ERRHANDLING_THROW_UNDERFLOW) || defined(HALF_ERRHANDLING_THROW_INEXACT)
+#define HALF_ERRHANDLING_THROWS 1
+#endif
+
+// any error handling enabled?
+#define HALF_ERRHANDLING (HALF_ERRHANDLING_FLAGS||HALF_ERRHANDLING_ERRNO||HALF_ERRHANDLING_FENV||HALF_ERRHANDLING_THROWS)
+
+#if HALF_ERRHANDLING
+ #define HALF_UNUSED_NOERR(name) name
+#else
+ #define HALF_UNUSED_NOERR(name)
+#endif
+
+// support constexpr
+#if HALF_ENABLE_CPP11_CONSTEXPR
+ #define HALF_CONSTEXPR constexpr
+ #define HALF_CONSTEXPR_CONST constexpr
+ #if HALF_ERRHANDLING
+ #define HALF_CONSTEXPR_NOERR
+ #else
+ #define HALF_CONSTEXPR_NOERR constexpr
+ #endif
+#else
+ #define HALF_CONSTEXPR
+ #define HALF_CONSTEXPR_CONST const
+ #define HALF_CONSTEXPR_NOERR
+#endif
+
+// support noexcept
+#if HALF_ENABLE_CPP11_NOEXCEPT
+ #define HALF_NOEXCEPT noexcept
+ #define HALF_NOTHROW noexcept
+#else
+ #define HALF_NOEXCEPT
+ #define HALF_NOTHROW throw()
+#endif
+
+// support thread storage
+#if HALF_ENABLE_CPP11_THREAD_LOCAL
+ #define HALF_THREAD_LOCAL thread_local
+#else
+ #define HALF_THREAD_LOCAL static
+#endif
+
+#include <utility>
+#include <algorithm>
+#include <istream>
+#include <ostream>
+#include <limits>
+#include <stdexcept>
+#include <climits>
+#include <cmath>
+#include <cstring>
+#include <cstdlib>
+#if HALF_ENABLE_CPP11_TYPE_TRAITS
+ #include <type_traits>
+#endif
+#if HALF_ENABLE_CPP11_CSTDINT
+ #include <cstdint>
+#endif
+#if HALF_ERRHANDLING_ERRNO
+ #include <cerrno>
+#endif
+#if HALF_ENABLE_CPP11_CFENV
+ #include <cfenv>
+#endif
+#if HALF_ENABLE_CPP11_HASH
+ #include <functional>
+#endif
+#if HALF_ENABLE_F16C_INTRINSICS
+ #include <immintrin.h>
+#endif
+
+
+#ifndef HALF_ENABLE_F16C_INTRINSICS
+ /// Enable F16C intruction set intrinsics.
+ /// Defining this to 1 enables the use of [F16C compiler intrinsics](https://en.wikipedia.org/wiki/F16C) for converting between
+ /// half-precision and single-precision values which may result in improved performance. This will not perform additional checks
+ /// for support of the F16C instruction set, so an appropriate target platform is required when enabling this feature.
+ ///
+ /// Unless predefined it will be enabled automatically when the `__F16C__` symbol is defined, which some compilers do on supporting platforms.
+ #define HALF_ENABLE_F16C_INTRINSICS __F16C__
+#endif
+
+#ifdef HALF_DOXYGEN_ONLY
+/// Type for internal floating-point computations.
+/// This can be predefined to a built-in floating-point type (`float`, `double` or `long double`) to override the internal
+/// half-precision implementation to use this type for computing arithmetic operations and mathematical function (if available).
+/// This can result in improved performance for arithmetic operators and mathematical functions but might cause results to
+/// deviate from the specified half-precision rounding mode and inhibits proper detection of half-precision exceptions.
+#define HALF_ARITHMETIC_TYPE (undefined)
+
+/// Enable internal exception flags.
+/// Defining this to 1 causes operations on half-precision values to raise internal floating-point exception flags according to
+/// the IEEE 754 standard. These can then be cleared and checked with clearexcept(), testexcept().
+#define HALF_ERRHANDLING_FLAGS 0
+
+/// Enable exception propagation to `errno`.
+/// Defining this to 1 causes operations on half-precision values to propagate floating-point exceptions to
+/// [errno](https://en.cppreference.com/w/cpp/error/errno) from `<cerrno>`. Specifically this will propagate domain errors as
+/// [EDOM](https://en.cppreference.com/w/cpp/error/errno_macros) and pole, overflow and underflow errors as
+/// [ERANGE](https://en.cppreference.com/w/cpp/error/errno_macros). Inexact errors won't be propagated.
+#define HALF_ERRHANDLING_ERRNO 0
+
+/// Enable exception propagation to built-in floating-point platform.
+/// Defining this to 1 causes operations on half-precision values to propagate floating-point exceptions to the built-in
+/// single- and double-precision implementation's exception flags using the
+/// [C++11 floating-point environment control](https://en.cppreference.com/w/cpp/numeric/fenv) from `<cfenv>`. However, this
+/// does not work in reverse and single- or double-precision exceptions will not raise the corresponding half-precision
+/// exception flags, nor will explicitly clearing flags clear the corresponding built-in flags.
+#define HALF_ERRHANDLING_FENV 0
+
+/// Throw C++ exception on domain errors.
+/// Defining this to a string literal causes operations on half-precision values to throw a
+/// [std::domain_error](https://en.cppreference.com/w/cpp/error/domain_error) with the specified message on domain errors.
+#define HALF_ERRHANDLING_THROW_INVALID (undefined)
+
+/// Throw C++ exception on pole errors.
+/// Defining this to a string literal causes operations on half-precision values to throw a
+/// [std::domain_error](https://en.cppreference.com/w/cpp/error/domain_error) with the specified message on pole errors.
+#define HALF_ERRHANDLING_THROW_DIVBYZERO (undefined)
+
+/// Throw C++ exception on overflow errors.
+/// Defining this to a string literal causes operations on half-precision values to throw a
+/// [std::overflow_error](https://en.cppreference.com/w/cpp/error/overflow_error) with the specified message on overflows.
+#define HALF_ERRHANDLING_THROW_OVERFLOW (undefined)
+
+/// Throw C++ exception on underflow errors.
+/// Defining this to a string literal causes operations on half-precision values to throw a
+/// [std::underflow_error](https://en.cppreference.com/w/cpp/error/underflow_error) with the specified message on underflows.
+#define HALF_ERRHANDLING_THROW_UNDERFLOW (undefined)
+
+/// Throw C++ exception on rounding errors.
+/// Defining this to 1 causes operations on half-precision values to throw a
+/// [std::range_error](https://en.cppreference.com/w/cpp/error/range_error) with the specified message on general rounding errors.
+#define HALF_ERRHANDLING_THROW_INEXACT (undefined)
+#endif
+
+#ifndef HALF_ERRHANDLING_OVERFLOW_TO_INEXACT
+/// Raise INEXACT exception on overflow.
+/// Defining this to 1 (default) causes overflow errors to automatically raise inexact exceptions in addition.
+/// These will be raised after any possible handling of the underflow exception.
+#define HALF_ERRHANDLING_OVERFLOW_TO_INEXACT 1
+#endif
+
+#ifndef HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT
+/// Raise INEXACT exception on underflow.
+/// Defining this to 1 (default) causes underflow errors to automatically raise inexact exceptions in addition.
+/// These will be raised after any possible handling of the underflow exception.
+///
+/// **Note:** This will actually cause underflow (and the accompanying inexact) exceptions to be raised *only* when the result
+/// is inexact, while if disabled bare underflow errors will be raised for *any* (possibly exact) subnormal result.
+#define HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT 1
+#endif
+
+/// Default rounding mode.
+/// This specifies the rounding mode used for all conversions between [half](\ref half_float::half)s and more precise types
+/// (unless using half_cast() and specifying the rounding mode directly) as well as in arithmetic operations and mathematical
+/// functions. It can be redefined (before including half.hpp) to one of the standard rounding modes using their respective
+/// constants or the equivalent values of
+/// [std::float_round_style](https://en.cppreference.com/w/cpp/types/numeric_limits/float_round_style):
+///
+/// `std::float_round_style` | value | rounding
+/// ---------------------------------|-------|-------------------------
+/// `std::round_indeterminate` | -1 | fastest
+/// `std::round_toward_zero` | 0 | toward zero
+/// `std::round_to_nearest` | 1 | to nearest (default)
+/// `std::round_toward_infinity` | 2 | toward positive infinity
+/// `std::round_toward_neg_infinity` | 3 | toward negative infinity
+///
+/// By default this is set to `1` (`std::round_to_nearest`), which rounds results to the nearest representable value. It can even
+/// be set to [std::numeric_limits<float>::round_style](https://en.cppreference.com/w/cpp/types/numeric_limits/round_style) to synchronize
+/// the rounding mode with that of the built-in single-precision implementation (which is likely `std::round_to_nearest`, though).
+#ifndef HALF_ROUND_STYLE
+ #define HALF_ROUND_STYLE 1 // = std::round_to_nearest
+#endif
+
+/// Value signaling overflow.
+/// In correspondence with `HUGE_VAL[F|L]` from `<cmath>` this symbol expands to a positive value signaling the overflow of an
+/// operation, in particular it just evaluates to positive infinity.
+///
+/// **See also:** Documentation for [HUGE_VAL](https://en.cppreference.com/w/cpp/numeric/math/HUGE_VAL)
+#define HUGE_VALH std::numeric_limits<half_float::half>::infinity()
+
+/// Fast half-precision fma function.
+/// This symbol is defined if the fma() function generally executes as fast as, or faster than, a separate
+/// half-precision multiplication followed by an addition, which is always the case.
+///
+/// **See also:** Documentation for [FP_FAST_FMA](https://en.cppreference.com/w/cpp/numeric/math/fma)
+#define FP_FAST_FMAH 1
+
+/// Half rounding mode.
+/// In correspondence with `FLT_ROUNDS` from `<cfloat>` this symbol expands to the rounding mode used for
+/// half-precision operations. It is an alias for [HALF_ROUND_STYLE](\ref HALF_ROUND_STYLE).
+///
+/// **See also:** Documentation for [FLT_ROUNDS](https://en.cppreference.com/w/cpp/types/climits/FLT_ROUNDS)
+#define HLF_ROUNDS HALF_ROUND_STYLE
+
+#ifndef FP_ILOGB0
+ #define FP_ILOGB0 INT_MIN
+#endif
+#ifndef FP_ILOGBNAN
+ #define FP_ILOGBNAN INT_MAX
+#endif
+#ifndef FP_SUBNORMAL
+ #define FP_SUBNORMAL 0
+#endif
+#ifndef FP_ZERO
+ #define FP_ZERO 1
+#endif
+#ifndef FP_NAN
+ #define FP_NAN 2
+#endif
+#ifndef FP_INFINITE
+ #define FP_INFINITE 3
+#endif
+#ifndef FP_NORMAL
+ #define FP_NORMAL 4
+#endif
+
+#if !HALF_ENABLE_CPP11_CFENV && !defined(FE_ALL_EXCEPT)
+ #define FE_INVALID 0x10
+ #define FE_DIVBYZERO 0x08
+ #define FE_OVERFLOW 0x04
+ #define FE_UNDERFLOW 0x02
+ #define FE_INEXACT 0x01
+ #define FE_ALL_EXCEPT (FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW|FE_UNDERFLOW|FE_INEXACT)
+#endif
+
+
+/// Main namespace for half-precision functionality.
+/// This namespace contains all the functionality provided by the library.
+namespace half_float
+{
+ class half;
+
+#if HALF_ENABLE_CPP11_USER_LITERALS
+ /// Library-defined half-precision literals.
+ /// Import this namespace to enable half-precision floating-point literals:
+ /// ~~~~{.cpp}
+ /// using namespace half_float::literal;
+ /// half_float::half = 4.2_h;
+ /// ~~~~
+ namespace literal
+ {
+ half operator "" _h(long double);
+ }
+#endif
+
+ /// \internal
+ /// \brief Implementation details.
+ namespace detail
+ {
+ #if HALF_ENABLE_CPP11_TYPE_TRAITS
+ /// Conditional type.
+ template<bool B,typename T,typename F> struct conditional : std::conditional<B,T,F> {};
+
+ /// Helper for tag dispatching.
+ template<bool B> struct bool_type : std::integral_constant<bool,B> {};
+ using std::true_type;
+ using std::false_type;
+
+ /// Type traits for floating-point types.
+ template<typename T> struct is_float : std::is_floating_point<T> {};
+ #else
+ /// Conditional type.
+ template<bool,typename T,typename> struct conditional { typedef T type; };
+ template<typename T,typename F> struct conditional<false,T,F> { typedef F type; };
+
+ /// Helper for tag dispatching.
+ template<bool> struct bool_type {};
+ typedef bool_type<true> true_type;
+ typedef bool_type<false> false_type;
+
+ /// Type traits for floating-point types.
+ template<typename> struct is_float : false_type {};
+ template<typename T> struct is_float<const T> : is_float<T> {};
+ template<typename T> struct is_float<volatile T> : is_float<T> {};
+ template<typename T> struct is_float<const volatile T> : is_float<T> {};
+ template<> struct is_float<float> : true_type {};
+ template<> struct is_float<double> : true_type {};
+ template<> struct is_float<long double> : true_type {};
+ #endif
+
+ /// Type traits for floating-point bits.
+ template<typename T> struct bits { typedef unsigned char type; };
+ template<typename T> struct bits<const T> : bits<T> {};
+ template<typename T> struct bits<volatile T> : bits<T> {};
+ template<typename T> struct bits<const volatile T> : bits<T> {};
+
+ #if HALF_ENABLE_CPP11_CSTDINT
+ /// Unsigned integer of (at least) 16 bits width.
+ typedef std::uint_least16_t uint16;
+
+ /// Fastest unsigned integer of (at least) 32 bits width.
+ typedef std::uint_fast32_t uint32;
+
+ /// Fastest signed integer of (at least) 32 bits width.
+ typedef std::int_fast32_t int32;
+
+ /// Unsigned integer of (at least) 32 bits width.
+ template<> struct bits<float> { typedef std::uint_least32_t type; };
+
+ /// Unsigned integer of (at least) 64 bits width.
+ template<> struct bits<double> { typedef std::uint_least64_t type; };
+ #else
+ /// Unsigned integer of (at least) 16 bits width.
+ typedef unsigned short uint16;
+
+ /// Fastest unsigned integer of (at least) 32 bits width.
+ typedef unsigned long uint32;
+
+ /// Fastest unsigned integer of (at least) 32 bits width.
+ typedef long int32;
+
+ /// Unsigned integer of (at least) 32 bits width.
+ template<> struct bits<float> : conditional<std::numeric_limits<unsigned int>::digits>=32,unsigned int,unsigned long> {};
+
+ #if HALF_ENABLE_CPP11_LONG_LONG
+ /// Unsigned integer of (at least) 64 bits width.
+ template<> struct bits<double> : conditional<std::numeric_limits<unsigned long>::digits>=64,unsigned long,unsigned long long> {};
+ #else
+ /// Unsigned integer of (at least) 64 bits width.
+ template<> struct bits<double> { typedef unsigned long type; };
+ #endif
+ #endif
+
+ #ifdef HALF_ARITHMETIC_TYPE
+ /// Type to use for arithmetic computations and mathematic functions internally.
+ typedef HALF_ARITHMETIC_TYPE internal_t;
+ #endif
+
+ /// Tag type for binary construction.
+ struct binary_t {};
+
+ /// Tag for binary construction.
+ HALF_CONSTEXPR_CONST binary_t binary = binary_t();
+
+ /// \name Implementation defined classification and arithmetic
+ /// \{
+
+ /// Check for infinity.
+ /// \tparam T argument type (builtin floating-point type)
+ /// \param arg value to query
+ /// \retval true if infinity
+ /// \retval false else
+ template<typename T> bool builtin_isinf(T arg)
+ {
+ #if HALF_ENABLE_CPP11_CMATH
+ return std::isinf(arg);
+ #elif defined(_MSC_VER)
+ return !::_finite(static_cast<double>(arg)) && !::_isnan(static_cast<double>(arg));
+ #else
+ return arg == std::numeric_limits<T>::infinity() || arg == -std::numeric_limits<T>::infinity();
+ #endif
+ }
+
+ /// Check for NaN.
+ /// \tparam T argument type (builtin floating-point type)
+ /// \param arg value to query
+ /// \retval true if not a number
+ /// \retval false else
+ template<typename T> bool builtin_isnan(T arg)
+ {
+ #if HALF_ENABLE_CPP11_CMATH
+ return std::isnan(arg);
+ #elif defined(_MSC_VER)
+ return ::_isnan(static_cast<double>(arg)) != 0;
+ #else
+ return arg != arg;
+ #endif
+ }
+
+ /// Check sign.
+ /// \tparam T argument type (builtin floating-point type)
+ /// \param arg value to query
+ /// \retval true if signbit set
+ /// \retval false else
+ template<typename T> bool builtin_signbit(T arg)
+ {
+ #if HALF_ENABLE_CPP11_CMATH
+ return std::signbit(arg);
+ #else
+ return arg < T() || (arg == T() && T(1)/arg < T());
+ #endif
+ }
+
+ /// Platform-independent sign mask.
+ /// \param arg integer value in two's complement
+ /// \retval -1 if \a arg negative
+ /// \retval 0 if \a arg positive
+ inline uint32 sign_mask(uint32 arg)
+ {
+ static const int N = std::numeric_limits<uint32>::digits - 1;
+ #if HALF_TWOS_COMPLEMENT_INT
+ return static_cast<int32>(arg) >> N;
+ #else
+ return -((arg>>N)&1);
+ #endif
+ }
+
+ /// Platform-independent arithmetic right shift.
+ /// \param arg integer value in two's complement
+ /// \param i shift amount (at most 31)
+ /// \return \a arg right shifted for \a i bits with possible sign extension
+ inline uint32 arithmetic_shift(uint32 arg, int i)
+ {
+ #if HALF_TWOS_COMPLEMENT_INT
+ return static_cast<int32>(arg) >> i;
+ #else
+ return static_cast<int32>(arg)/(static_cast<int32>(1)<<i) - ((arg>>(std::numeric_limits<uint32>::digits-1))&1);
+ #endif
+ }
+
+ /// \}
+ /// \name Error handling
+ /// \{
+
+ /// Internal exception flags.
+ /// \return reference to global exception flags
+ inline int& errflags() { HALF_THREAD_LOCAL int flags = 0; return flags; }
+
+ /// Raise floating-point exception.
+ /// \param flags exceptions to raise
+ /// \param cond condition to raise exceptions for
+ inline void raise(int HALF_UNUSED_NOERR(flags), bool HALF_UNUSED_NOERR(cond) = true)
+ {
+ #if HALF_ERRHANDLING
+ if(!cond)
+ return;
+ #if HALF_ERRHANDLING_FLAGS
+ errflags() |= flags;
+ #endif
+ #if HALF_ERRHANDLING_ERRNO
+ if(flags & FE_INVALID)
+ errno = EDOM;
+ else if(flags & (FE_DIVBYZERO|FE_OVERFLOW|FE_UNDERFLOW))
+ errno = ERANGE;
+ #endif
+ #if HALF_ERRHANDLING_FENV && HALF_ENABLE_CPP11_CFENV
+ std::feraiseexcept(flags);
+ #endif
+ #ifdef HALF_ERRHANDLING_THROW_INVALID
+ if(flags & FE_INVALID)
+ throw std::domain_error(HALF_ERRHANDLING_THROW_INVALID);
+ #endif
+ #ifdef HALF_ERRHANDLING_THROW_DIVBYZERO
+ if(flags & FE_DIVBYZERO)
+ throw std::domain_error(HALF_ERRHANDLING_THROW_DIVBYZERO);
+ #endif
+ #ifdef HALF_ERRHANDLING_THROW_OVERFLOW
+ if(flags & FE_OVERFLOW)
+ throw std::overflow_error(HALF_ERRHANDLING_THROW_OVERFLOW);
+ #endif
+ #ifdef HALF_ERRHANDLING_THROW_UNDERFLOW
+ if(flags & FE_UNDERFLOW)
+ throw std::underflow_error(HALF_ERRHANDLING_THROW_UNDERFLOW);
+ #endif
+ #ifdef HALF_ERRHANDLING_THROW_INEXACT
+ if(flags & FE_INEXACT)
+ throw std::range_error(HALF_ERRHANDLING_THROW_INEXACT);
+ #endif
+ #if HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT
+ if((flags & FE_UNDERFLOW) && !(flags & FE_INEXACT))
+ raise(FE_INEXACT);
+ #endif
+ #if HALF_ERRHANDLING_OVERFLOW_TO_INEXACT
+ if((flags & FE_OVERFLOW) && !(flags & FE_INEXACT))
+ raise(FE_INEXACT);
+ #endif
+ #endif
+ }
+
+ /// Check and signal for any NaN.
+ /// \param x first half-precision value to check
+ /// \param y second half-precision value to check
+ /// \retval true if either \a x or \a y is NaN
+ /// \retval false else
+ /// \exception FE_INVALID if \a x or \a y is NaN
+ inline HALF_CONSTEXPR_NOERR bool compsignal(unsigned int x, unsigned int y)
+ {
+ #if HALF_ERRHANDLING
+ raise(FE_INVALID, (x&0x7FFF)>0x7C00 || (y&0x7FFF)>0x7C00);
+ #endif
+ return (x&0x7FFF) > 0x7C00 || (y&0x7FFF) > 0x7C00;
+ }
+
+ /// Signal and silence signaling NaN.
+ /// \param nan half-precision NaN value
+ /// \return quiet NaN
+ /// \exception FE_INVALID if \a nan is signaling NaN
+ inline HALF_CONSTEXPR_NOERR unsigned int signal(unsigned int nan)
+ {
+ #if HALF_ERRHANDLING
+ raise(FE_INVALID, !(nan&0x200));
+ #endif
+ return nan | 0x200;
+ }
+
+ /// Signal and silence signaling NaNs.
+ /// \param x first half-precision value to check
+ /// \param y second half-precision value to check
+ /// \return quiet NaN
+ /// \exception FE_INVALID if \a x or \a y is signaling NaN
+ inline HALF_CONSTEXPR_NOERR unsigned int signal(unsigned int x, unsigned int y)
+ {
+ #if HALF_ERRHANDLING
+ raise(FE_INVALID, ((x&0x7FFF)>0x7C00 && !(x&0x200)) || ((y&0x7FFF)>0x7C00 && !(y&0x200)));
+ #endif
+ return ((x&0x7FFF)>0x7C00) ? (x|0x200) : (y|0x200);
+ }
+
+ /// Signal and silence signaling NaNs.
+ /// \param x first half-precision value to check
+ /// \param y second half-precision value to check
+ /// \param z third half-precision value to check
+ /// \return quiet NaN
+ /// \exception FE_INVALID if \a x, \a y or \a z is signaling NaN
+ inline HALF_CONSTEXPR_NOERR unsigned int signal(unsigned int x, unsigned int y, unsigned int z)
+ {
+ #if HALF_ERRHANDLING
+ raise(FE_INVALID, ((x&0x7FFF)>0x7C00 && !(x&0x200)) || ((y&0x7FFF)>0x7C00 && !(y&0x200)) || ((z&0x7FFF)>0x7C00 && !(z&0x200)));
+ #endif
+ return ((x&0x7FFF)>0x7C00) ? (x|0x200) : ((y&0x7FFF)>0x7C00) ? (y|0x200) : (z|0x200);
+ }
+
+ /// Select value or signaling NaN.
+ /// \param x preferred half-precision value
+ /// \param y ignored half-precision value except for signaling NaN
+ /// \return \a y if signaling NaN, \a x otherwise
+ /// \exception FE_INVALID if \a y is signaling NaN
+ inline HALF_CONSTEXPR_NOERR unsigned int select(unsigned int x, unsigned int HALF_UNUSED_NOERR(y))
+ {
+ #if HALF_ERRHANDLING
+ return (((y&0x7FFF)>0x7C00) && !(y&0x200)) ? signal(y) : x;
+ #else
+ return x;
+ #endif
+ }
+
+ /// Raise domain error and return NaN.
+ /// return quiet NaN
+ /// \exception FE_INVALID
+ inline HALF_CONSTEXPR_NOERR unsigned int invalid()
+ {
+ #if HALF_ERRHANDLING
+ raise(FE_INVALID);
+ #endif
+ return 0x7FFF;
+ }
+
+ /// Raise pole error and return infinity.
+ /// \param sign half-precision value with sign bit only
+ /// \return half-precision infinity with sign of \a sign
+ /// \exception FE_DIVBYZERO
+ inline HALF_CONSTEXPR_NOERR unsigned int pole(unsigned int sign = 0)
+ {
+ #if HALF_ERRHANDLING
+ raise(FE_DIVBYZERO);
+ #endif
+ return sign | 0x7C00;
+ }
+
+ /// Check value for underflow.
+ /// \param arg non-zero half-precision value to check
+ /// \return \a arg
+ /// \exception FE_UNDERFLOW if arg is subnormal
+ inline HALF_CONSTEXPR_NOERR unsigned int check_underflow(unsigned int arg)
+ {
+ #if HALF_ERRHANDLING && !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT
+ raise(FE_UNDERFLOW, !(arg&0x7C00));
+ #endif
+ return arg;
+ }
+
+ /// \}
+ /// \name Conversion and rounding
+ /// \{
+
+ /// Half-precision overflow.
+ /// \tparam R rounding mode to use
+ /// \param sign half-precision value with sign bit only
+ /// \return rounded overflowing half-precision value
+ /// \exception FE_OVERFLOW
+ template<std::float_round_style R> HALF_CONSTEXPR_NOERR unsigned int overflow(unsigned int sign = 0)
+ {
+ #if HALF_ERRHANDLING
+ raise(FE_OVERFLOW);
+ #endif
+ return (R==std::round_toward_infinity) ? (sign+0x7C00-(sign>>15)) :
+ (R==std::round_toward_neg_infinity) ? (sign+0x7BFF+(sign>>15)) :
+ (R==std::round_toward_zero) ? (sign|0x7BFF) :
+ (sign|0x7C00);
+ }
+
+ /// Half-precision underflow.
+ /// \tparam R rounding mode to use
+ /// \param sign half-precision value with sign bit only
+ /// \return rounded underflowing half-precision value
+ /// \exception FE_UNDERFLOW
+ template<std::float_round_style R> HALF_CONSTEXPR_NOERR unsigned int underflow(unsigned int sign = 0)
+ {
+ #if HALF_ERRHANDLING
+ raise(FE_UNDERFLOW);
+ #endif
+ return (R==std::round_toward_infinity) ? (sign+1-(sign>>15)) :
+ (R==std::round_toward_neg_infinity) ? (sign+(sign>>15)) :
+ sign;
+ }
+
+ /// Round half-precision number.
+ /// \tparam R rounding mode to use
+ /// \tparam I `true` to always raise INEXACT exception, `false` to raise only for rounded results
+ /// \param value finite half-precision number to round
+ /// \param g guard bit (most significant discarded bit)
+ /// \param s sticky bit (or of all but the most significant discarded bits)
+ /// \return rounded half-precision value
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if value had to be rounded or \a I is `true`
+ template<std::float_round_style R,bool I> HALF_CONSTEXPR_NOERR unsigned int rounded(unsigned int value, int g, int s)
+ {
+ #if HALF_ERRHANDLING
+ value += (R==std::round_to_nearest) ? (g&(s|value)) :
+ (R==std::round_toward_infinity) ? (~(value>>15)&(g|s)) :
+ (R==std::round_toward_neg_infinity) ? ((value>>15)&(g|s)) : 0;
+ if((value&0x7C00) == 0x7C00)
+ raise(FE_OVERFLOW);
+ else if(value & 0x7C00)
+ raise(FE_INEXACT, I || (g|s)!=0);
+ else
+ raise(FE_UNDERFLOW, !(HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT) || I || (g|s)!=0);
+ return value;
+ #else
+ return (R==std::round_to_nearest) ? (value+(g&(s|value))) :
+ (R==std::round_toward_infinity) ? (value+(~(value>>15)&(g|s))) :
+ (R==std::round_toward_neg_infinity) ? (value+((value>>15)&(g|s))) :
+ value;
+ #endif
+ }
+
+ /// Round half-precision number to nearest integer value.
+ /// \tparam R rounding mode to use
+ /// \tparam E `true` for round to even, `false` for round away from zero
+ /// \tparam I `true` to raise INEXACT exception (if inexact), `false` to never raise it
+ /// \param value half-precision value to round
+ /// \return half-precision bits for nearest integral value
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_INEXACT if value had to be rounded and \a I is `true`
+ template<std::float_round_style R,bool E,bool I> unsigned int integral(unsigned int value)
+ {
+ unsigned int abs = value & 0x7FFF;
+ if(abs < 0x3C00)
+ {
+ raise(FE_INEXACT, I);
+ return ((R==std::round_to_nearest) ? (0x3C00&-static_cast<unsigned>(abs>=(0x3800+E))) :
+ (R==std::round_toward_infinity) ? (0x3C00&-(~(value>>15)&(abs!=0))) :
+ (R==std::round_toward_neg_infinity) ? (0x3C00&-static_cast<unsigned>(value>0x8000)) :
+ 0) | (value&0x8000);
+ }
+ if(abs >= 0x6400)
+ return (abs>0x7C00) ? signal(value) : value;
+ unsigned int exp = 25 - (abs>>10), mask = (1<<exp) - 1;
+ raise(FE_INEXACT, I && (value&mask));
+ return (( (R==std::round_to_nearest) ? ((1<<(exp-1))-(~(value>>exp)&E)) :
+ (R==std::round_toward_infinity) ? (mask&((value>>15)-1)) :
+ (R==std::round_toward_neg_infinity) ? (mask&-(value>>15)) :
+ 0) + value) & ~mask;
+ }
+
+ /// Convert fixed point to half-precision floating-point.
+ /// \tparam R rounding mode to use
+ /// \tparam F number of fractional bits (at least 11)
+ /// \tparam S `true` for signed, `false` for unsigned
+ /// \tparam N `true` for additional normalization step, `false` if already normalized to 1.F
+ /// \tparam I `true` to always raise INEXACT exception, `false` to raise only for rounded results
+ /// \param m mantissa in Q1.F fixed point format
+ /// \param exp exponent
+ /// \param sign half-precision value with sign bit only
+ /// \param s sticky bit (or of all but the most significant already discarded bits)
+ /// \return value converted to half-precision
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if value had to be rounded or \a I is `true`
+ template<std::float_round_style R,unsigned int F,bool S,bool N,bool I> unsigned int fixed2half(uint32 m, int exp = 14, unsigned int sign = 0, int s = 0)
+ {
+ if(S)
+ {
+ uint32 msign = sign_mask(m);
+ m = (m^msign) - msign;
+ sign = msign & 0x8000;
+ }
+ if(N)
+ for(; m<(static_cast<uint32>(1)<<F) && exp; m<<=1,--exp) ;
+ else if(exp < 0)
+ return rounded<R,I>(sign+(m>>(F-10-exp)), (m>>(F-11-exp))&1, s|((m&((static_cast<uint32>(1)<<(F-11-exp))-1))!=0));
+ return rounded<R,I>(sign+(exp<<10)+(m>>(F-10)), (m>>(F-11))&1, s|((m&((static_cast<uint32>(1)<<(F-11))-1))!=0));
+ }
+
+ /// Convert IEEE single-precision to half-precision.
+ /// Credit for this goes to [Jeroen van der Zijp](ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf).
+ /// \tparam R rounding mode to use
+ /// \param value single-precision value to convert
+ /// \return rounded half-precision value
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if value had to be rounded
+ template<std::float_round_style R> unsigned int float2half_impl(float value, true_type)
+ {
+ #if HALF_ENABLE_F16C_INTRINSICS
+ return _mm_cvtsi128_si32(_mm_cvtps_ph(_mm_set_ss(value),
+ (R==std::round_to_nearest) ? _MM_FROUND_TO_NEAREST_INT :
+ (R==std::round_toward_zero) ? _MM_FROUND_TO_ZERO :
+ (R==std::round_toward_infinity) ? _MM_FROUND_TO_POS_INF :
+ (R==std::round_toward_neg_infinity) ? _MM_FROUND_TO_NEG_INF :
+ _MM_FROUND_CUR_DIRECTION));
+ #else
+ bits<float>::type fbits;
+ std::memcpy(&fbits, &value, sizeof(float));
+ #if 1
+ unsigned int sign = (fbits>>16) & 0x8000;
+ fbits &= 0x7FFFFFFF;
+ if(fbits >= 0x7F800000)
+ return sign | 0x7C00 | ((fbits>0x7F800000) ? (0x200|((fbits>>13)&0x3FF)) : 0);
+ if(fbits >= 0x47800000)
+ return overflow<R>(sign);
+ if(fbits >= 0x38800000)
+ return rounded<R,false>(sign|(((fbits>>23)-112)<<10)|((fbits>>13)&0x3FF), (fbits>>12)&1, (fbits&0xFFF)!=0);
+ if(fbits >= 0x33000000)
+ {
+ int i = 125 - (fbits>>23);
+ fbits = (fbits&0x7FFFFF) | 0x800000;
+ return rounded<R,false>(sign|(fbits>>(i+1)), (fbits>>i)&1, (fbits&((static_cast<uint32>(1)<<i)-1))!=0);
+ }
+ if(fbits != 0)
+ return underflow<R>(sign);
+ return sign;
+ #else
+ static const uint16 base_table[512] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100,
+ 0x0200, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00,
+ 0x4000, 0x4400, 0x4800, 0x4C00, 0x5000, 0x5400, 0x5800, 0x5C00, 0x6000, 0x6400, 0x6800, 0x6C00, 0x7000, 0x7400, 0x7800, 0x7BFF,
+ 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF,
+ 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF,
+ 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF,
+ 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF,
+ 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF,
+ 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF,
+ 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7C00,
+ 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+ 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+ 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+ 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+ 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+ 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+ 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, 0x8002, 0x8004, 0x8008, 0x8010, 0x8020, 0x8040, 0x8080, 0x8100,
+ 0x8200, 0x8400, 0x8800, 0x8C00, 0x9000, 0x9400, 0x9800, 0x9C00, 0xA000, 0xA400, 0xA800, 0xAC00, 0xB000, 0xB400, 0xB800, 0xBC00,
+ 0xC000, 0xC400, 0xC800, 0xCC00, 0xD000, 0xD400, 0xD800, 0xDC00, 0xE000, 0xE400, 0xE800, 0xEC00, 0xF000, 0xF400, 0xF800, 0xFBFF,
+ 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF,
+ 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF,
+ 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF,
+ 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF,
+ 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF,
+ 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF,
+ 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFC00 };
+ static const unsigned char shift_table[256] = {
+ 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 13 };
+ int sexp = fbits >> 23, exp = sexp & 0xFF, i = shift_table[exp];
+ fbits &= 0x7FFFFF;
+ uint32 m = (fbits|((exp!=0)<<23)) & -static_cast<uint32>(exp!=0xFF);
+ return rounded<R,false>(base_table[sexp]+(fbits>>i), (m>>(i-1))&1, (((static_cast<uint32>(1)<<(i-1))-1)&m)!=0);
+ #endif
+ #endif
+ }
+
+ /// Convert IEEE double-precision to half-precision.
+ /// \tparam R rounding mode to use
+ /// \param value double-precision value to convert
+ /// \return rounded half-precision value
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if value had to be rounded
+ template<std::float_round_style R> unsigned int float2half_impl(double value, true_type)
+ {
+ #if HALF_ENABLE_F16C_INTRINSICS
+ if(R == std::round_indeterminate)
+ return _mm_cvtsi128_si32(_mm_cvtps_ph(_mm_cvtpd_ps(_mm_set_sd(value)), _MM_FROUND_CUR_DIRECTION));
+ #endif
+ bits<double>::type dbits;
+ std::memcpy(&dbits, &value, sizeof(double));
+ uint32 hi = dbits >> 32, lo = dbits & 0xFFFFFFFF;
+ unsigned int sign = (hi>>16) & 0x8000;
+ hi &= 0x7FFFFFFF;
+ if(hi >= 0x7FF00000)
+ return sign | 0x7C00 | ((dbits&0xFFFFFFFFFFFFF) ? (0x200|((hi>>10)&0x3FF)) : 0);
+ if(hi >= 0x40F00000)
+ return overflow<R>(sign);
+ if(hi >= 0x3F100000)
+ return rounded<R,false>(sign|(((hi>>20)-1008)<<10)|((hi>>10)&0x3FF), (hi>>9)&1, ((hi&0x1FF)|lo)!=0);
+ if(hi >= 0x3E600000)
+ {
+ int i = 1018 - (hi>>20);
+ hi = (hi&0xFFFFF) | 0x100000;
+ return rounded<R,false>(sign|(hi>>(i+1)), (hi>>i)&1, ((hi&((static_cast<uint32>(1)<<i)-1))|lo)!=0);
+ }
+ if((hi|lo) != 0)
+ return underflow<R>(sign);
+ return sign;
+ }
+
+ /// Convert non-IEEE floating-point to half-precision.
+ /// \tparam R rounding mode to use
+ /// \tparam T source type (builtin floating-point type)
+ /// \param value floating-point value to convert
+ /// \return rounded half-precision value
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if value had to be rounded
+ template<std::float_round_style R,typename T> unsigned int float2half_impl(T value, ...)
+ {
+ unsigned int hbits = static_cast<unsigned>(builtin_signbit(value)) << 15;
+ if(value == T())
+ return hbits;
+ if(builtin_isnan(value))
+ return hbits | 0x7FFF;
+ if(builtin_isinf(value))
+ return hbits | 0x7C00;
+ int exp;
+ std::frexp(value, &exp);
+ if(exp > 16)
+ return overflow<R>(hbits);
+ if(exp < -13)
+ value = std::ldexp(value, 25);
+ else
+ {
+ value = std::ldexp(value, 12-exp);
+ hbits |= ((exp+13)<<10);
+ }
+ T ival, frac = std::modf(value, &ival);
+ int m = std::abs(static_cast<int>(ival));
+ return rounded<R,false>(hbits+(m>>1), m&1, frac!=T());
+ }
+
+ /// Convert floating-point to half-precision.
+ /// \tparam R rounding mode to use
+ /// \tparam T source type (builtin floating-point type)
+ /// \param value floating-point value to convert
+ /// \return rounded half-precision value
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if value had to be rounded
+ template<std::float_round_style R,typename T> unsigned int float2half(T value)
+ {
+ return float2half_impl<R>(value, bool_type<std::numeric_limits<T>::is_iec559&&sizeof(typename bits<T>::type)==sizeof(T)>());
+ }
+
+ /// Convert integer to half-precision floating-point.
+ /// \tparam R rounding mode to use
+ /// \tparam T type to convert (builtin integer type)
+ /// \param value integral value to convert
+ /// \return rounded half-precision value
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_INEXACT if value had to be rounded
+ template<std::float_round_style R,typename T> unsigned int int2half(T value)
+ {
+ unsigned int bits = static_cast<unsigned>(value<0) << 15;
+ if(!value)
+ return bits;
+ if(bits)
+ value = -value;
+ if(value > 0xFFFF)
+ return overflow<R>(bits);
+ unsigned int m = static_cast<unsigned int>(value), exp = 24;
+ for(; m<0x400; m<<=1,--exp) ;
+ for(; m>0x7FF; m>>=1,++exp) ;
+ bits |= (exp<<10) + m;
+ return (exp>24) ? rounded<R,false>(bits, (value>>(exp-25))&1, (((1<<(exp-25))-1)&value)!=0) : bits;
+ }
+
+ /// Convert half-precision to IEEE single-precision.
+ /// Credit for this goes to [Jeroen van der Zijp](ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf).
+ /// \param value half-precision value to convert
+ /// \return single-precision value
+ inline float half2float_impl(unsigned int value, float, true_type)
+ {
+ #if HALF_ENABLE_F16C_INTRINSICS
+ return _mm_cvtss_f32(_mm_cvtph_ps(_mm_cvtsi32_si128(value)));
+ #else
+ #if 0
+ bits<float>::type fbits = static_cast<bits<float>::type>(value&0x8000) << 16;
+ int abs = value & 0x7FFF;
+ if(abs)
+ {
+ fbits |= 0x38000000 << static_cast<unsigned>(abs>=0x7C00);
+ for(; abs<0x400; abs<<=1,fbits-=0x800000) ;
+ fbits += static_cast<bits<float>::type>(abs) << 13;
+ }
+ #else
+ static const bits<float>::type mantissa_table[2048] = {
+ 0x00000000, 0x33800000, 0x34000000, 0x34400000, 0x34800000, 0x34A00000, 0x34C00000, 0x34E00000, 0x35000000, 0x35100000, 0x35200000, 0x35300000, 0x35400000, 0x35500000, 0x35600000, 0x35700000,
+ 0x35800000, 0x35880000, 0x35900000, 0x35980000, 0x35A00000, 0x35A80000, 0x35B00000, 0x35B80000, 0x35C00000, 0x35C80000, 0x35D00000, 0x35D80000, 0x35E00000, 0x35E80000, 0x35F00000, 0x35F80000,
+ 0x36000000, 0x36040000, 0x36080000, 0x360C0000, 0x36100000, 0x36140000, 0x36180000, 0x361C0000, 0x36200000, 0x36240000, 0x36280000, 0x362C0000, 0x36300000, 0x36340000, 0x36380000, 0x363C0000,
+ 0x36400000, 0x36440000, 0x36480000, 0x364C0000, 0x36500000, 0x36540000, 0x36580000, 0x365C0000, 0x36600000, 0x36640000, 0x36680000, 0x366C0000, 0x36700000, 0x36740000, 0x36780000, 0x367C0000,
+ 0x36800000, 0x36820000, 0x36840000, 0x36860000, 0x36880000, 0x368A0000, 0x368C0000, 0x368E0000, 0x36900000, 0x36920000, 0x36940000, 0x36960000, 0x36980000, 0x369A0000, 0x369C0000, 0x369E0000,
+ 0x36A00000, 0x36A20000, 0x36A40000, 0x36A60000, 0x36A80000, 0x36AA0000, 0x36AC0000, 0x36AE0000, 0x36B00000, 0x36B20000, 0x36B40000, 0x36B60000, 0x36B80000, 0x36BA0000, 0x36BC0000, 0x36BE0000,
+ 0x36C00000, 0x36C20000, 0x36C40000, 0x36C60000, 0x36C80000, 0x36CA0000, 0x36CC0000, 0x36CE0000, 0x36D00000, 0x36D20000, 0x36D40000, 0x36D60000, 0x36D80000, 0x36DA0000, 0x36DC0000, 0x36DE0000,
+ 0x36E00000, 0x36E20000, 0x36E40000, 0x36E60000, 0x36E80000, 0x36EA0000, 0x36EC0000, 0x36EE0000, 0x36F00000, 0x36F20000, 0x36F40000, 0x36F60000, 0x36F80000, 0x36FA0000, 0x36FC0000, 0x36FE0000,
+ 0x37000000, 0x37010000, 0x37020000, 0x37030000, 0x37040000, 0x37050000, 0x37060000, 0x37070000, 0x37080000, 0x37090000, 0x370A0000, 0x370B0000, 0x370C0000, 0x370D0000, 0x370E0000, 0x370F0000,
+ 0x37100000, 0x37110000, 0x37120000, 0x37130000, 0x37140000, 0x37150000, 0x37160000, 0x37170000, 0x37180000, 0x37190000, 0x371A0000, 0x371B0000, 0x371C0000, 0x371D0000, 0x371E0000, 0x371F0000,
+ 0x37200000, 0x37210000, 0x37220000, 0x37230000, 0x37240000, 0x37250000, 0x37260000, 0x37270000, 0x37280000, 0x37290000, 0x372A0000, 0x372B0000, 0x372C0000, 0x372D0000, 0x372E0000, 0x372F0000,
+ 0x37300000, 0x37310000, 0x37320000, 0x37330000, 0x37340000, 0x37350000, 0x37360000, 0x37370000, 0x37380000, 0x37390000, 0x373A0000, 0x373B0000, 0x373C0000, 0x373D0000, 0x373E0000, 0x373F0000,
+ 0x37400000, 0x37410000, 0x37420000, 0x37430000, 0x37440000, 0x37450000, 0x37460000, 0x37470000, 0x37480000, 0x37490000, 0x374A0000, 0x374B0000, 0x374C0000, 0x374D0000, 0x374E0000, 0x374F0000,
+ 0x37500000, 0x37510000, 0x37520000, 0x37530000, 0x37540000, 0x37550000, 0x37560000, 0x37570000, 0x37580000, 0x37590000, 0x375A0000, 0x375B0000, 0x375C0000, 0x375D0000, 0x375E0000, 0x375F0000,
+ 0x37600000, 0x37610000, 0x37620000, 0x37630000, 0x37640000, 0x37650000, 0x37660000, 0x37670000, 0x37680000, 0x37690000, 0x376A0000, 0x376B0000, 0x376C0000, 0x376D0000, 0x376E0000, 0x376F0000,
+ 0x37700000, 0x37710000, 0x37720000, 0x37730000, 0x37740000, 0x37750000, 0x37760000, 0x37770000, 0x37780000, 0x37790000, 0x377A0000, 0x377B0000, 0x377C0000, 0x377D0000, 0x377E0000, 0x377F0000,
+ 0x37800000, 0x37808000, 0x37810000, 0x37818000, 0x37820000, 0x37828000, 0x37830000, 0x37838000, 0x37840000, 0x37848000, 0x37850000, 0x37858000, 0x37860000, 0x37868000, 0x37870000, 0x37878000,
+ 0x37880000, 0x37888000, 0x37890000, 0x37898000, 0x378A0000, 0x378A8000, 0x378B0000, 0x378B8000, 0x378C0000, 0x378C8000, 0x378D0000, 0x378D8000, 0x378E0000, 0x378E8000, 0x378F0000, 0x378F8000,
+ 0x37900000, 0x37908000, 0x37910000, 0x37918000, 0x37920000, 0x37928000, 0x37930000, 0x37938000, 0x37940000, 0x37948000, 0x37950000, 0x37958000, 0x37960000, 0x37968000, 0x37970000, 0x37978000,
+ 0x37980000, 0x37988000, 0x37990000, 0x37998000, 0x379A0000, 0x379A8000, 0x379B0000, 0x379B8000, 0x379C0000, 0x379C8000, 0x379D0000, 0x379D8000, 0x379E0000, 0x379E8000, 0x379F0000, 0x379F8000,
+ 0x37A00000, 0x37A08000, 0x37A10000, 0x37A18000, 0x37A20000, 0x37A28000, 0x37A30000, 0x37A38000, 0x37A40000, 0x37A48000, 0x37A50000, 0x37A58000, 0x37A60000, 0x37A68000, 0x37A70000, 0x37A78000,
+ 0x37A80000, 0x37A88000, 0x37A90000, 0x37A98000, 0x37AA0000, 0x37AA8000, 0x37AB0000, 0x37AB8000, 0x37AC0000, 0x37AC8000, 0x37AD0000, 0x37AD8000, 0x37AE0000, 0x37AE8000, 0x37AF0000, 0x37AF8000,
+ 0x37B00000, 0x37B08000, 0x37B10000, 0x37B18000, 0x37B20000, 0x37B28000, 0x37B30000, 0x37B38000, 0x37B40000, 0x37B48000, 0x37B50000, 0x37B58000, 0x37B60000, 0x37B68000, 0x37B70000, 0x37B78000,
+ 0x37B80000, 0x37B88000, 0x37B90000, 0x37B98000, 0x37BA0000, 0x37BA8000, 0x37BB0000, 0x37BB8000, 0x37BC0000, 0x37BC8000, 0x37BD0000, 0x37BD8000, 0x37BE0000, 0x37BE8000, 0x37BF0000, 0x37BF8000,
+ 0x37C00000, 0x37C08000, 0x37C10000, 0x37C18000, 0x37C20000, 0x37C28000, 0x37C30000, 0x37C38000, 0x37C40000, 0x37C48000, 0x37C50000, 0x37C58000, 0x37C60000, 0x37C68000, 0x37C70000, 0x37C78000,
+ 0x37C80000, 0x37C88000, 0x37C90000, 0x37C98000, 0x37CA0000, 0x37CA8000, 0x37CB0000, 0x37CB8000, 0x37CC0000, 0x37CC8000, 0x37CD0000, 0x37CD8000, 0x37CE0000, 0x37CE8000, 0x37CF0000, 0x37CF8000,
+ 0x37D00000, 0x37D08000, 0x37D10000, 0x37D18000, 0x37D20000, 0x37D28000, 0x37D30000, 0x37D38000, 0x37D40000, 0x37D48000, 0x37D50000, 0x37D58000, 0x37D60000, 0x37D68000, 0x37D70000, 0x37D78000,
+ 0x37D80000, 0x37D88000, 0x37D90000, 0x37D98000, 0x37DA0000, 0x37DA8000, 0x37DB0000, 0x37DB8000, 0x37DC0000, 0x37DC8000, 0x37DD0000, 0x37DD8000, 0x37DE0000, 0x37DE8000, 0x37DF0000, 0x37DF8000,
+ 0x37E00000, 0x37E08000, 0x37E10000, 0x37E18000, 0x37E20000, 0x37E28000, 0x37E30000, 0x37E38000, 0x37E40000, 0x37E48000, 0x37E50000, 0x37E58000, 0x37E60000, 0x37E68000, 0x37E70000, 0x37E78000,
+ 0x37E80000, 0x37E88000, 0x37E90000, 0x37E98000, 0x37EA0000, 0x37EA8000, 0x37EB0000, 0x37EB8000, 0x37EC0000, 0x37EC8000, 0x37ED0000, 0x37ED8000, 0x37EE0000, 0x37EE8000, 0x37EF0000, 0x37EF8000,
+ 0x37F00000, 0x37F08000, 0x37F10000, 0x37F18000, 0x37F20000, 0x37F28000, 0x37F30000, 0x37F38000, 0x37F40000, 0x37F48000, 0x37F50000, 0x37F58000, 0x37F60000, 0x37F68000, 0x37F70000, 0x37F78000,
+ 0x37F80000, 0x37F88000, 0x37F90000, 0x37F98000, 0x37FA0000, 0x37FA8000, 0x37FB0000, 0x37FB8000, 0x37FC0000, 0x37FC8000, 0x37FD0000, 0x37FD8000, 0x37FE0000, 0x37FE8000, 0x37FF0000, 0x37FF8000,
+ 0x38000000, 0x38004000, 0x38008000, 0x3800C000, 0x38010000, 0x38014000, 0x38018000, 0x3801C000, 0x38020000, 0x38024000, 0x38028000, 0x3802C000, 0x38030000, 0x38034000, 0x38038000, 0x3803C000,
+ 0x38040000, 0x38044000, 0x38048000, 0x3804C000, 0x38050000, 0x38054000, 0x38058000, 0x3805C000, 0x38060000, 0x38064000, 0x38068000, 0x3806C000, 0x38070000, 0x38074000, 0x38078000, 0x3807C000,
+ 0x38080000, 0x38084000, 0x38088000, 0x3808C000, 0x38090000, 0x38094000, 0x38098000, 0x3809C000, 0x380A0000, 0x380A4000, 0x380A8000, 0x380AC000, 0x380B0000, 0x380B4000, 0x380B8000, 0x380BC000,
+ 0x380C0000, 0x380C4000, 0x380C8000, 0x380CC000, 0x380D0000, 0x380D4000, 0x380D8000, 0x380DC000, 0x380E0000, 0x380E4000, 0x380E8000, 0x380EC000, 0x380F0000, 0x380F4000, 0x380F8000, 0x380FC000,
+ 0x38100000, 0x38104000, 0x38108000, 0x3810C000, 0x38110000, 0x38114000, 0x38118000, 0x3811C000, 0x38120000, 0x38124000, 0x38128000, 0x3812C000, 0x38130000, 0x38134000, 0x38138000, 0x3813C000,
+ 0x38140000, 0x38144000, 0x38148000, 0x3814C000, 0x38150000, 0x38154000, 0x38158000, 0x3815C000, 0x38160000, 0x38164000, 0x38168000, 0x3816C000, 0x38170000, 0x38174000, 0x38178000, 0x3817C000,
+ 0x38180000, 0x38184000, 0x38188000, 0x3818C000, 0x38190000, 0x38194000, 0x38198000, 0x3819C000, 0x381A0000, 0x381A4000, 0x381A8000, 0x381AC000, 0x381B0000, 0x381B4000, 0x381B8000, 0x381BC000,
+ 0x381C0000, 0x381C4000, 0x381C8000, 0x381CC000, 0x381D0000, 0x381D4000, 0x381D8000, 0x381DC000, 0x381E0000, 0x381E4000, 0x381E8000, 0x381EC000, 0x381F0000, 0x381F4000, 0x381F8000, 0x381FC000,
+ 0x38200000, 0x38204000, 0x38208000, 0x3820C000, 0x38210000, 0x38214000, 0x38218000, 0x3821C000, 0x38220000, 0x38224000, 0x38228000, 0x3822C000, 0x38230000, 0x38234000, 0x38238000, 0x3823C000,
+ 0x38240000, 0x38244000, 0x38248000, 0x3824C000, 0x38250000, 0x38254000, 0x38258000, 0x3825C000, 0x38260000, 0x38264000, 0x38268000, 0x3826C000, 0x38270000, 0x38274000, 0x38278000, 0x3827C000,
+ 0x38280000, 0x38284000, 0x38288000, 0x3828C000, 0x38290000, 0x38294000, 0x38298000, 0x3829C000, 0x382A0000, 0x382A4000, 0x382A8000, 0x382AC000, 0x382B0000, 0x382B4000, 0x382B8000, 0x382BC000,
+ 0x382C0000, 0x382C4000, 0x382C8000, 0x382CC000, 0x382D0000, 0x382D4000, 0x382D8000, 0x382DC000, 0x382E0000, 0x382E4000, 0x382E8000, 0x382EC000, 0x382F0000, 0x382F4000, 0x382F8000, 0x382FC000,
+ 0x38300000, 0x38304000, 0x38308000, 0x3830C000, 0x38310000, 0x38314000, 0x38318000, 0x3831C000, 0x38320000, 0x38324000, 0x38328000, 0x3832C000, 0x38330000, 0x38334000, 0x38338000, 0x3833C000,
+ 0x38340000, 0x38344000, 0x38348000, 0x3834C000, 0x38350000, 0x38354000, 0x38358000, 0x3835C000, 0x38360000, 0x38364000, 0x38368000, 0x3836C000, 0x38370000, 0x38374000, 0x38378000, 0x3837C000,
+ 0x38380000, 0x38384000, 0x38388000, 0x3838C000, 0x38390000, 0x38394000, 0x38398000, 0x3839C000, 0x383A0000, 0x383A4000, 0x383A8000, 0x383AC000, 0x383B0000, 0x383B4000, 0x383B8000, 0x383BC000,
+ 0x383C0000, 0x383C4000, 0x383C8000, 0x383CC000, 0x383D0000, 0x383D4000, 0x383D8000, 0x383DC000, 0x383E0000, 0x383E4000, 0x383E8000, 0x383EC000, 0x383F0000, 0x383F4000, 0x383F8000, 0x383FC000,
+ 0x38400000, 0x38404000, 0x38408000, 0x3840C000, 0x38410000, 0x38414000, 0x38418000, 0x3841C000, 0x38420000, 0x38424000, 0x38428000, 0x3842C000, 0x38430000, 0x38434000, 0x38438000, 0x3843C000,
+ 0x38440000, 0x38444000, 0x38448000, 0x3844C000, 0x38450000, 0x38454000, 0x38458000, 0x3845C000, 0x38460000, 0x38464000, 0x38468000, 0x3846C000, 0x38470000, 0x38474000, 0x38478000, 0x3847C000,
+ 0x38480000, 0x38484000, 0x38488000, 0x3848C000, 0x38490000, 0x38494000, 0x38498000, 0x3849C000, 0x384A0000, 0x384A4000, 0x384A8000, 0x384AC000, 0x384B0000, 0x384B4000, 0x384B8000, 0x384BC000,
+ 0x384C0000, 0x384C4000, 0x384C8000, 0x384CC000, 0x384D0000, 0x384D4000, 0x384D8000, 0x384DC000, 0x384E0000, 0x384E4000, 0x384E8000, 0x384EC000, 0x384F0000, 0x384F4000, 0x384F8000, 0x384FC000,
+ 0x38500000, 0x38504000, 0x38508000, 0x3850C000, 0x38510000, 0x38514000, 0x38518000, 0x3851C000, 0x38520000, 0x38524000, 0x38528000, 0x3852C000, 0x38530000, 0x38534000, 0x38538000, 0x3853C000,
+ 0x38540000, 0x38544000, 0x38548000, 0x3854C000, 0x38550000, 0x38554000, 0x38558000, 0x3855C000, 0x38560000, 0x38564000, 0x38568000, 0x3856C000, 0x38570000, 0x38574000, 0x38578000, 0x3857C000,
+ 0x38580000, 0x38584000, 0x38588000, 0x3858C000, 0x38590000, 0x38594000, 0x38598000, 0x3859C000, 0x385A0000, 0x385A4000, 0x385A8000, 0x385AC000, 0x385B0000, 0x385B4000, 0x385B8000, 0x385BC000,
+ 0x385C0000, 0x385C4000, 0x385C8000, 0x385CC000, 0x385D0000, 0x385D4000, 0x385D8000, 0x385DC000, 0x385E0000, 0x385E4000, 0x385E8000, 0x385EC000, 0x385F0000, 0x385F4000, 0x385F8000, 0x385FC000,
+ 0x38600000, 0x38604000, 0x38608000, 0x3860C000, 0x38610000, 0x38614000, 0x38618000, 0x3861C000, 0x38620000, 0x38624000, 0x38628000, 0x3862C000, 0x38630000, 0x38634000, 0x38638000, 0x3863C000,
+ 0x38640000, 0x38644000, 0x38648000, 0x3864C000, 0x38650000, 0x38654000, 0x38658000, 0x3865C000, 0x38660000, 0x38664000, 0x38668000, 0x3866C000, 0x38670000, 0x38674000, 0x38678000, 0x3867C000,
+ 0x38680000, 0x38684000, 0x38688000, 0x3868C000, 0x38690000, 0x38694000, 0x38698000, 0x3869C000, 0x386A0000, 0x386A4000, 0x386A8000, 0x386AC000, 0x386B0000, 0x386B4000, 0x386B8000, 0x386BC000,
+ 0x386C0000, 0x386C4000, 0x386C8000, 0x386CC000, 0x386D0000, 0x386D4000, 0x386D8000, 0x386DC000, 0x386E0000, 0x386E4000, 0x386E8000, 0x386EC000, 0x386F0000, 0x386F4000, 0x386F8000, 0x386FC000,
+ 0x38700000, 0x38704000, 0x38708000, 0x3870C000, 0x38710000, 0x38714000, 0x38718000, 0x3871C000, 0x38720000, 0x38724000, 0x38728000, 0x3872C000, 0x38730000, 0x38734000, 0x38738000, 0x3873C000,
+ 0x38740000, 0x38744000, 0x38748000, 0x3874C000, 0x38750000, 0x38754000, 0x38758000, 0x3875C000, 0x38760000, 0x38764000, 0x38768000, 0x3876C000, 0x38770000, 0x38774000, 0x38778000, 0x3877C000,
+ 0x38780000, 0x38784000, 0x38788000, 0x3878C000, 0x38790000, 0x38794000, 0x38798000, 0x3879C000, 0x387A0000, 0x387A4000, 0x387A8000, 0x387AC000, 0x387B0000, 0x387B4000, 0x387B8000, 0x387BC000,
+ 0x387C0000, 0x387C4000, 0x387C8000, 0x387CC000, 0x387D0000, 0x387D4000, 0x387D8000, 0x387DC000, 0x387E0000, 0x387E4000, 0x387E8000, 0x387EC000, 0x387F0000, 0x387F4000, 0x387F8000, 0x387FC000,
+ 0x38000000, 0x38002000, 0x38004000, 0x38006000, 0x38008000, 0x3800A000, 0x3800C000, 0x3800E000, 0x38010000, 0x38012000, 0x38014000, 0x38016000, 0x38018000, 0x3801A000, 0x3801C000, 0x3801E000,
+ 0x38020000, 0x38022000, 0x38024000, 0x38026000, 0x38028000, 0x3802A000, 0x3802C000, 0x3802E000, 0x38030000, 0x38032000, 0x38034000, 0x38036000, 0x38038000, 0x3803A000, 0x3803C000, 0x3803E000,
+ 0x38040000, 0x38042000, 0x38044000, 0x38046000, 0x38048000, 0x3804A000, 0x3804C000, 0x3804E000, 0x38050000, 0x38052000, 0x38054000, 0x38056000, 0x38058000, 0x3805A000, 0x3805C000, 0x3805E000,
+ 0x38060000, 0x38062000, 0x38064000, 0x38066000, 0x38068000, 0x3806A000, 0x3806C000, 0x3806E000, 0x38070000, 0x38072000, 0x38074000, 0x38076000, 0x38078000, 0x3807A000, 0x3807C000, 0x3807E000,
+ 0x38080000, 0x38082000, 0x38084000, 0x38086000, 0x38088000, 0x3808A000, 0x3808C000, 0x3808E000, 0x38090000, 0x38092000, 0x38094000, 0x38096000, 0x38098000, 0x3809A000, 0x3809C000, 0x3809E000,
+ 0x380A0000, 0x380A2000, 0x380A4000, 0x380A6000, 0x380A8000, 0x380AA000, 0x380AC000, 0x380AE000, 0x380B0000, 0x380B2000, 0x380B4000, 0x380B6000, 0x380B8000, 0x380BA000, 0x380BC000, 0x380BE000,
+ 0x380C0000, 0x380C2000, 0x380C4000, 0x380C6000, 0x380C8000, 0x380CA000, 0x380CC000, 0x380CE000, 0x380D0000, 0x380D2000, 0x380D4000, 0x380D6000, 0x380D8000, 0x380DA000, 0x380DC000, 0x380DE000,
+ 0x380E0000, 0x380E2000, 0x380E4000, 0x380E6000, 0x380E8000, 0x380EA000, 0x380EC000, 0x380EE000, 0x380F0000, 0x380F2000, 0x380F4000, 0x380F6000, 0x380F8000, 0x380FA000, 0x380FC000, 0x380FE000,
+ 0x38100000, 0x38102000, 0x38104000, 0x38106000, 0x38108000, 0x3810A000, 0x3810C000, 0x3810E000, 0x38110000, 0x38112000, 0x38114000, 0x38116000, 0x38118000, 0x3811A000, 0x3811C000, 0x3811E000,
+ 0x38120000, 0x38122000, 0x38124000, 0x38126000, 0x38128000, 0x3812A000, 0x3812C000, 0x3812E000, 0x38130000, 0x38132000, 0x38134000, 0x38136000, 0x38138000, 0x3813A000, 0x3813C000, 0x3813E000,
+ 0x38140000, 0x38142000, 0x38144000, 0x38146000, 0x38148000, 0x3814A000, 0x3814C000, 0x3814E000, 0x38150000, 0x38152000, 0x38154000, 0x38156000, 0x38158000, 0x3815A000, 0x3815C000, 0x3815E000,
+ 0x38160000, 0x38162000, 0x38164000, 0x38166000, 0x38168000, 0x3816A000, 0x3816C000, 0x3816E000, 0x38170000, 0x38172000, 0x38174000, 0x38176000, 0x38178000, 0x3817A000, 0x3817C000, 0x3817E000,
+ 0x38180000, 0x38182000, 0x38184000, 0x38186000, 0x38188000, 0x3818A000, 0x3818C000, 0x3818E000, 0x38190000, 0x38192000, 0x38194000, 0x38196000, 0x38198000, 0x3819A000, 0x3819C000, 0x3819E000,
+ 0x381A0000, 0x381A2000, 0x381A4000, 0x381A6000, 0x381A8000, 0x381AA000, 0x381AC000, 0x381AE000, 0x381B0000, 0x381B2000, 0x381B4000, 0x381B6000, 0x381B8000, 0x381BA000, 0x381BC000, 0x381BE000,
+ 0x381C0000, 0x381C2000, 0x381C4000, 0x381C6000, 0x381C8000, 0x381CA000, 0x381CC000, 0x381CE000, 0x381D0000, 0x381D2000, 0x381D4000, 0x381D6000, 0x381D8000, 0x381DA000, 0x381DC000, 0x381DE000,
+ 0x381E0000, 0x381E2000, 0x381E4000, 0x381E6000, 0x381E8000, 0x381EA000, 0x381EC000, 0x381EE000, 0x381F0000, 0x381F2000, 0x381F4000, 0x381F6000, 0x381F8000, 0x381FA000, 0x381FC000, 0x381FE000,
+ 0x38200000, 0x38202000, 0x38204000, 0x38206000, 0x38208000, 0x3820A000, 0x3820C000, 0x3820E000, 0x38210000, 0x38212000, 0x38214000, 0x38216000, 0x38218000, 0x3821A000, 0x3821C000, 0x3821E000,
+ 0x38220000, 0x38222000, 0x38224000, 0x38226000, 0x38228000, 0x3822A000, 0x3822C000, 0x3822E000, 0x38230000, 0x38232000, 0x38234000, 0x38236000, 0x38238000, 0x3823A000, 0x3823C000, 0x3823E000,
+ 0x38240000, 0x38242000, 0x38244000, 0x38246000, 0x38248000, 0x3824A000, 0x3824C000, 0x3824E000, 0x38250000, 0x38252000, 0x38254000, 0x38256000, 0x38258000, 0x3825A000, 0x3825C000, 0x3825E000,
+ 0x38260000, 0x38262000, 0x38264000, 0x38266000, 0x38268000, 0x3826A000, 0x3826C000, 0x3826E000, 0x38270000, 0x38272000, 0x38274000, 0x38276000, 0x38278000, 0x3827A000, 0x3827C000, 0x3827E000,
+ 0x38280000, 0x38282000, 0x38284000, 0x38286000, 0x38288000, 0x3828A000, 0x3828C000, 0x3828E000, 0x38290000, 0x38292000, 0x38294000, 0x38296000, 0x38298000, 0x3829A000, 0x3829C000, 0x3829E000,
+ 0x382A0000, 0x382A2000, 0x382A4000, 0x382A6000, 0x382A8000, 0x382AA000, 0x382AC000, 0x382AE000, 0x382B0000, 0x382B2000, 0x382B4000, 0x382B6000, 0x382B8000, 0x382BA000, 0x382BC000, 0x382BE000,
+ 0x382C0000, 0x382C2000, 0x382C4000, 0x382C6000, 0x382C8000, 0x382CA000, 0x382CC000, 0x382CE000, 0x382D0000, 0x382D2000, 0x382D4000, 0x382D6000, 0x382D8000, 0x382DA000, 0x382DC000, 0x382DE000,
+ 0x382E0000, 0x382E2000, 0x382E4000, 0x382E6000, 0x382E8000, 0x382EA000, 0x382EC000, 0x382EE000, 0x382F0000, 0x382F2000, 0x382F4000, 0x382F6000, 0x382F8000, 0x382FA000, 0x382FC000, 0x382FE000,
+ 0x38300000, 0x38302000, 0x38304000, 0x38306000, 0x38308000, 0x3830A000, 0x3830C000, 0x3830E000, 0x38310000, 0x38312000, 0x38314000, 0x38316000, 0x38318000, 0x3831A000, 0x3831C000, 0x3831E000,
+ 0x38320000, 0x38322000, 0x38324000, 0x38326000, 0x38328000, 0x3832A000, 0x3832C000, 0x3832E000, 0x38330000, 0x38332000, 0x38334000, 0x38336000, 0x38338000, 0x3833A000, 0x3833C000, 0x3833E000,
+ 0x38340000, 0x38342000, 0x38344000, 0x38346000, 0x38348000, 0x3834A000, 0x3834C000, 0x3834E000, 0x38350000, 0x38352000, 0x38354000, 0x38356000, 0x38358000, 0x3835A000, 0x3835C000, 0x3835E000,
+ 0x38360000, 0x38362000, 0x38364000, 0x38366000, 0x38368000, 0x3836A000, 0x3836C000, 0x3836E000, 0x38370000, 0x38372000, 0x38374000, 0x38376000, 0x38378000, 0x3837A000, 0x3837C000, 0x3837E000,
+ 0x38380000, 0x38382000, 0x38384000, 0x38386000, 0x38388000, 0x3838A000, 0x3838C000, 0x3838E000, 0x38390000, 0x38392000, 0x38394000, 0x38396000, 0x38398000, 0x3839A000, 0x3839C000, 0x3839E000,
+ 0x383A0000, 0x383A2000, 0x383A4000, 0x383A6000, 0x383A8000, 0x383AA000, 0x383AC000, 0x383AE000, 0x383B0000, 0x383B2000, 0x383B4000, 0x383B6000, 0x383B8000, 0x383BA000, 0x383BC000, 0x383BE000,
+ 0x383C0000, 0x383C2000, 0x383C4000, 0x383C6000, 0x383C8000, 0x383CA000, 0x383CC000, 0x383CE000, 0x383D0000, 0x383D2000, 0x383D4000, 0x383D6000, 0x383D8000, 0x383DA000, 0x383DC000, 0x383DE000,
+ 0x383E0000, 0x383E2000, 0x383E4000, 0x383E6000, 0x383E8000, 0x383EA000, 0x383EC000, 0x383EE000, 0x383F0000, 0x383F2000, 0x383F4000, 0x383F6000, 0x383F8000, 0x383FA000, 0x383FC000, 0x383FE000,
+ 0x38400000, 0x38402000, 0x38404000, 0x38406000, 0x38408000, 0x3840A000, 0x3840C000, 0x3840E000, 0x38410000, 0x38412000, 0x38414000, 0x38416000, 0x38418000, 0x3841A000, 0x3841C000, 0x3841E000,
+ 0x38420000, 0x38422000, 0x38424000, 0x38426000, 0x38428000, 0x3842A000, 0x3842C000, 0x3842E000, 0x38430000, 0x38432000, 0x38434000, 0x38436000, 0x38438000, 0x3843A000, 0x3843C000, 0x3843E000,
+ 0x38440000, 0x38442000, 0x38444000, 0x38446000, 0x38448000, 0x3844A000, 0x3844C000, 0x3844E000, 0x38450000, 0x38452000, 0x38454000, 0x38456000, 0x38458000, 0x3845A000, 0x3845C000, 0x3845E000,
+ 0x38460000, 0x38462000, 0x38464000, 0x38466000, 0x38468000, 0x3846A000, 0x3846C000, 0x3846E000, 0x38470000, 0x38472000, 0x38474000, 0x38476000, 0x38478000, 0x3847A000, 0x3847C000, 0x3847E000,
+ 0x38480000, 0x38482000, 0x38484000, 0x38486000, 0x38488000, 0x3848A000, 0x3848C000, 0x3848E000, 0x38490000, 0x38492000, 0x38494000, 0x38496000, 0x38498000, 0x3849A000, 0x3849C000, 0x3849E000,
+ 0x384A0000, 0x384A2000, 0x384A4000, 0x384A6000, 0x384A8000, 0x384AA000, 0x384AC000, 0x384AE000, 0x384B0000, 0x384B2000, 0x384B4000, 0x384B6000, 0x384B8000, 0x384BA000, 0x384BC000, 0x384BE000,
+ 0x384C0000, 0x384C2000, 0x384C4000, 0x384C6000, 0x384C8000, 0x384CA000, 0x384CC000, 0x384CE000, 0x384D0000, 0x384D2000, 0x384D4000, 0x384D6000, 0x384D8000, 0x384DA000, 0x384DC000, 0x384DE000,
+ 0x384E0000, 0x384E2000, 0x384E4000, 0x384E6000, 0x384E8000, 0x384EA000, 0x384EC000, 0x384EE000, 0x384F0000, 0x384F2000, 0x384F4000, 0x384F6000, 0x384F8000, 0x384FA000, 0x384FC000, 0x384FE000,
+ 0x38500000, 0x38502000, 0x38504000, 0x38506000, 0x38508000, 0x3850A000, 0x3850C000, 0x3850E000, 0x38510000, 0x38512000, 0x38514000, 0x38516000, 0x38518000, 0x3851A000, 0x3851C000, 0x3851E000,
+ 0x38520000, 0x38522000, 0x38524000, 0x38526000, 0x38528000, 0x3852A000, 0x3852C000, 0x3852E000, 0x38530000, 0x38532000, 0x38534000, 0x38536000, 0x38538000, 0x3853A000, 0x3853C000, 0x3853E000,
+ 0x38540000, 0x38542000, 0x38544000, 0x38546000, 0x38548000, 0x3854A000, 0x3854C000, 0x3854E000, 0x38550000, 0x38552000, 0x38554000, 0x38556000, 0x38558000, 0x3855A000, 0x3855C000, 0x3855E000,
+ 0x38560000, 0x38562000, 0x38564000, 0x38566000, 0x38568000, 0x3856A000, 0x3856C000, 0x3856E000, 0x38570000, 0x38572000, 0x38574000, 0x38576000, 0x38578000, 0x3857A000, 0x3857C000, 0x3857E000,
+ 0x38580000, 0x38582000, 0x38584000, 0x38586000, 0x38588000, 0x3858A000, 0x3858C000, 0x3858E000, 0x38590000, 0x38592000, 0x38594000, 0x38596000, 0x38598000, 0x3859A000, 0x3859C000, 0x3859E000,
+ 0x385A0000, 0x385A2000, 0x385A4000, 0x385A6000, 0x385A8000, 0x385AA000, 0x385AC000, 0x385AE000, 0x385B0000, 0x385B2000, 0x385B4000, 0x385B6000, 0x385B8000, 0x385BA000, 0x385BC000, 0x385BE000,
+ 0x385C0000, 0x385C2000, 0x385C4000, 0x385C6000, 0x385C8000, 0x385CA000, 0x385CC000, 0x385CE000, 0x385D0000, 0x385D2000, 0x385D4000, 0x385D6000, 0x385D8000, 0x385DA000, 0x385DC000, 0x385DE000,
+ 0x385E0000, 0x385E2000, 0x385E4000, 0x385E6000, 0x385E8000, 0x385EA000, 0x385EC000, 0x385EE000, 0x385F0000, 0x385F2000, 0x385F4000, 0x385F6000, 0x385F8000, 0x385FA000, 0x385FC000, 0x385FE000,
+ 0x38600000, 0x38602000, 0x38604000, 0x38606000, 0x38608000, 0x3860A000, 0x3860C000, 0x3860E000, 0x38610000, 0x38612000, 0x38614000, 0x38616000, 0x38618000, 0x3861A000, 0x3861C000, 0x3861E000,
+ 0x38620000, 0x38622000, 0x38624000, 0x38626000, 0x38628000, 0x3862A000, 0x3862C000, 0x3862E000, 0x38630000, 0x38632000, 0x38634000, 0x38636000, 0x38638000, 0x3863A000, 0x3863C000, 0x3863E000,
+ 0x38640000, 0x38642000, 0x38644000, 0x38646000, 0x38648000, 0x3864A000, 0x3864C000, 0x3864E000, 0x38650000, 0x38652000, 0x38654000, 0x38656000, 0x38658000, 0x3865A000, 0x3865C000, 0x3865E000,
+ 0x38660000, 0x38662000, 0x38664000, 0x38666000, 0x38668000, 0x3866A000, 0x3866C000, 0x3866E000, 0x38670000, 0x38672000, 0x38674000, 0x38676000, 0x38678000, 0x3867A000, 0x3867C000, 0x3867E000,
+ 0x38680000, 0x38682000, 0x38684000, 0x38686000, 0x38688000, 0x3868A000, 0x3868C000, 0x3868E000, 0x38690000, 0x38692000, 0x38694000, 0x38696000, 0x38698000, 0x3869A000, 0x3869C000, 0x3869E000,
+ 0x386A0000, 0x386A2000, 0x386A4000, 0x386A6000, 0x386A8000, 0x386AA000, 0x386AC000, 0x386AE000, 0x386B0000, 0x386B2000, 0x386B4000, 0x386B6000, 0x386B8000, 0x386BA000, 0x386BC000, 0x386BE000,
+ 0x386C0000, 0x386C2000, 0x386C4000, 0x386C6000, 0x386C8000, 0x386CA000, 0x386CC000, 0x386CE000, 0x386D0000, 0x386D2000, 0x386D4000, 0x386D6000, 0x386D8000, 0x386DA000, 0x386DC000, 0x386DE000,
+ 0x386E0000, 0x386E2000, 0x386E4000, 0x386E6000, 0x386E8000, 0x386EA000, 0x386EC000, 0x386EE000, 0x386F0000, 0x386F2000, 0x386F4000, 0x386F6000, 0x386F8000, 0x386FA000, 0x386FC000, 0x386FE000,
+ 0x38700000, 0x38702000, 0x38704000, 0x38706000, 0x38708000, 0x3870A000, 0x3870C000, 0x3870E000, 0x38710000, 0x38712000, 0x38714000, 0x38716000, 0x38718000, 0x3871A000, 0x3871C000, 0x3871E000,
+ 0x38720000, 0x38722000, 0x38724000, 0x38726000, 0x38728000, 0x3872A000, 0x3872C000, 0x3872E000, 0x38730000, 0x38732000, 0x38734000, 0x38736000, 0x38738000, 0x3873A000, 0x3873C000, 0x3873E000,
+ 0x38740000, 0x38742000, 0x38744000, 0x38746000, 0x38748000, 0x3874A000, 0x3874C000, 0x3874E000, 0x38750000, 0x38752000, 0x38754000, 0x38756000, 0x38758000, 0x3875A000, 0x3875C000, 0x3875E000,
+ 0x38760000, 0x38762000, 0x38764000, 0x38766000, 0x38768000, 0x3876A000, 0x3876C000, 0x3876E000, 0x38770000, 0x38772000, 0x38774000, 0x38776000, 0x38778000, 0x3877A000, 0x3877C000, 0x3877E000,
+ 0x38780000, 0x38782000, 0x38784000, 0x38786000, 0x38788000, 0x3878A000, 0x3878C000, 0x3878E000, 0x38790000, 0x38792000, 0x38794000, 0x38796000, 0x38798000, 0x3879A000, 0x3879C000, 0x3879E000,
+ 0x387A0000, 0x387A2000, 0x387A4000, 0x387A6000, 0x387A8000, 0x387AA000, 0x387AC000, 0x387AE000, 0x387B0000, 0x387B2000, 0x387B4000, 0x387B6000, 0x387B8000, 0x387BA000, 0x387BC000, 0x387BE000,
+ 0x387C0000, 0x387C2000, 0x387C4000, 0x387C6000, 0x387C8000, 0x387CA000, 0x387CC000, 0x387CE000, 0x387D0000, 0x387D2000, 0x387D4000, 0x387D6000, 0x387D8000, 0x387DA000, 0x387DC000, 0x387DE000,
+ 0x387E0000, 0x387E2000, 0x387E4000, 0x387E6000, 0x387E8000, 0x387EA000, 0x387EC000, 0x387EE000, 0x387F0000, 0x387F2000, 0x387F4000, 0x387F6000, 0x387F8000, 0x387FA000, 0x387FC000, 0x387FE000 };
+ static const bits<float>::type exponent_table[64] = {
+ 0x00000000, 0x00800000, 0x01000000, 0x01800000, 0x02000000, 0x02800000, 0x03000000, 0x03800000, 0x04000000, 0x04800000, 0x05000000, 0x05800000, 0x06000000, 0x06800000, 0x07000000, 0x07800000,
+ 0x08000000, 0x08800000, 0x09000000, 0x09800000, 0x0A000000, 0x0A800000, 0x0B000000, 0x0B800000, 0x0C000000, 0x0C800000, 0x0D000000, 0x0D800000, 0x0E000000, 0x0E800000, 0x0F000000, 0x47800000,
+ 0x80000000, 0x80800000, 0x81000000, 0x81800000, 0x82000000, 0x82800000, 0x83000000, 0x83800000, 0x84000000, 0x84800000, 0x85000000, 0x85800000, 0x86000000, 0x86800000, 0x87000000, 0x87800000,
+ 0x88000000, 0x88800000, 0x89000000, 0x89800000, 0x8A000000, 0x8A800000, 0x8B000000, 0x8B800000, 0x8C000000, 0x8C800000, 0x8D000000, 0x8D800000, 0x8E000000, 0x8E800000, 0x8F000000, 0xC7800000 };
+ static const unsigned short offset_table[64] = {
+ 0, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
+ 0, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 };
+ bits<float>::type fbits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10];
+ #endif
+ float out;
+ std::memcpy(&out, &fbits, sizeof(float));
+ return out;
+ #endif
+ }
+
+ /// Convert half-precision to IEEE double-precision.
+ /// \param value half-precision value to convert
+ /// \return double-precision value
+ inline double half2float_impl(unsigned int value, double, true_type)
+ {
+ #if HALF_ENABLE_F16C_INTRINSICS
+ return _mm_cvtsd_f64(_mm_cvtps_pd(_mm_cvtph_ps(_mm_cvtsi32_si128(value))));
+ #else
+ uint32 hi = static_cast<uint32>(value&0x8000) << 16;
+ unsigned int abs = value & 0x7FFF;
+ if(abs)
+ {
+ hi |= 0x3F000000 << static_cast<unsigned>(abs>=0x7C00);
+ for(; abs<0x400; abs<<=1,hi-=0x100000) ;
+ hi += static_cast<uint32>(abs) << 10;
+ }
+ bits<double>::type dbits = static_cast<bits<double>::type>(hi) << 32;
+ double out;
+ std::memcpy(&out, &dbits, sizeof(double));
+ return out;
+ #endif
+ }
+
+ /// Convert half-precision to non-IEEE floating-point.
+ /// \tparam T type to convert to (builtin integer type)
+ /// \param value half-precision value to convert
+ /// \return floating-point value
+ template<typename T> T half2float_impl(unsigned int value, T, ...)
+ {
+ T out;
+ unsigned int abs = value & 0x7FFF;
+ if(abs > 0x7C00)
+ out = (std::numeric_limits<T>::has_signaling_NaN && !(abs&0x200)) ? std::numeric_limits<T>::signaling_NaN() :
+ std::numeric_limits<T>::has_quiet_NaN ? std::numeric_limits<T>::quiet_NaN() : T();
+ else if(abs == 0x7C00)
+ out = std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : std::numeric_limits<T>::max();
+ else if(abs > 0x3FF)
+ out = std::ldexp(static_cast<T>((abs&0x3FF)|0x400), (abs>>10)-25);
+ else
+ out = std::ldexp(static_cast<T>(abs), -24);
+ return (value&0x8000) ? -out : out;
+ }
+
+ /// Convert half-precision to floating-point.
+ /// \tparam T type to convert to (builtin integer type)
+ /// \param value half-precision value to convert
+ /// \return floating-point value
+ template<typename T> T half2float(unsigned int value)
+ {
+ return half2float_impl(value, T(), bool_type<std::numeric_limits<T>::is_iec559&&sizeof(typename bits<T>::type)==sizeof(T)>());
+ }
+
+ /// Convert half-precision floating-point to integer.
+ /// \tparam R rounding mode to use
+ /// \tparam E `true` for round to even, `false` for round away from zero
+ /// \tparam I `true` to raise INEXACT exception (if inexact), `false` to never raise it
+ /// \tparam T type to convert to (buitlin integer type with at least 16 bits precision, excluding any implicit sign bits)
+ /// \param value half-precision value to convert
+ /// \return rounded integer value
+ /// \exception FE_INVALID if value is not representable in type \a T
+ /// \exception FE_INEXACT if value had to be rounded and \a I is `true`
+ template<std::float_round_style R,bool E,bool I,typename T> T half2int(unsigned int value)
+ {
+ unsigned int abs = value & 0x7FFF;
+ if(abs >= 0x7C00)
+ {
+ raise(FE_INVALID);
+ return (value&0x8000) ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
+ }
+ if(abs < 0x3800)
+ {
+ raise(FE_INEXACT, I);
+ return (R==std::round_toward_infinity) ? T(~(value>>15)&(abs!=0)) :
+ (R==std::round_toward_neg_infinity) ? -T(value>0x8000) :
+ T();
+ }
+ int exp = 25 - (abs>>10);
+ unsigned int m = (value&0x3FF) | 0x400;
+ int32 i = static_cast<int32>((exp<=0) ? (m<<-exp) : ((m+(
+ (R==std::round_to_nearest) ? ((1<<(exp-1))-(~(m>>exp)&E)) :
+ (R==std::round_toward_infinity) ? (((1<<exp)-1)&((value>>15)-1)) :
+ (R==std::round_toward_neg_infinity) ? (((1<<exp)-1)&-(value>>15)) : 0))>>exp));
+ if((!std::numeric_limits<T>::is_signed && (value&0x8000)) || (std::numeric_limits<T>::digits<16 &&
+ ((value&0x8000) ? (-i<std::numeric_limits<T>::min()) : (i>std::numeric_limits<T>::max()))))
+ raise(FE_INVALID);
+ else if(I && exp > 0 && (m&((1<<exp)-1)))
+ raise(FE_INEXACT);
+ return static_cast<T>((value&0x8000) ? -i : i);
+ }
+
+ /// \}
+ /// \name Mathematics
+ /// \{
+
+ /// upper part of 64-bit multiplication.
+ /// \tparam R rounding mode to use
+ /// \param x first factor
+ /// \param y second factor
+ /// \return upper 32 bit of \a x * \a y
+ template<std::float_round_style R> uint32 mulhi(uint32 x, uint32 y)
+ {
+ uint32 xy = (x>>16) * (y&0xFFFF), yx = (x&0xFFFF) * (y>>16), c = (xy&0xFFFF) + (yx&0xFFFF) + (((x&0xFFFF)*(y&0xFFFF))>>16);
+ return (x>>16)*(y>>16) + (xy>>16) + (yx>>16) + (c>>16) +
+ ((R==std::round_to_nearest) ? ((c>>15)&1) : (R==std::round_toward_infinity) ? ((c&0xFFFF)!=0) : 0);
+ }
+
+ /// 64-bit multiplication.
+ /// \param x first factor
+ /// \param y second factor
+ /// \return upper 32 bit of \a x * \a y rounded to nearest
+ inline uint32 multiply64(uint32 x, uint32 y)
+ {
+ #if HALF_ENABLE_CPP11_LONG_LONG
+ return static_cast<uint32>((static_cast<unsigned long long>(x)*static_cast<unsigned long long>(y)+0x80000000)>>32);
+ #else
+ return mulhi<std::round_to_nearest>(x, y);
+ #endif
+ }
+
+ /// 64-bit division.
+ /// \param x upper 32 bit of dividend
+ /// \param y divisor
+ /// \param s variable to store sticky bit for rounding
+ /// \return (\a x << 32) / \a y
+ inline uint32 divide64(uint32 x, uint32 y, int &s)
+ {
+ #if HALF_ENABLE_CPP11_LONG_LONG
+ unsigned long long xx = static_cast<unsigned long long>(x) << 32;
+ return s = (xx%y!=0), static_cast<uint32>(xx/y);
+ #else
+ y >>= 1;
+ uint32 rem = x, div = 0;
+ for(unsigned int i=0; i<32; ++i)
+ {
+ div <<= 1;
+ if(rem >= y)
+ {
+ rem -= y;
+ div |= 1;
+ }
+ rem <<= 1;
+ }
+ return s = rem > 1, div;
+ #endif
+ }
+
+ /// Half precision positive modulus.
+ /// \tparam Q `true` to compute full quotient, `false` else
+ /// \tparam R `true` to compute signed remainder, `false` for positive remainder
+ /// \param x first operand as positive finite half-precision value
+ /// \param y second operand as positive finite half-precision value
+ /// \param quo adress to store quotient at, `nullptr` if \a Q `false`
+ /// \return modulus of \a x / \a y
+ template<bool Q,bool R> unsigned int mod(unsigned int x, unsigned int y, int *quo = NULL)
+ {
+ unsigned int q = 0;
+ if(x > y)
+ {
+ int absx = x, absy = y, expx = 0, expy = 0;
+ for(; absx<0x400; absx<<=1,--expx) ;
+ for(; absy<0x400; absy<<=1,--expy) ;
+ expx += absx >> 10;
+ expy += absy >> 10;
+ int mx = (absx&0x3FF) | 0x400, my = (absy&0x3FF) | 0x400;
+ for(int d=expx-expy; d; --d)
+ {
+ if(!Q && mx == my)
+ return 0;
+ if(mx >= my)
+ {
+ mx -= my;
+ q += Q;
+ }
+ mx <<= 1;
+ q <<= static_cast<int>(Q);
+ }
+ if(!Q && mx == my)
+ return 0;
+ if(mx >= my)
+ {
+ mx -= my;
+ ++q;
+ }
+ if(Q)
+ {
+ q &= (1<<(std::numeric_limits<int>::digits-1)) - 1;
+ if(!mx)
+ return *quo = q, 0;
+ }
+ for(; mx<0x400; mx<<=1,--expy) ;
+ x = (expy>0) ? ((expy<<10)|(mx&0x3FF)) : (mx>>(1-expy));
+ }
+ if(R)
+ {
+ unsigned int a, b;
+ if(y < 0x800)
+ {
+ a = (x<0x400) ? (x<<1) : (x+0x400);
+ b = y;
+ }
+ else
+ {
+ a = x;
+ b = y - 0x400;
+ }
+ if(a > b || (a == b && (q&1)))
+ {
+ int exp = (y>>10) + (y<=0x3FF), d = exp - (x>>10) - (x<=0x3FF);
+ int m = (((y&0x3FF)|((y>0x3FF)<<10))<<1) - (((x&0x3FF)|((x>0x3FF)<<10))<<(1-d));
+ for(; m<0x800 && exp>1; m<<=1,--exp) ;
+ x = 0x8000 + ((exp-1)<<10) + (m>>1);
+ q += Q;
+ }
+ }
+ if(Q)
+ *quo = q;
+ return x;
+ }
+
+ /// Fixed point square root.
+ /// \tparam F number of fractional bits
+ /// \param r radicand in Q1.F fixed point format
+ /// \param exp exponent
+ /// \return square root as Q1.F/2
+ template<unsigned int F> uint32 sqrt(uint32 &r, int &exp)
+ {
+ int i = exp & 1;
+ r <<= i;
+ exp = (exp-i) / 2;
+ uint32 m = 0;
+ for(uint32 bit=static_cast<uint32>(1)<<F; bit; bit>>=2)
+ {
+ if(r < m+bit)
+ m >>= 1;
+ else
+ {
+ r -= m + bit;
+ m = (m>>1) + bit;
+ }
+ }
+ return m;
+ }
+
+ /// Fixed point binary exponential.
+ /// This uses the BKM algorithm in E-mode.
+ /// \param m exponent in [0,1) as Q0.31
+ /// \param n number of iterations (at most 32)
+ /// \return 2 ^ \a m as Q1.31
+ inline uint32 exp2(uint32 m, unsigned int n = 32)
+ {
+ static const uint32 logs[] = {
+ 0x80000000, 0x4AE00D1D, 0x2934F098, 0x15C01A3A, 0x0B31FB7D, 0x05AEB4DD, 0x02DCF2D1, 0x016FE50B,
+ 0x00B84E23, 0x005C3E10, 0x002E24CA, 0x001713D6, 0x000B8A47, 0x0005C53B, 0x0002E2A3, 0x00017153,
+ 0x0000B8AA, 0x00005C55, 0x00002E2B, 0x00001715, 0x00000B8B, 0x000005C5, 0x000002E3, 0x00000171,
+ 0x000000B9, 0x0000005C, 0x0000002E, 0x00000017, 0x0000000C, 0x00000006, 0x00000003, 0x00000001 };
+ if(!m)
+ return 0x80000000;
+ uint32 mx = 0x80000000, my = 0;
+ for(unsigned int i=1; i<n; ++i)
+ {
+ uint32 mz = my + logs[i];
+ if(mz <= m)
+ {
+ my = mz;
+ mx += mx >> i;
+ }
+ }
+ return mx;
+ }
+
+ /// Fixed point binary logarithm.
+ /// This uses the BKM algorithm in L-mode.
+ /// \param m mantissa in [1,2) as Q1.30
+ /// \param n number of iterations (at most 32)
+ /// \return log2(\a m) as Q0.31
+ inline uint32 log2(uint32 m, unsigned int n = 32)
+ {
+ static const uint32 logs[] = {
+ 0x80000000, 0x4AE00D1D, 0x2934F098, 0x15C01A3A, 0x0B31FB7D, 0x05AEB4DD, 0x02DCF2D1, 0x016FE50B,
+ 0x00B84E23, 0x005C3E10, 0x002E24CA, 0x001713D6, 0x000B8A47, 0x0005C53B, 0x0002E2A3, 0x00017153,
+ 0x0000B8AA, 0x00005C55, 0x00002E2B, 0x00001715, 0x00000B8B, 0x000005C5, 0x000002E3, 0x00000171,
+ 0x000000B9, 0x0000005C, 0x0000002E, 0x00000017, 0x0000000C, 0x00000006, 0x00000003, 0x00000001 };
+ if(m == 0x40000000)
+ return 0;
+ uint32 mx = 0x40000000, my = 0;
+ for(unsigned int i=1; i<n; ++i)
+ {
+ uint32 mz = mx + (mx>>i);
+ if(mz <= m)
+ {
+ mx = mz;
+ my += logs[i];
+ }
+ }
+ return my;
+ }
+
+ /// Fixed point sine and cosine.
+ /// This uses the CORDIC algorithm in rotation mode.
+ /// \param mz angle in [-pi/2,pi/2] as Q1.30
+ /// \param n number of iterations (at most 31)
+ /// \return sine and cosine of \a mz as Q1.30
+ inline std::pair<uint32,uint32> sincos(uint32 mz, unsigned int n = 31)
+ {
+ static const uint32 angles[] = {
+ 0x3243F6A9, 0x1DAC6705, 0x0FADBAFD, 0x07F56EA7, 0x03FEAB77, 0x01FFD55C, 0x00FFFAAB, 0x007FFF55,
+ 0x003FFFEB, 0x001FFFFD, 0x00100000, 0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00008000,
+ 0x00004000, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200, 0x00000100, 0x00000080,
+ 0x00000040, 0x00000020, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000001 };
+ uint32 mx = 0x26DD3B6A, my = 0;
+ for(unsigned int i=0; i<n; ++i)
+ {
+ uint32 sign = sign_mask(mz);
+ uint32 tx = mx - (arithmetic_shift(my, i)^sign) + sign;
+ uint32 ty = my + (arithmetic_shift(mx, i)^sign) - sign;
+ mx = tx; my = ty; mz -= (angles[i]^sign) - sign;
+ }
+ return std::make_pair(my, mx);
+ }
+
+ /// Fixed point arc tangent.
+ /// This uses the CORDIC algorithm in vectoring mode.
+ /// \param my y coordinate as Q0.30
+ /// \param mx x coordinate as Q0.30
+ /// \param n number of iterations (at most 31)
+ /// \return arc tangent of \a my / \a mx as Q1.30
+ inline uint32 atan2(uint32 my, uint32 mx, unsigned int n = 31)
+ {
+ static const uint32 angles[] = {
+ 0x3243F6A9, 0x1DAC6705, 0x0FADBAFD, 0x07F56EA7, 0x03FEAB77, 0x01FFD55C, 0x00FFFAAB, 0x007FFF55,
+ 0x003FFFEB, 0x001FFFFD, 0x00100000, 0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00008000,
+ 0x00004000, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200, 0x00000100, 0x00000080,
+ 0x00000040, 0x00000020, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000001 };
+ uint32 mz = 0;
+ for(unsigned int i=0; i<n; ++i)
+ {
+ uint32 sign = sign_mask(my);
+ uint32 tx = mx + (arithmetic_shift(my, i)^sign) - sign;
+ uint32 ty = my - (arithmetic_shift(mx, i)^sign) + sign;
+ mx = tx; my = ty; mz += (angles[i]^sign) - sign;
+ }
+ return mz;
+ }
+
+ /// Reduce argument for trigonometric functions.
+ /// \param abs half-precision floating-point value
+ /// \param k value to take quarter period
+ /// \return \a abs reduced to [-pi/4,pi/4] as Q0.30
+ inline uint32 angle_arg(unsigned int abs, int &k)
+ {
+ uint32 m = (abs&0x3FF) | ((abs>0x3FF)<<10);
+ int exp = (abs>>10) + (abs<=0x3FF) - 15;
+ if(abs < 0x3A48)
+ return k = 0, m << (exp+20);
+ #if HALF_ENABLE_CPP11_LONG_LONG
+ unsigned long long y = m * 0xA2F9836E4E442, mask = (1ULL<<(62-exp)) - 1, yi = (y+(mask>>1)) & ~mask, f = y - yi;
+ uint32 sign = -static_cast<uint32>(f>>63);
+ k = static_cast<int>(yi>>(62-exp));
+ return (multiply64(static_cast<uint32>((sign ? -f : f)>>(31-exp)), 0xC90FDAA2)^sign) - sign;
+ #else
+ uint32 yh = m*0xA2F98 + mulhi<std::round_toward_zero>(m, 0x36E4E442), yl = (m*0x36E4E442) & 0xFFFFFFFF;
+ uint32 mask = (static_cast<uint32>(1)<<(30-exp)) - 1, yi = (yh+(mask>>1)) & ~mask, sign = -static_cast<uint32>(yi>yh);
+ k = static_cast<int>(yi>>(30-exp));
+ uint32 fh = (yh^sign) + (yi^~sign) - ~sign, fl = (yl^sign) - sign;
+ return (multiply64((exp>-1) ? (((fh<<(1+exp))&0xFFFFFFFF)|((fl&0xFFFFFFFF)>>(31-exp))) : fh, 0xC90FDAA2)^sign) - sign;
+ #endif
+ }
+
+ /// Get arguments for atan2 function.
+ /// \param abs half-precision floating-point value
+ /// \return \a abs and sqrt(1 - \a abs^2) as Q0.30
+ inline std::pair<uint32,uint32> atan2_args(unsigned int abs)
+ {
+ int exp = -15;
+ for(; abs<0x400; abs<<=1,--exp) ;
+ exp += abs >> 10;
+ uint32 my = ((abs&0x3FF)|0x400) << 5, r = my * my;
+ int rexp = 2 * exp;
+ r = 0x40000000 - ((rexp>-31) ? ((r>>-rexp)|((r&((static_cast<uint32>(1)<<-rexp)-1))!=0)) : 1);
+ for(rexp=0; r<0x40000000; r<<=1,--rexp) ;
+ uint32 mx = sqrt<30>(r, rexp);
+ int d = exp - rexp;
+ if(d < 0)
+ return std::make_pair((d<-14) ? ((my>>(-d-14))+((my>>(-d-15))&1)) : (my<<(14+d)), (mx<<14)+(r<<13)/mx);
+ if(d > 0)
+ return std::make_pair(my<<14, (d>14) ? ((mx>>(d-14))+((mx>>(d-15))&1)) : ((d==14) ? mx : ((mx<<(14-d))+(r<<(13-d))/mx)));
+ return std::make_pair(my<<13, (mx<<13)+(r<<12)/mx);
+ }
+
+ /// Get exponentials for hyperbolic computation
+ /// \param abs half-precision floating-point value
+ /// \param exp variable to take unbiased exponent of larger result
+ /// \param n number of BKM iterations (at most 32)
+ /// \return exp(abs) and exp(-\a abs) as Q1.31 with same exponent
+ inline std::pair<uint32,uint32> hyperbolic_args(unsigned int abs, int &exp, unsigned int n = 32)
+ {
+ uint32 mx = detail::multiply64(static_cast<uint32>((abs&0x3FF)+((abs>0x3FF)<<10))<<21, 0xB8AA3B29), my;
+ int e = (abs>>10) + (abs<=0x3FF);
+ if(e < 14)
+ {
+ exp = 0;
+ mx >>= 14 - e;
+ }
+ else
+ {
+ exp = mx >> (45-e);
+ mx = (mx<<(e-14)) & 0x7FFFFFFF;
+ }
+ mx = exp2(mx, n);
+ int d = exp << 1, s;
+ if(mx > 0x80000000)
+ {
+ my = divide64(0x80000000, mx, s);
+ my |= s;
+ ++d;
+ }
+ else
+ my = mx;
+ return std::make_pair(mx, (d<31) ? ((my>>d)|((my&((static_cast<uint32>(1)<<d)-1))!=0)) : 1);
+ }
+
+ /// Postprocessing for binary exponential.
+ /// \tparam R rounding mode to use
+ /// \tparam I `true` to always raise INEXACT exception, `false` to raise only for rounded results
+ /// \param m mantissa as Q1.31
+ /// \param exp absolute value of unbiased exponent
+ /// \param esign sign of actual exponent
+ /// \param sign sign bit of result
+ /// \return value converted to half-precision
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if value had to be rounded or \a I is `true`
+ template<std::float_round_style R,bool I> unsigned int exp2_post(uint32 m, int exp, bool esign, unsigned int sign = 0)
+ {
+ int s = 0;
+ if(esign)
+ {
+ if(m > 0x80000000)
+ {
+ m = divide64(0x80000000, m, s);
+ ++exp;
+ }
+ if(exp > 25)
+ return underflow<R>(sign);
+ else if(exp == 25)
+ return rounded<R,I>(sign, 1, (m&0x7FFFFFFF)!=0);
+ exp = -exp;
+ }
+ else if(exp > 15)
+ return overflow<R>(sign);
+ return fixed2half<R,31,false,false,I>(m, exp+14, sign, s);
+ }
+
+ /// Postprocessing for binary logarithm.
+ /// \tparam R rounding mode to use
+ /// \tparam L logarithm for base transformation as Q1.31
+ /// \param m fractional part of logarithm as Q0.31
+ /// \param ilog signed integer part of logarithm
+ /// \param exp biased exponent of result
+ /// \param sign sign bit of result
+ /// \return value base-transformed and converted to half-precision
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if no other exception occurred
+ template<std::float_round_style R,uint32 L> unsigned int log2_post(uint32 m, int ilog, int exp, unsigned int sign = 0)
+ {
+ uint32 msign = sign_mask(ilog);
+ m = (((static_cast<uint32>(ilog)<<27)+(m>>4))^msign) - msign;
+ if(!m)
+ return 0;
+ for(; m<0x80000000; m<<=1,--exp) ;
+ int i = m >= L, s;
+ exp += i;
+ m >>= 1 + i;
+ sign ^= msign & 0x8000;
+ if(exp < -11)
+ return underflow<R>(sign);
+ m = divide64(m, L, s);
+ return fixed2half<R,30,false,false,true>(m, exp, sign, 1);
+ }
+
+ /// Hypotenuse square root and postprocessing.
+ /// \tparam R rounding mode to use
+ /// \param r mantissa as Q2.30
+ /// \param exp unbiased exponent
+ /// \return square root converted to half-precision
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if value had to be rounded
+ template<std::float_round_style R> unsigned int hypot_post(uint32 r, int exp)
+ {
+ int i = r >> 31;
+ if((exp+=i) > 46)
+ return overflow<R>();
+ if(exp < -34)
+ return underflow<R>();
+ r = (r>>i) | (r&i);
+ uint32 m = sqrt<30>(r, exp+=15);
+ return fixed2half<R,15,false,false,false>(m, exp-1, 0, r!=0);
+ }
+
+ /// Division and postprocessing for tangents.
+ /// \tparam R rounding mode to use
+ /// \param my dividend as Q1.31
+ /// \param mx divisor as Q1.31
+ /// \param exp biased exponent of result
+ /// \param sign sign bit of result
+ /// \return quotient converted to half-precision
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if no other exception occurred
+ template<std::float_round_style R> unsigned int tangent_post(uint32 my, uint32 mx, int exp, unsigned int sign = 0)
+ {
+ int i = my >= mx, s;
+ exp += i;
+ if(exp > 29)
+ return overflow<R>(sign);
+ if(exp < -11)
+ return underflow<R>(sign);
+ uint32 m = divide64(my>>(i+1), mx, s);
+ return fixed2half<R,30,false,false,true>(m, exp, sign, s);
+ }
+
+ /// Area function and postprocessing.
+ /// This computes the value directly in Q2.30 using the representation `asinh|acosh(x) = log(x+sqrt(x^2+|-1))`.
+ /// \tparam R rounding mode to use
+ /// \tparam S `true` for asinh, `false` for acosh
+ /// \param arg half-precision argument
+ /// \return asinh|acosh(\a arg) converted to half-precision
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if no other exception occurred
+ template<std::float_round_style R,bool S> unsigned int area(unsigned int arg)
+ {
+ int abs = arg & 0x7FFF, expx = (abs>>10) + (abs<=0x3FF) - 15, expy = -15, ilog, i;
+ uint32 mx = static_cast<uint32>((abs&0x3FF)|((abs>0x3FF)<<10)) << 20, my, r;
+ for(; abs<0x400; abs<<=1,--expy) ;
+ expy += abs >> 10;
+ r = ((abs&0x3FF)|0x400) << 5;
+ r *= r;
+ i = r >> 31;
+ expy = 2*expy + i;
+ r >>= i;
+ if(S)
+ {
+ if(expy < 0)
+ {
+ r = 0x40000000 + ((expy>-30) ? ((r>>-expy)|((r&((static_cast<uint32>(1)<<-expy)-1))!=0)) : 1);
+ expy = 0;
+ }
+ else
+ {
+ r += 0x40000000 >> expy;
+ i = r >> 31;
+ r = (r>>i) | (r&i);
+ expy += i;
+ }
+ }
+ else
+ {
+ r -= 0x40000000 >> expy;
+ for(; r<0x40000000; r<<=1,--expy) ;
+ }
+ my = sqrt<30>(r, expy);
+ my = (my<<15) + (r<<14)/my;
+ if(S)
+ {
+ mx >>= expy - expx;
+ ilog = expy;
+ }
+ else
+ {
+ my >>= expx - expy;
+ ilog = expx;
+ }
+ my += mx;
+ i = my >> 31;
+ static const int G = S && (R==std::round_to_nearest);
+ return log2_post<R,0xB8AA3B2A>(log2(my>>i, 26+S+G)+(G<<3), ilog+i, 17, arg&(static_cast<unsigned>(S)<<15));
+ }
+
+ /// Class for 1.31 unsigned floating-point computation
+ struct f31
+ {
+ /// Constructor.
+ /// \param mant mantissa as 1.31
+ /// \param e exponent
+ HALF_CONSTEXPR f31(uint32 mant, int e) : m(mant), exp(e) {}
+
+ /// Constructor.
+ /// \param abs unsigned half-precision value
+ f31(unsigned int abs) : exp(-15)
+ {
+ for(; abs<0x400; abs<<=1,--exp) ;
+ m = static_cast<uint32>((abs&0x3FF)|0x400) << 21;
+ exp += (abs>>10);
+ }
+
+ /// Addition operator.
+ /// \param a first operand
+ /// \param b second operand
+ /// \return \a a + \a b
+ friend f31 operator+(f31 a, f31 b)
+ {
+ if(b.exp > a.exp)
+ std::swap(a, b);
+ int d = a.exp - b.exp;
+ uint32 m = a.m + ((d<32) ? (b.m>>d) : 0);
+ int i = (m&0xFFFFFFFF) < a.m;
+ return f31(((m+i)>>i)|0x80000000, a.exp+i);
+ }
+
+ /// Subtraction operator.
+ /// \param a first operand
+ /// \param b second operand
+ /// \return \a a - \a b
+ friend f31 operator-(f31 a, f31 b)
+ {
+ int d = a.exp - b.exp, exp = a.exp;
+ uint32 m = a.m - ((d<32) ? (b.m>>d) : 0);
+ if(!m)
+ return f31(0, -32);
+ for(; m<0x80000000; m<<=1,--exp) ;
+ return f31(m, exp);
+ }
+
+ /// Multiplication operator.
+ /// \param a first operand
+ /// \param b second operand
+ /// \return \a a * \a b
+ friend f31 operator*(f31 a, f31 b)
+ {
+ uint32 m = multiply64(a.m, b.m);
+ int i = m >> 31;
+ return f31(m<<(1-i), a.exp + b.exp + i);
+ }
+
+ /// Division operator.
+ /// \param a first operand
+ /// \param b second operand
+ /// \return \a a / \a b
+ friend f31 operator/(f31 a, f31 b)
+ {
+ int i = a.m >= b.m, s;
+ uint32 m = divide64((a.m+i)>>i, b.m, s);
+ return f31(m, a.exp - b.exp + i - 1);
+ }
+
+ uint32 m; ///< mantissa as 1.31.
+ int exp; ///< exponent.
+ };
+
+ /// Error function and postprocessing.
+ /// This computes the value directly in Q1.31 using the approximations given
+ /// [here](https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions).
+ /// \tparam R rounding mode to use
+ /// \tparam C `true` for comlementary error function, `false` else
+ /// \param arg half-precision function argument
+ /// \return approximated value of error function in half-precision
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if no other exception occurred
+ template<std::float_round_style R,bool C> unsigned int erf(unsigned int arg)
+ {
+ unsigned int abs = arg & 0x7FFF, sign = arg & 0x8000;
+ f31 x(abs), x2 = x * x * f31(0xB8AA3B29, 0), t = f31(0x80000000, 0) / (f31(0x80000000, 0)+f31(0xA7BA054A, -2)*x), t2 = t * t;
+ f31 e = ((f31(0x87DC2213, 0)*t2+f31(0xB5F0E2AE, 0))*t2+f31(0x82790637, -2)-(f31(0xBA00E2B8, 0)*t2+f31(0x91A98E62, -2))*t) * t /
+ ((x2.exp<0) ? f31(exp2((x2.exp>-32) ? (x2.m>>-x2.exp) : 0, 30), 0) : f31(exp2((x2.m<<x2.exp)&0x7FFFFFFF, 22), x2.m>>(31-x2.exp)));
+ return (!C || sign) ? fixed2half<R,31,false,true,true>(0x80000000-(e.m>>(C-e.exp)), 14+C, sign&(C-1U)) :
+ (e.exp<-25) ? underflow<R>() : fixed2half<R,30,false,false,true>(e.m>>1, e.exp+14, 0, e.m&1);
+ }
+
+ /// Gamma function and postprocessing.
+ /// This approximates the value of either the gamma function or its logarithm directly in Q1.31.
+ /// \tparam R rounding mode to use
+ /// \tparam L `true` for lograithm of gamma function, `false` for gamma function
+ /// \param arg half-precision floating-point value
+ /// \return lgamma/tgamma(\a arg) in half-precision
+ /// \exception FE_OVERFLOW on overflows
+ /// \exception FE_UNDERFLOW on underflows
+ /// \exception FE_INEXACT if \a arg is not a positive integer
+ template<std::float_round_style R,bool L> unsigned int gamma(unsigned int arg)
+ {
+/* static const double p[] ={ 2.50662827563479526904, 225.525584619175212544, -268.295973841304927459, 80.9030806934622512966, -5.00757863970517583837, 0.0114684895434781459556 };
+ double t = arg + 4.65, s = p[0];
+ for(unsigned int i=0; i<5; ++i)
+ s += p[i+1] / (arg+i);
+ return std::log(s) + (arg-0.5)*std::log(t) - t;
+*/ static const f31 pi(0xC90FDAA2, 1), lbe(0xB8AA3B29, 0);
+ unsigned int abs = arg & 0x7FFF, sign = arg & 0x8000;
+ bool bsign = sign != 0;
+ f31 z(abs), x = sign ? (z+f31(0x80000000, 0)) : z, t = x + f31(0x94CCCCCD, 2), s =
+ f31(0xA06C9901, 1) + f31(0xBBE654E2, -7)/(x+f31(0x80000000, 2)) + f31(0xA1CE6098, 6)/(x+f31(0x80000000, 1))
+ + f31(0xE1868CB7, 7)/x - f31(0x8625E279, 8)/(x+f31(0x80000000, 0)) - f31(0xA03E158F, 2)/(x+f31(0xC0000000, 1));
+ int i = (s.exp>=2) + (s.exp>=4) + (s.exp>=8) + (s.exp>=16);
+ s = f31((static_cast<uint32>(s.exp)<<(31-i))+(log2(s.m>>1, 28)>>i), i) / lbe;
+ if(x.exp != -1 || x.m != 0x80000000)
+ {
+ i = (t.exp>=2) + (t.exp>=4) + (t.exp>=8);
+ f31 l = f31((static_cast<uint32>(t.exp)<<(31-i))+(log2(t.m>>1, 30)>>i), i) / lbe;
+ s = (x.exp<-1) ? (s-(f31(0x80000000, -1)-x)*l) : (s+(x-f31(0x80000000, -1))*l);
+ }
+ s = x.exp ? (s-t) : (t-s);
+ if(bsign)
+ {
+ if(z.exp >= 0)
+ {
+ sign &= (L|((z.m>>(31-z.exp))&1)) - 1;
+ for(z=f31((z.m<<(1+z.exp))&0xFFFFFFFF, -1); z.m<0x80000000; z.m<<=1,--z.exp) ;
+ }
+ if(z.exp == -1)
+ z = f31(0x80000000, 0) - z;
+ if(z.exp < -1)
+ {
+ z = z * pi;
+ z.m = sincos(z.m>>(1-z.exp), 30).first;
+ for(z.exp=1; z.m<0x80000000; z.m<<=1,--z.exp) ;
+ }
+ else
+ z = f31(0x80000000, 0);
+ }
+ if(L)
+ {
+ if(bsign)
+ {
+ f31 l(0x92868247, 0);
+ if(z.exp < 0)
+ {
+ uint32 m = log2((z.m+1)>>1, 27);
+ z = f31(-((static_cast<uint32>(z.exp)<<26)+(m>>5)), 5);
+ for(; z.m<0x80000000; z.m<<=1,--z.exp) ;
+ l = l + z / lbe;
+ }
+ sign = static_cast<unsigned>(x.exp&&(l.exp<s.exp||(l.exp==s.exp&&l.m<s.m))) << 15;
+ s = sign ? (s-l) : x.exp ? (l-s) : (l+s);
+ }
+ else
+ {
+ sign = static_cast<unsigned>(x.exp==0) << 15;
+ if(s.exp < -24)
+ return underflow<R>(sign);
+ if(s.exp > 15)
+ return overflow<R>(sign);
+ }
+ }
+ else
+ {
+ s = s * lbe;
+ uint32 m;
+ if(s.exp < 0)
+ {
+ m = s.m >> -s.exp;
+ s.exp = 0;
+ }
+ else
+ {
+ m = (s.m<<s.exp) & 0x7FFFFFFF;
+ s.exp = (s.m>>(31-s.exp));
+ }
+ s.m = exp2(m, 27);
+ if(!x.exp)
+ s = f31(0x80000000, 0) / s;
+ if(bsign)
+ {
+ if(z.exp < 0)
+ s = s * z;
+ s = pi / s;
+ if(s.exp < -24)
+ return underflow<R>(sign);
+ }
+ else if(z.exp > 0 && !(z.m&((1<<(31-z.exp))-1)))
+ return ((s.exp+14)<<10) + (s.m>>21);
+ if(s.exp > 15)
+ return overflow<R>(sign);
+ }
+ return fixed2half<R,31,false,false,true>(s.m, s.exp+14, sign);
+ }
+ /// \}
+
+ template<typename,typename,std::float_round_style> struct half_caster;
+ }
+
+ /// Half-precision floating-point type.
+ /// This class implements an IEEE-conformant half-precision floating-point type with the usual arithmetic
+ /// operators and conversions. It is implicitly convertible to single-precision floating-point, which makes artihmetic
+ /// expressions and functions with mixed-type operands to be of the most precise operand type.
+ ///
+ /// According to the C++98/03 definition, the half type is not a POD type. But according to C++11's less strict and
+ /// extended definitions it is both a standard layout type and a trivially copyable type (even if not a POD type), which
+ /// means it can be standard-conformantly copied using raw binary copies. But in this context some more words about the
+ /// actual size of the type. Although the half is representing an IEEE 16-bit type, it does not neccessarily have to be of
+ /// exactly 16-bits size. But on any reasonable implementation the actual binary representation of this type will most
+ /// probably not ivolve any additional "magic" or padding beyond the simple binary representation of the underlying 16-bit
+ /// IEEE number, even if not strictly guaranteed by the standard. But even then it only has an actual size of 16 bits if
+ /// your C++ implementation supports an unsigned integer type of exactly 16 bits width. But this should be the case on
+ /// nearly any reasonable platform.
+ ///
+ /// So if your C++ implementation is not totally exotic or imposes special alignment requirements, it is a reasonable
+ /// assumption that the data of a half is just comprised of the 2 bytes of the underlying IEEE representation.
+ class half
+ {
+ public:
+ /// \name Construction and assignment
+ /// \{
+
+ /// Default constructor.
+ /// This initializes the half to 0. Although this does not match the builtin types' default-initialization semantics
+ /// and may be less efficient than no initialization, it is needed to provide proper value-initialization semantics.
+ HALF_CONSTEXPR half() HALF_NOEXCEPT : data_() {}
+
+ /// Conversion constructor.
+ /// \param rhs float to convert
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ explicit half(float rhs) : data_(static_cast<detail::uint16>(detail::float2half<round_style>(rhs))) {}
+
+ /// Conversion to single-precision.
+ /// \return single precision value representing expression value
+ operator float() const { return detail::half2float<float>(data_); }
+
+ /// Assignment operator.
+ /// \param rhs single-precision value to copy from
+ /// \return reference to this half
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ half& operator=(float rhs) { data_ = static_cast<detail::uint16>(detail::float2half<round_style>(rhs)); return *this; }
+
+ /// \}
+ /// \name Arithmetic updates
+ /// \{
+
+ /// Arithmetic assignment.
+ /// \tparam T type of concrete half expression
+ /// \param rhs half expression to add
+ /// \return reference to this half
+ /// \exception FE_... according to operator+(half,half)
+ half& operator+=(half rhs) { return *this = *this + rhs; }
+
+ /// Arithmetic assignment.
+ /// \tparam T type of concrete half expression
+ /// \param rhs half expression to subtract
+ /// \return reference to this half
+ /// \exception FE_... according to operator-(half,half)
+ half& operator-=(half rhs) { return *this = *this - rhs; }
+
+ /// Arithmetic assignment.
+ /// \tparam T type of concrete half expression
+ /// \param rhs half expression to multiply with
+ /// \return reference to this half
+ /// \exception FE_... according to operator*(half,half)
+ half& operator*=(half rhs) { return *this = *this * rhs; }
+
+ /// Arithmetic assignment.
+ /// \tparam T type of concrete half expression
+ /// \param rhs half expression to divide by
+ /// \return reference to this half
+ /// \exception FE_... according to operator/(half,half)
+ half& operator/=(half rhs) { return *this = *this / rhs; }
+
+ /// Arithmetic assignment.
+ /// \param rhs single-precision value to add
+ /// \return reference to this half
+ /// \exception FE_... according to operator=()
+ half& operator+=(float rhs) { return *this = *this + rhs; }
+
+ /// Arithmetic assignment.
+ /// \param rhs single-precision value to subtract
+ /// \return reference to this half
+ /// \exception FE_... according to operator=()
+ half& operator-=(float rhs) { return *this = *this - rhs; }
+
+ /// Arithmetic assignment.
+ /// \param rhs single-precision value to multiply with
+ /// \return reference to this half
+ /// \exception FE_... according to operator=()
+ half& operator*=(float rhs) { return *this = *this * rhs; }
+
+ /// Arithmetic assignment.
+ /// \param rhs single-precision value to divide by
+ /// \return reference to this half
+ /// \exception FE_... according to operator=()
+ half& operator/=(float rhs) { return *this = *this / rhs; }
+
+ /// \}
+ /// \name Increment and decrement
+ /// \{
+
+ /// Prefix increment.
+ /// \return incremented half value
+ /// \exception FE_... according to operator+(half,half)
+ half& operator++() { return *this = *this + half(detail::binary, 0x3C00); }
+
+ /// Prefix decrement.
+ /// \return decremented half value
+ /// \exception FE_... according to operator-(half,half)
+ half& operator--() { return *this = *this + half(detail::binary, 0xBC00); }
+
+ /// Postfix increment.
+ /// \return non-incremented half value
+ /// \exception FE_... according to operator+(half,half)
+ half operator++(int) { half out(*this); ++*this; return out; }
+
+ /// Postfix decrement.
+ /// \return non-decremented half value
+ /// \exception FE_... according to operator-(half,half)
+ half operator--(int) { half out(*this); --*this; return out; }
+ /// \}
+
+ private:
+ /// Rounding mode to use
+ static const std::float_round_style round_style = (std::float_round_style)(HALF_ROUND_STYLE);
+
+ /// Constructor.
+ /// \param bits binary representation to set half to
+ HALF_CONSTEXPR half(detail::binary_t, unsigned int bits) HALF_NOEXCEPT : data_(static_cast<detail::uint16>(bits)) {}
+
+ /// Internal binary representation
+ detail::uint16 data_;
+
+ #ifndef HALF_DOXYGEN_ONLY
+ friend HALF_CONSTEXPR_NOERR bool operator==(half, half);
+ friend HALF_CONSTEXPR_NOERR bool operator!=(half, half);
+ friend HALF_CONSTEXPR_NOERR bool operator<(half, half);
+ friend HALF_CONSTEXPR_NOERR bool operator>(half, half);
+ friend HALF_CONSTEXPR_NOERR bool operator<=(half, half);
+ friend HALF_CONSTEXPR_NOERR bool operator>=(half, half);
+ friend HALF_CONSTEXPR half operator-(half);
+ friend half operator+(half, half);
+ friend half operator-(half, half);
+ friend half operator*(half, half);
+ friend half operator/(half, half);
+ template<typename charT,typename traits> friend std::basic_ostream<charT,traits>& operator<<(std::basic_ostream<charT,traits>&, half);
+ template<typename charT,typename traits> friend std::basic_istream<charT,traits>& operator>>(std::basic_istream<charT,traits>&, half&);
+ friend HALF_CONSTEXPR half fabs(half);
+ friend half fmod(half, half);
+ friend half remainder(half, half);
+ friend half remquo(half, half, int*);
+ friend half fma(half, half, half);
+ friend HALF_CONSTEXPR_NOERR half fmax(half, half);
+ friend HALF_CONSTEXPR_NOERR half fmin(half, half);
+ friend half fdim(half, half);
+ friend half nanh(const char*);
+ friend half exp(half);
+ friend half exp2(half);
+ friend half expm1(half);
+ friend half log(half);
+ friend half log10(half);
+ friend half log2(half);
+ friend half log1p(half);
+ friend half sqrt(half);
+ friend half cbrt(half);
+ friend half hypot(half, half);
+ friend half hypot(half, half, half);
+ friend half pow(half, half);
+ friend void sincos(half, half*, half*);
+ friend half sin(half);
+ friend half cos(half);
+ friend half tan(half);
+ friend half asin(half);
+ friend half acos(half);
+ friend half atan(half);
+ friend half atan2(half, half);
+ friend half sinh(half);
+ friend half cosh(half);
+ friend half tanh(half);
+ friend half asinh(half);
+ friend half acosh(half);
+ friend half atanh(half);
+ friend half erf(half);
+ friend half erfc(half);
+ friend half lgamma(half);
+ friend half tgamma(half);
+ friend half ceil(half);
+ friend half floor(half);
+ friend half trunc(half);
+ friend half round(half);
+ friend long lround(half);
+ friend half rint(half);
+ friend long lrint(half);
+ friend half nearbyint(half);
+ #ifdef HALF_ENABLE_CPP11_LONG_LONG
+ friend long long llround(half);
+ friend long long llrint(half);
+ #endif
+ friend half frexp(half, int*);
+ friend half scalbln(half, long);
+ friend half modf(half, half*);
+ friend int ilogb(half);
+ friend half logb(half);
+ friend half nextafter(half, half);
+ friend half nexttoward(half, long double);
+ friend HALF_CONSTEXPR half copysign(half, half);
+ friend HALF_CONSTEXPR int fpclassify(half);
+ friend HALF_CONSTEXPR bool isfinite(half);
+ friend HALF_CONSTEXPR bool isinf(half);
+ friend HALF_CONSTEXPR bool isnan(half);
+ friend HALF_CONSTEXPR bool isnormal(half);
+ friend HALF_CONSTEXPR bool signbit(half);
+ friend HALF_CONSTEXPR bool isgreater(half, half);
+ friend HALF_CONSTEXPR bool isgreaterequal(half, half);
+ friend HALF_CONSTEXPR bool isless(half, half);
+ friend HALF_CONSTEXPR bool islessequal(half, half);
+ friend HALF_CONSTEXPR bool islessgreater(half, half);
+ template<typename,typename,std::float_round_style> friend struct detail::half_caster;
+ friend class std::numeric_limits<half>;
+ #if HALF_ENABLE_CPP11_HASH
+ friend struct std::hash<half>;
+ #endif
+ #if HALF_ENABLE_CPP11_USER_LITERALS
+ friend half literal::operator "" _h(long double);
+ #endif
+ #endif
+ };
+
+#if HALF_ENABLE_CPP11_USER_LITERALS
+ namespace literal
+ {
+ /// Half literal.
+ /// While this returns a properly rounded half-precision value, half literals can unfortunately not be constant
+ /// expressions due to rather involved conversions. So don't expect this to be a literal literal without involving
+ /// conversion operations at runtime. It is a convenience feature, not a performance optimization.
+ /// \param value literal value
+ /// \return half with of given value (possibly rounded)
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half operator "" _h(long double value) { return half(detail::binary, detail::float2half<half::round_style>(value)); }
+ }
+#endif
+
+ namespace detail
+ {
+ /// Helper class for half casts.
+ /// This class template has to be specialized for all valid cast arguments to define an appropriate static
+ /// `cast` member function and a corresponding `type` member denoting its return type.
+ /// \tparam T destination type
+ /// \tparam U source type
+ /// \tparam R rounding mode to use
+ template<typename T,typename U,std::float_round_style R=(std::float_round_style)(HALF_ROUND_STYLE)> struct half_caster {};
+ template<typename U,std::float_round_style R> struct half_caster<half,U,R>
+ {
+ #if HALF_ENABLE_CPP11_STATIC_ASSERT && HALF_ENABLE_CPP11_TYPE_TRAITS
+ static_assert(std::is_arithmetic<U>::value, "half_cast from non-arithmetic type unsupported");
+ #endif
+
+ static half cast(U arg) { return cast_impl(arg, is_float<U>()); };
+
+ private:
+ static half cast_impl(U arg, true_type) { return half(binary, float2half<R>(arg)); }
+ static half cast_impl(U arg, false_type) { return half(binary, int2half<R>(arg)); }
+ };
+ template<typename T,std::float_round_style R> struct half_caster<T,half,R>
+ {
+ #if HALF_ENABLE_CPP11_STATIC_ASSERT && HALF_ENABLE_CPP11_TYPE_TRAITS
+ static_assert(std::is_arithmetic<T>::value, "half_cast to non-arithmetic type unsupported");
+ #endif
+
+ static T cast(half arg) { return cast_impl(arg, is_float<T>()); }
+
+ private:
+ static T cast_impl(half arg, true_type) { return half2float<T>(arg.data_); }
+ static T cast_impl(half arg, false_type) { return half2int<R,true,true,T>(arg.data_); }
+ };
+ template<std::float_round_style R> struct half_caster<half,half,R>
+ {
+ static half cast(half arg) { return arg; }
+ };
+ }
+}
+
+/// Extensions to the C++ standard library.
+namespace std
+{
+ /// Numeric limits for half-precision floats.
+ /// **See also:** Documentation for [std::numeric_limits](https://en.cppreference.com/w/cpp/types/numeric_limits)
+ template<> class numeric_limits<half_float::half>
+ {
+ public:
+ /// Is template specialization.
+ static HALF_CONSTEXPR_CONST bool is_specialized = true;
+
+ /// Supports signed values.
+ static HALF_CONSTEXPR_CONST bool is_signed = true;
+
+ /// Is not an integer type.
+ static HALF_CONSTEXPR_CONST bool is_integer = false;
+
+ /// Is not exact.
+ static HALF_CONSTEXPR_CONST bool is_exact = false;
+
+ /// Doesn't provide modulo arithmetic.
+ static HALF_CONSTEXPR_CONST bool is_modulo = false;
+
+ /// Has a finite set of values.
+ static HALF_CONSTEXPR_CONST bool is_bounded = true;
+
+ /// IEEE conformant.
+ static HALF_CONSTEXPR_CONST bool is_iec559 = true;
+
+ /// Supports infinity.
+ static HALF_CONSTEXPR_CONST bool has_infinity = true;
+
+ /// Supports quiet NaNs.
+ static HALF_CONSTEXPR_CONST bool has_quiet_NaN = true;
+
+ /// Supports signaling NaNs.
+ static HALF_CONSTEXPR_CONST bool has_signaling_NaN = true;
+
+ /// Supports subnormal values.
+ static HALF_CONSTEXPR_CONST float_denorm_style has_denorm = denorm_present;
+
+ /// Supports no denormalization detection.
+ static HALF_CONSTEXPR_CONST bool has_denorm_loss = false;
+
+ #if HALF_ERRHANDLING_THROWS
+ static HALF_CONSTEXPR_CONST bool traps = true;
+ #else
+ /// Traps only if [HALF_ERRHANDLING_THROW_...](\ref HALF_ERRHANDLING_THROW_INVALID) is acitvated.
+ static HALF_CONSTEXPR_CONST bool traps = false;
+ #endif
+
+ /// Does not support no pre-rounding underflow detection.
+ static HALF_CONSTEXPR_CONST bool tinyness_before = false;
+
+ /// Rounding mode.
+ static HALF_CONSTEXPR_CONST float_round_style round_style = half_float::half::round_style;
+
+ /// Significant digits.
+ static HALF_CONSTEXPR_CONST int digits = 11;
+
+ /// Significant decimal digits.
+ static HALF_CONSTEXPR_CONST int digits10 = 3;
+
+ /// Required decimal digits to represent all possible values.
+ static HALF_CONSTEXPR_CONST int max_digits10 = 5;
+
+ /// Number base.
+ static HALF_CONSTEXPR_CONST int radix = 2;
+
+ /// One more than smallest exponent.
+ static HALF_CONSTEXPR_CONST int min_exponent = -13;
+
+ /// Smallest normalized representable power of 10.
+ static HALF_CONSTEXPR_CONST int min_exponent10 = -4;
+
+ /// One more than largest exponent
+ static HALF_CONSTEXPR_CONST int max_exponent = 16;
+
+ /// Largest finitely representable power of 10.
+ static HALF_CONSTEXPR_CONST int max_exponent10 = 4;
+
+ /// Smallest positive normal value.
+ static HALF_CONSTEXPR half_float::half min() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x0400); }
+
+ /// Smallest finite value.
+ static HALF_CONSTEXPR half_float::half lowest() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0xFBFF); }
+
+ /// Largest finite value.
+ static HALF_CONSTEXPR half_float::half max() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x7BFF); }
+
+ /// Difference between 1 and next representable value.
+ static HALF_CONSTEXPR half_float::half epsilon() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x1400); }
+
+ /// Maximum rounding error in ULP (units in the last place).
+ static HALF_CONSTEXPR half_float::half round_error() HALF_NOTHROW
+ { return half_float::half(half_float::detail::binary, (round_style==std::round_to_nearest) ? 0x3800 : 0x3C00); }
+
+ /// Positive infinity.
+ static HALF_CONSTEXPR half_float::half infinity() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x7C00); }
+
+ /// Quiet NaN.
+ static HALF_CONSTEXPR half_float::half quiet_NaN() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x7FFF); }
+
+ /// Signaling NaN.
+ static HALF_CONSTEXPR half_float::half signaling_NaN() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x7DFF); }
+
+ /// Smallest positive subnormal value.
+ static HALF_CONSTEXPR half_float::half denorm_min() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x0001); }
+ };
+
+#if HALF_ENABLE_CPP11_HASH
+ /// Hash function for half-precision floats.
+ /// This is only defined if C++11 `std::hash` is supported and enabled.
+ ///
+ /// **See also:** Documentation for [std::hash](https://en.cppreference.com/w/cpp/utility/hash)
+ template<> struct hash<half_float::half>
+ {
+ /// Type of function argument.
+ typedef half_float::half argument_type;
+
+ /// Function return type.
+ typedef size_t result_type;
+
+ /// Compute hash function.
+ /// \param arg half to hash
+ /// \return hash value
+ result_type operator()(argument_type arg) const { return hash<half_float::detail::uint16>()(arg.data_&-static_cast<unsigned>(arg.data_!=0x8000)); }
+ };
+#endif
+}
+
+namespace half_float
+{
+ /// \anchor compop
+ /// \name Comparison operators
+ /// \{
+
+ /// Comparison for equality.
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if operands equal
+ /// \retval false else
+ /// \exception FE_INVALID if \a x or \a y is NaN
+ inline HALF_CONSTEXPR_NOERR bool operator==(half x, half y)
+ {
+ return !detail::compsignal(x.data_, y.data_) && (x.data_==y.data_ || !((x.data_|y.data_)&0x7FFF));
+ }
+
+ /// Comparison for inequality.
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if operands not equal
+ /// \retval false else
+ /// \exception FE_INVALID if \a x or \a y is NaN
+ inline HALF_CONSTEXPR_NOERR bool operator!=(half x, half y)
+ {
+ return detail::compsignal(x.data_, y.data_) || (x.data_!=y.data_ && ((x.data_|y.data_)&0x7FFF));
+ }
+
+ /// Comparison for less than.
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if \a x less than \a y
+ /// \retval false else
+ /// \exception FE_INVALID if \a x or \a y is NaN
+ inline HALF_CONSTEXPR_NOERR bool operator<(half x, half y)
+ {
+ return !detail::compsignal(x.data_, y.data_) &&
+ ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) < ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15));
+ }
+
+ /// Comparison for greater than.
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if \a x greater than \a y
+ /// \retval false else
+ /// \exception FE_INVALID if \a x or \a y is NaN
+ inline HALF_CONSTEXPR_NOERR bool operator>(half x, half y)
+ {
+ return !detail::compsignal(x.data_, y.data_) &&
+ ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) > ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15));
+ }
+
+ /// Comparison for less equal.
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if \a x less equal \a y
+ /// \retval false else
+ /// \exception FE_INVALID if \a x or \a y is NaN
+ inline HALF_CONSTEXPR_NOERR bool operator<=(half x, half y)
+ {
+ return !detail::compsignal(x.data_, y.data_) &&
+ ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) <= ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15));
+ }
+
+ /// Comparison for greater equal.
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if \a x greater equal \a y
+ /// \retval false else
+ /// \exception FE_INVALID if \a x or \a y is NaN
+ inline HALF_CONSTEXPR_NOERR bool operator>=(half x, half y)
+ {
+ return !detail::compsignal(x.data_, y.data_) &&
+ ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) >= ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15));
+ }
+
+ /// \}
+ /// \anchor arithmetics
+ /// \name Arithmetic operators
+ /// \{
+
+ /// Identity.
+ /// \param arg operand
+ /// \return unchanged operand
+ inline HALF_CONSTEXPR half operator+(half arg) { return arg; }
+
+ /// Negation.
+ /// \param arg operand
+ /// \return negated operand
+ inline HALF_CONSTEXPR half operator-(half arg) { return half(detail::binary, arg.data_^0x8000); }
+
+ /// Addition.
+ /// This operation is exact to rounding for all rounding modes.
+ /// \param x left operand
+ /// \param y right operand
+ /// \return sum of half expressions
+ /// \exception FE_INVALID if \a x and \a y are infinities with different signs or signaling NaNs
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half operator+(half x, half y)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(detail::half2float<detail::internal_t>(x.data_)+detail::half2float<detail::internal_t>(y.data_)));
+ #else
+ int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF;
+ bool sub = ((x.data_^y.data_)&0x8000) != 0;
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) : (absy!=0x7C00) ? x.data_ :
+ (sub && absx==0x7C00) ? detail::invalid() : y.data_);
+ if(!absx)
+ return absy ? y : half(detail::binary, (half::round_style==std::round_toward_neg_infinity) ? (x.data_|y.data_) : (x.data_&y.data_));
+ if(!absy)
+ return x;
+ unsigned int sign = ((sub && absy>absx) ? y.data_ : x.data_) & 0x8000;
+ if(absy > absx)
+ std::swap(absx, absy);
+ int exp = (absx>>10) + (absx<=0x3FF), d = exp - (absy>>10) - (absy<=0x3FF), mx = ((absx&0x3FF)|((absx>0x3FF)<<10)) << 3, my;
+ if(d < 13)
+ {
+ my = ((absy&0x3FF)|((absy>0x3FF)<<10)) << 3;
+ my = (my>>d) | ((my&((1<<d)-1))!=0);
+ }
+ else
+ my = 1;
+ if(sub)
+ {
+ if(!(mx-=my))
+ return half(detail::binary, static_cast<unsigned>(half::round_style==std::round_toward_neg_infinity)<<15);
+ for(; mx<0x2000 && exp>1; mx<<=1,--exp) ;
+ }
+ else
+ {
+ mx += my;
+ int i = mx >> 14;
+ if((exp+=i) > 30)
+ return half(detail::binary, detail::overflow<half::round_style>(sign));
+ mx = (mx>>i) | (mx&i);
+ }
+ return half(detail::binary, detail::rounded<half::round_style,false>(sign+((exp-1)<<10)+(mx>>3), (mx>>2)&1, (mx&0x3)!=0));
+ #endif
+ }
+
+ /// Subtraction.
+ /// This operation is exact to rounding for all rounding modes.
+ /// \param x left operand
+ /// \param y right operand
+ /// \return difference of half expressions
+ /// \exception FE_INVALID if \a x and \a y are infinities with equal signs or signaling NaNs
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half operator-(half x, half y)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(detail::half2float<detail::internal_t>(x.data_)-detail::half2float<detail::internal_t>(y.data_)));
+ #else
+ return x + -y;
+ #endif
+ }
+
+ /// Multiplication.
+ /// This operation is exact to rounding for all rounding modes.
+ /// \param x left operand
+ /// \param y right operand
+ /// \return product of half expressions
+ /// \exception FE_INVALID if multiplying 0 with infinity or if \a x or \a y is signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half operator*(half x, half y)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(detail::half2float<detail::internal_t>(x.data_)*detail::half2float<detail::internal_t>(y.data_)));
+ #else
+ int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, exp = -16;
+ unsigned int sign = (x.data_^y.data_) & 0x8000;
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) :
+ ((absx==0x7C00 && !absy)||(absy==0x7C00 && !absx)) ? detail::invalid() : (sign|0x7C00));
+ if(!absx || !absy)
+ return half(detail::binary, sign);
+ for(; absx<0x400; absx<<=1,--exp) ;
+ for(; absy<0x400; absy<<=1,--exp) ;
+ detail::uint32 m = static_cast<detail::uint32>((absx&0x3FF)|0x400) * static_cast<detail::uint32>((absy&0x3FF)|0x400);
+ int i = m >> 21, s = m & i;
+ exp += (absx>>10) + (absy>>10) + i;
+ if(exp > 29)
+ return half(detail::binary, detail::overflow<half::round_style>(sign));
+ else if(exp < -11)
+ return half(detail::binary, detail::underflow<half::round_style>(sign));
+ return half(detail::binary, detail::fixed2half<half::round_style,20,false,false,false>(m>>i, exp, sign, s));
+ #endif
+ }
+
+ /// Division.
+ /// This operation is exact to rounding for all rounding modes.
+ /// \param x left operand
+ /// \param y right operand
+ /// \return quotient of half expressions
+ /// \exception FE_INVALID if dividing 0s or infinities with each other or if \a x or \a y is signaling NaN
+ /// \exception FE_DIVBYZERO if dividing finite value by 0
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half operator/(half x, half y)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(detail::half2float<detail::internal_t>(x.data_)/detail::half2float<detail::internal_t>(y.data_)));
+ #else
+ int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, exp = 14;
+ unsigned int sign = (x.data_^y.data_) & 0x8000;
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) :
+ (absx==absy) ? detail::invalid() : (sign|((absx==0x7C00) ? 0x7C00 : 0)));
+ if(!absx)
+ return half(detail::binary, absy ? sign : detail::invalid());
+ if(!absy)
+ return half(detail::binary, detail::pole(sign));
+ for(; absx<0x400; absx<<=1,--exp) ;
+ for(; absy<0x400; absy<<=1,++exp) ;
+ detail::uint32 mx = (absx&0x3FF) | 0x400, my = (absy&0x3FF) | 0x400;
+ int i = mx < my;
+ exp += (absx>>10) - (absy>>10) - i;
+ if(exp > 29)
+ return half(detail::binary, detail::overflow<half::round_style>(sign));
+ else if(exp < -11)
+ return half(detail::binary, detail::underflow<half::round_style>(sign));
+ mx <<= 12 + i;
+ my <<= 1;
+ return half(detail::binary, detail::fixed2half<half::round_style,11,false,false,false>(mx/my, exp, sign, mx%my!=0));
+ #endif
+ }
+
+ /// \}
+ /// \anchor streaming
+ /// \name Input and output
+ /// \{
+
+ /// Output operator.
+ /// This uses the built-in functionality for streaming out floating-point numbers.
+ /// \param out output stream to write into
+ /// \param arg half expression to write
+ /// \return reference to output stream
+ template<typename charT,typename traits> std::basic_ostream<charT,traits>& operator<<(std::basic_ostream<charT,traits> &out, half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return out << detail::half2float<detail::internal_t>(arg.data_);
+ #else
+ return out << detail::half2float<float>(arg.data_);
+ #endif
+ }
+
+ /// Input operator.
+ /// This uses the built-in functionality for streaming in floating-point numbers, specifically double precision floating
+ /// point numbers (unless overridden with [HALF_ARITHMETIC_TYPE](\ref HALF_ARITHMETIC_TYPE)). So the input string is first
+ /// rounded to double precision using the underlying platform's current floating-point rounding mode before being rounded
+ /// to half-precision using the library's half-precision rounding mode.
+ /// \param in input stream to read from
+ /// \param arg half to read into
+ /// \return reference to input stream
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ template<typename charT,typename traits> std::basic_istream<charT,traits>& operator>>(std::basic_istream<charT,traits> &in, half &arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ detail::internal_t f;
+ #else
+ double f;
+ #endif
+ if(in >> f)
+ arg.data_ = detail::float2half<half::round_style>(f);
+ return in;
+ }
+
+ /// \}
+ /// \anchor basic
+ /// \name Basic mathematical operations
+ /// \{
+
+ /// Absolute value.
+ /// **See also:** Documentation for [std::fabs](https://en.cppreference.com/w/cpp/numeric/math/fabs).
+ /// \param arg operand
+ /// \return absolute value of \a arg
+ inline HALF_CONSTEXPR half fabs(half arg) { return half(detail::binary, arg.data_&0x7FFF); }
+
+ /// Absolute value.
+ /// **See also:** Documentation for [std::abs](https://en.cppreference.com/w/cpp/numeric/math/fabs).
+ /// \param arg operand
+ /// \return absolute value of \a arg
+ inline HALF_CONSTEXPR half abs(half arg) { return fabs(arg); }
+
+ /// Remainder of division.
+ /// **See also:** Documentation for [std::fmod](https://en.cppreference.com/w/cpp/numeric/math/fmod).
+ /// \param x first operand
+ /// \param y second operand
+ /// \return remainder of floating-point division.
+ /// \exception FE_INVALID if \a x is infinite or \a y is 0 or if \a x or \a y is signaling NaN
+ inline half fmod(half x, half y)
+ {
+ unsigned int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, sign = x.data_ & 0x8000;
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) :
+ (absx==0x7C00) ? detail::invalid() : x.data_);
+ if(!absy)
+ return half(detail::binary, detail::invalid());
+ if(!absx)
+ return x;
+ if(absx == absy)
+ return half(detail::binary, sign);
+ return half(detail::binary, sign|detail::mod<false,false>(absx, absy));
+ }
+
+ /// Remainder of division.
+ /// **See also:** Documentation for [std::remainder](https://en.cppreference.com/w/cpp/numeric/math/remainder).
+ /// \param x first operand
+ /// \param y second operand
+ /// \return remainder of floating-point division.
+ /// \exception FE_INVALID if \a x is infinite or \a y is 0 or if \a x or \a y is signaling NaN
+ inline half remainder(half x, half y)
+ {
+ unsigned int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, sign = x.data_ & 0x8000;
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) :
+ (absx==0x7C00) ? detail::invalid() : x.data_);
+ if(!absy)
+ return half(detail::binary, detail::invalid());
+ if(absx == absy)
+ return half(detail::binary, sign);
+ return half(detail::binary, sign^detail::mod<false,true>(absx, absy));
+ }
+
+ /// Remainder of division.
+ /// **See also:** Documentation for [std::remquo](https://en.cppreference.com/w/cpp/numeric/math/remquo).
+ /// \param x first operand
+ /// \param y second operand
+ /// \param quo address to store some bits of quotient at
+ /// \return remainder of floating-point division.
+ /// \exception FE_INVALID if \a x is infinite or \a y is 0 or if \a x or \a y is signaling NaN
+ inline half remquo(half x, half y, int *quo)
+ {
+ unsigned int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, value = x.data_ & 0x8000;
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) :
+ (absx==0x7C00) ? detail::invalid() : (*quo = 0, x.data_));
+ if(!absy)
+ return half(detail::binary, detail::invalid());
+ bool qsign = ((value^y.data_)&0x8000) != 0;
+ int q = 1;
+ if(absx != absy)
+ value ^= detail::mod<true, true>(absx, absy, &q);
+ return *quo = qsign ? -q : q, half(detail::binary, value);
+ }
+
+ /// Fused multiply add.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::fma](https://en.cppreference.com/w/cpp/numeric/math/fma).
+ /// \param x first operand
+ /// \param y second operand
+ /// \param z third operand
+ /// \return ( \a x * \a y ) + \a z rounded as one operation.
+ /// \exception FE_INVALID according to operator*() and operator+() unless any argument is a quiet NaN and no argument is a signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding the final addition
+ inline half fma(half x, half y, half z)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ detail::internal_t fx = detail::half2float<detail::internal_t>(x.data_), fy = detail::half2float<detail::internal_t>(y.data_), fz = detail::half2float<detail::internal_t>(z.data_);
+ #if HALF_ENABLE_CPP11_CMATH && FP_FAST_FMA
+ return half(detail::binary, detail::float2half<half::round_style>(std::fma(fx, fy, fz)));
+ #else
+ return half(detail::binary, detail::float2half<half::round_style>(fx*fy+fz));
+ #endif
+ #else
+ int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, absz = z.data_ & 0x7FFF, exp = -15;
+ unsigned int sign = (x.data_^y.data_) & 0x8000;
+ bool sub = ((sign^z.data_)&0x8000) != 0;
+ if(absx >= 0x7C00 || absy >= 0x7C00 || absz >= 0x7C00)
+ return (absx>0x7C00 || absy>0x7C00 || absz>0x7C00) ? half(detail::binary, detail::signal(x.data_, y.data_, z.data_)) :
+ (absx==0x7C00) ? half(detail::binary, (!absy || (sub && absz==0x7C00)) ? detail::invalid() : (sign|0x7C00)) :
+ (absy==0x7C00) ? half(detail::binary, (!absx || (sub && absz==0x7C00)) ? detail::invalid() : (sign|0x7C00)) : z;
+ if(!absx || !absy)
+ return absz ? z : half(detail::binary, (half::round_style==std::round_toward_neg_infinity) ? (z.data_|sign) : (z.data_&sign));
+ for(; absx<0x400; absx<<=1,--exp) ;
+ for(; absy<0x400; absy<<=1,--exp) ;
+ detail::uint32 m = static_cast<detail::uint32>((absx&0x3FF)|0x400) * static_cast<detail::uint32>((absy&0x3FF)|0x400);
+ int i = m >> 21;
+ exp += (absx>>10) + (absy>>10) + i;
+ m <<= 3 - i;
+ if(absz)
+ {
+ int expz = 0;
+ for(; absz<0x400; absz<<=1,--expz) ;
+ expz += absz >> 10;
+ detail::uint32 mz = static_cast<detail::uint32>((absz&0x3FF)|0x400) << 13;
+ if(expz > exp || (expz == exp && mz > m))
+ {
+ std::swap(m, mz);
+ std::swap(exp, expz);
+ if(sub)
+ sign = z.data_ & 0x8000;
+ }
+ int d = exp - expz;
+ mz = (d<23) ? ((mz>>d)|((mz&((static_cast<detail::uint32>(1)<<d)-1))!=0)) : 1;
+ if(sub)
+ {
+ m = m - mz;
+ if(!m)
+ return half(detail::binary, static_cast<unsigned>(half::round_style==std::round_toward_neg_infinity)<<15);
+ for(; m<0x800000; m<<=1,--exp) ;
+ }
+ else
+ {
+ m += mz;
+ i = m >> 24;
+ m = (m>>i) | (m&i);
+ exp += i;
+ }
+ }
+ if(exp > 30)
+ return half(detail::binary, detail::overflow<half::round_style>(sign));
+ else if(exp < -10)
+ return half(detail::binary, detail::underflow<half::round_style>(sign));
+ return half(detail::binary, detail::fixed2half<half::round_style,23,false,false,false>(m, exp-1, sign));
+ #endif
+ }
+
+ /// Maximum of half expressions.
+ /// **See also:** Documentation for [std::fmax](https://en.cppreference.com/w/cpp/numeric/math/fmax).
+ /// \param x first operand
+ /// \param y second operand
+ /// \return maximum of operands, ignoring quiet NaNs
+ /// \exception FE_INVALID if \a x or \a y is signaling NaN
+ inline HALF_CONSTEXPR_NOERR half fmax(half x, half y)
+ {
+ return half(detail::binary, (!isnan(y) && (isnan(x) || (x.data_^(0x8000|(0x8000-(x.data_>>15)))) <
+ (y.data_^(0x8000|(0x8000-(y.data_>>15)))))) ? detail::select(y.data_, x.data_) : detail::select(x.data_, y.data_));
+ }
+
+ /// Minimum of half expressions.
+ /// **See also:** Documentation for [std::fmin](https://en.cppreference.com/w/cpp/numeric/math/fmin).
+ /// \param x first operand
+ /// \param y second operand
+ /// \return minimum of operands, ignoring quiet NaNs
+ /// \exception FE_INVALID if \a x or \a y is signaling NaN
+ inline HALF_CONSTEXPR_NOERR half fmin(half x, half y)
+ {
+ return half(detail::binary, (!isnan(y) && (isnan(x) || (x.data_^(0x8000|(0x8000-(x.data_>>15)))) >
+ (y.data_^(0x8000|(0x8000-(y.data_>>15)))))) ? detail::select(y.data_, x.data_) : detail::select(x.data_, y.data_));
+ }
+
+ /// Positive difference.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::fdim](https://en.cppreference.com/w/cpp/numeric/math/fdim).
+ /// \param x first operand
+ /// \param y second operand
+ /// \return \a x - \a y or 0 if difference negative
+ /// \exception FE_... according to operator-(half,half)
+ inline half fdim(half x, half y)
+ {
+ if(isnan(x) || isnan(y))
+ return half(detail::binary, detail::signal(x.data_, y.data_));
+ return (x.data_^(0x8000|(0x8000-(x.data_>>15)))) <= (y.data_^(0x8000|(0x8000-(y.data_>>15)))) ? half(detail::binary, 0) : (x-y);
+ }
+
+ /// Get NaN value.
+ /// **See also:** Documentation for [std::nan](https://en.cppreference.com/w/cpp/numeric/math/nan).
+ /// \param arg string code
+ /// \return quiet NaN
+ inline half nanh(const char *arg)
+ {
+ unsigned int value = 0x7FFF;
+ while(*arg)
+ value ^= static_cast<unsigned>(*arg++) & 0xFF;
+ return half(detail::binary, value);
+ }
+
+ /// \}
+ /// \anchor exponential
+ /// \name Exponential functions
+ /// \{
+
+ /// Exponential function.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::exp](https://en.cppreference.com/w/cpp/numeric/math/exp).
+ /// \param arg function argument
+ /// \return e raised to \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half exp(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::exp(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF;
+ if(!abs)
+ return half(detail::binary, 0x3C00);
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? (0x7C00&((arg.data_>>15)-1U)) : detail::signal(arg.data_));
+ if(abs >= 0x4C80)
+ return half(detail::binary, (arg.data_&0x8000) ? detail::underflow<half::round_style>() : detail::overflow<half::round_style>());
+ detail::uint32 m = detail::multiply64(static_cast<detail::uint32>((abs&0x3FF)+((abs>0x3FF)<<10))<<21, 0xB8AA3B29);
+ int e = (abs>>10) + (abs<=0x3FF), exp;
+ if(e < 14)
+ {
+ exp = 0;
+ m >>= 14 - e;
+ }
+ else
+ {
+ exp = m >> (45-e);
+ m = (m<<(e-14)) & 0x7FFFFFFF;
+ }
+ return half(detail::binary, detail::exp2_post<half::round_style,true>(detail::exp2(m, 26), exp, (arg.data_&0x8000)!=0));
+ #endif
+ }
+
+ /// Binary exponential.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::exp2](https://en.cppreference.com/w/cpp/numeric/math/exp2).
+ /// \param arg function argument
+ /// \return 2 raised to \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half exp2(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::exp2(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF;
+ if(!abs)
+ return half(detail::binary, 0x3C00);
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? (0x7C00&((arg.data_>>15)-1U)) : detail::signal(arg.data_));
+ if(abs >= 0x4E40)
+ return half(detail::binary, (arg.data_&0x8000) ? detail::underflow<half::round_style>() : detail::overflow<half::round_style>());
+ int e = (abs>>10) + (abs<=0x3FF), exp = (abs&0x3FF) + ((abs>0x3FF)<<10);
+ detail::uint32 m = detail::exp2((static_cast<detail::uint32>(exp)<<(6+e))&0x7FFFFFFF, 28);
+ exp >>= 25 - e;
+ if(m == 0x80000000)
+ {
+ if(arg.data_&0x8000)
+ exp = -exp;
+ else if(exp > 15)
+ return half(detail::binary, detail::overflow<half::round_style>());
+ return half(detail::binary, detail::fixed2half<half::round_style,31,false,false,false>(m, exp+14));
+ }
+ return half(detail::binary, detail::exp2_post<half::round_style,true>(m, exp, (arg.data_&0x8000)!=0));
+ #endif
+ }
+
+ /// Exponential minus one.
+ /// This function may be 1 ULP off the correctly rounded exact result in <0.05% of inputs for `std::round_to_nearest`
+ /// and in <1% of inputs for any other rounding mode.
+ ///
+ /// **See also:** Documentation for [std::expm1](https://en.cppreference.com/w/cpp/numeric/math/expm1).
+ /// \param arg function argument
+ /// \return e raised to \a arg and subtracted by 1
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half expm1(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::expm1(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000;
+ if(!abs)
+ return arg;
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? (0x7C00+(sign>>1)) : detail::signal(arg.data_));
+ if(abs >= 0x4A00)
+ return half(detail::binary, (arg.data_&0x8000) ? detail::rounded<half::round_style,true>(0xBBFF, 1, 1) : detail::overflow<half::round_style>());
+ detail::uint32 m = detail::multiply64(static_cast<detail::uint32>((abs&0x3FF)+((abs>0x3FF)<<10))<<21, 0xB8AA3B29);
+ int e = (abs>>10) + (abs<=0x3FF), exp;
+ if(e < 14)
+ {
+ exp = 0;
+ m >>= 14 - e;
+ }
+ else
+ {
+ exp = m >> (45-e);
+ m = (m<<(e-14)) & 0x7FFFFFFF;
+ }
+ m = detail::exp2(m);
+ if(sign)
+ {
+ int s = 0;
+ if(m > 0x80000000)
+ {
+ ++exp;
+ m = detail::divide64(0x80000000, m, s);
+ }
+ m = 0x80000000 - ((m>>exp)|((m&((static_cast<detail::uint32>(1)<<exp)-1))!=0)|s);
+ exp = 0;
+ }
+ else
+ m -= (exp<31) ? (0x80000000>>exp) : 1;
+ for(exp+=14; m<0x80000000 && exp; m<<=1,--exp) ;
+ if(exp > 29)
+ return half(detail::binary, detail::overflow<half::round_style>());
+ return half(detail::binary, detail::rounded<half::round_style,true>(sign+(exp<<10)+(m>>21), (m>>20)&1, (m&0xFFFFF)!=0));
+ #endif
+ }
+
+ /// Natural logarithm.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::log](https://en.cppreference.com/w/cpp/numeric/math/log).
+ /// \param arg function argument
+ /// \return logarithm of \a arg to base e
+ /// \exception FE_INVALID for signaling NaN or negative argument
+ /// \exception FE_DIVBYZERO for 0
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half log(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::log(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp = -15;
+ if(!abs)
+ return half(detail::binary, detail::pole(0x8000));
+ if(arg.data_ & 0x8000)
+ return half(detail::binary, (arg.data_<=0xFC00) ? detail::invalid() : detail::signal(arg.data_));
+ if(abs >= 0x7C00)
+ return (abs==0x7C00) ? arg : half(detail::binary, detail::signal(arg.data_));
+ for(; abs<0x400; abs<<=1,--exp) ;
+ exp += abs >> 10;
+ return half(detail::binary, detail::log2_post<half::round_style,0xB8AA3B2A>(
+ detail::log2(static_cast<detail::uint32>((abs&0x3FF)|0x400)<<20, 27)+8, exp, 17));
+ #endif
+ }
+
+ /// Common logarithm.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::log10](https://en.cppreference.com/w/cpp/numeric/math/log10).
+ /// \param arg function argument
+ /// \return logarithm of \a arg to base 10
+ /// \exception FE_INVALID for signaling NaN or negative argument
+ /// \exception FE_DIVBYZERO for 0
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half log10(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::log10(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp = -15;
+ if(!abs)
+ return half(detail::binary, detail::pole(0x8000));
+ if(arg.data_ & 0x8000)
+ return half(detail::binary, (arg.data_<=0xFC00) ? detail::invalid() : detail::signal(arg.data_));
+ if(abs >= 0x7C00)
+ return (abs==0x7C00) ? arg : half(detail::binary, detail::signal(arg.data_));
+ switch(abs)
+ {
+ case 0x4900: return half(detail::binary, 0x3C00);
+ case 0x5640: return half(detail::binary, 0x4000);
+ case 0x63D0: return half(detail::binary, 0x4200);
+ case 0x70E2: return half(detail::binary, 0x4400);
+ }
+ for(; abs<0x400; abs<<=1,--exp) ;
+ exp += abs >> 10;
+ return half(detail::binary, detail::log2_post<half::round_style,0xD49A784C>(
+ detail::log2(static_cast<detail::uint32>((abs&0x3FF)|0x400)<<20, 27)+8, exp, 16));
+ #endif
+ }
+
+ /// Binary logarithm.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::log2](https://en.cppreference.com/w/cpp/numeric/math/log2).
+ /// \param arg function argument
+ /// \return logarithm of \a arg to base 2
+ /// \exception FE_INVALID for signaling NaN or negative argument
+ /// \exception FE_DIVBYZERO for 0
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half log2(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::log2(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp = -15, s = 0;
+ if(!abs)
+ return half(detail::binary, detail::pole(0x8000));
+ if(arg.data_ & 0x8000)
+ return half(detail::binary, (arg.data_<=0xFC00) ? detail::invalid() : detail::signal(arg.data_));
+ if(abs >= 0x7C00)
+ return (abs==0x7C00) ? arg : half(detail::binary, detail::signal(arg.data_));
+ if(abs == 0x3C00)
+ return half(detail::binary, 0);
+ for(; abs<0x400; abs<<=1,--exp) ;
+ exp += (abs>>10);
+ if(!(abs&0x3FF))
+ {
+ unsigned int value = static_cast<unsigned>(exp<0) << 15, m = std::abs(exp) << 6;
+ for(exp=18; m<0x400; m<<=1,--exp) ;
+ return half(detail::binary, value+(exp<<10)+m);
+ }
+ detail::uint32 ilog = exp, sign = detail::sign_mask(ilog), m =
+ (((ilog<<27)+(detail::log2(static_cast<detail::uint32>((abs&0x3FF)|0x400)<<20, 28)>>4))^sign) - sign;
+ if(!m)
+ return half(detail::binary, 0);
+ for(exp=14; m<0x8000000 && exp; m<<=1,--exp) ;
+ for(; m>0xFFFFFFF; m>>=1,++exp)
+ s |= m & 1;
+ return half(detail::binary, detail::fixed2half<half::round_style,27,false,false,true>(m, exp, sign&0x8000, s));
+ #endif
+ }
+
+ /// Natural logarithm plus one.
+ /// This function may be 1 ULP off the correctly rounded exact result in <0.05% of inputs for `std::round_to_nearest`
+ /// and in ~1% of inputs for any other rounding mode.
+ ///
+ /// **See also:** Documentation for [std::log1p](https://en.cppreference.com/w/cpp/numeric/math/log1p).
+ /// \param arg function argument
+ /// \return logarithm of \a arg plus 1 to base e
+ /// \exception FE_INVALID for signaling NaN or argument <-1
+ /// \exception FE_DIVBYZERO for -1
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half log1p(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::log1p(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ if(arg.data_ >= 0xBC00)
+ return half(detail::binary, (arg.data_==0xBC00) ? detail::pole(0x8000) : (arg.data_<=0xFC00) ? detail::invalid() : detail::signal(arg.data_));
+ int abs = arg.data_ & 0x7FFF, exp = -15;
+ if(!abs || abs >= 0x7C00)
+ return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg;
+ for(; abs<0x400; abs<<=1,--exp) ;
+ exp += abs >> 10;
+ detail::uint32 m = static_cast<detail::uint32>((abs&0x3FF)|0x400) << 20;
+ if(arg.data_ & 0x8000)
+ {
+ m = 0x40000000 - (m>>-exp);
+ for(exp=0; m<0x40000000; m<<=1,--exp) ;
+ }
+ else
+ {
+ if(exp < 0)
+ {
+ m = 0x40000000 + (m>>-exp);
+ exp = 0;
+ }
+ else
+ {
+ m += 0x40000000 >> exp;
+ int i = m >> 31;
+ m >>= i;
+ exp += i;
+ }
+ }
+ return half(detail::binary, detail::log2_post<half::round_style,0xB8AA3B2A>(detail::log2(m), exp, 17));
+ #endif
+ }
+
+ /// \}
+ /// \anchor power
+ /// \name Power functions
+ /// \{
+
+ /// Square root.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::sqrt](https://en.cppreference.com/w/cpp/numeric/math/sqrt).
+ /// \param arg function argument
+ /// \return square root of \a arg
+ /// \exception FE_INVALID for signaling NaN and negative arguments
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half sqrt(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::sqrt(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp = 15;
+ if(!abs || arg.data_ >= 0x7C00)
+ return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : (arg.data_>0x8000) ? detail::invalid() : arg.data_);
+ for(; abs<0x400; abs<<=1,--exp) ;
+ detail::uint32 r = static_cast<detail::uint32>((abs&0x3FF)|0x400) << 10, m = detail::sqrt<20>(r, exp+=abs>>10);
+ return half(detail::binary, detail::rounded<half::round_style,false>((exp<<10)+(m&0x3FF), r>m, r!=0));
+ #endif
+ }
+
+ /// Cubic root.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::cbrt](https://en.cppreference.com/w/cpp/numeric/math/cbrt).
+ /// \param arg function argument
+ /// \return cubic root of \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half cbrt(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::cbrt(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp = -15;
+ if(!abs || abs == 0x3C00 || abs >= 0x7C00)
+ return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg;
+ for(; abs<0x400; abs<<=1, --exp);
+ detail::uint32 ilog = exp + (abs>>10), sign = detail::sign_mask(ilog), f, m =
+ (((ilog<<27)+(detail::log2(static_cast<detail::uint32>((abs&0x3FF)|0x400)<<20, 24)>>4))^sign) - sign;
+ for(exp=2; m<0x80000000; m<<=1,--exp) ;
+ m = detail::multiply64(m, 0xAAAAAAAB);
+ int i = m >> 31, s;
+ exp += i;
+ m <<= 1 - i;
+ if(exp < 0)
+ {
+ f = m >> -exp;
+ exp = 0;
+ }
+ else
+ {
+ f = (m<<exp) & 0x7FFFFFFF;
+ exp = m >> (31-exp);
+ }
+ m = detail::exp2(f, (half::round_style==std::round_to_nearest) ? 29 : 26);
+ if(sign)
+ {
+ if(m > 0x80000000)
+ {
+ m = detail::divide64(0x80000000, m, s);
+ ++exp;
+ }
+ exp = -exp;
+ }
+ return half(detail::binary, (half::round_style==std::round_to_nearest) ?
+ detail::fixed2half<half::round_style,31,false,false,false>(m, exp+14, arg.data_&0x8000) :
+ detail::fixed2half<half::round_style,23,false,false,false>((m+0x80)>>8, exp+14, arg.data_&0x8000));
+ #endif
+ }
+
+ /// Hypotenuse function.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::hypot](https://en.cppreference.com/w/cpp/numeric/math/hypot).
+ /// \param x first argument
+ /// \param y second argument
+ /// \return square root of sum of squares without internal over- or underflows
+ /// \exception FE_INVALID if \a x or \a y is signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding of the final square root
+ inline half hypot(half x, half y)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ detail::internal_t fx = detail::half2float<detail::internal_t>(x.data_), fy = detail::half2float<detail::internal_t>(y.data_);
+ #if HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::hypot(fx, fy)));
+ #else
+ return half(detail::binary, detail::float2half<half::round_style>(std::sqrt(fx*fx+fy*fy)));
+ #endif
+ #else
+ int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, expx = 0, expy = 0;
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ return half(detail::binary, (absx==0x7C00) ? detail::select(0x7C00, y.data_) :
+ (absy==0x7C00) ? detail::select(0x7C00, x.data_) : detail::signal(x.data_, y.data_));
+ if(!absx)
+ return half(detail::binary, absy ? detail::check_underflow(absy) : 0);
+ if(!absy)
+ return half(detail::binary, detail::check_underflow(absx));
+ if(absy > absx)
+ std::swap(absx, absy);
+ for(; absx<0x400; absx<<=1,--expx) ;
+ for(; absy<0x400; absy<<=1,--expy) ;
+ detail::uint32 mx = (absx&0x3FF) | 0x400, my = (absy&0x3FF) | 0x400;
+ mx *= mx;
+ my *= my;
+ int ix = mx >> 21, iy = my >> 21;
+ expx = 2*(expx+(absx>>10)) - 15 + ix;
+ expy = 2*(expy+(absy>>10)) - 15 + iy;
+ mx <<= 10 - ix;
+ my <<= 10 - iy;
+ int d = expx - expy;
+ my = (d<30) ? ((my>>d)|((my&((static_cast<detail::uint32>(1)<<d)-1))!=0)) : 1;
+ return half(detail::binary, detail::hypot_post<half::round_style>(mx+my, expx));
+ #endif
+ }
+
+ /// Hypotenuse function.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::hypot](https://en.cppreference.com/w/cpp/numeric/math/hypot).
+ /// \param x first argument
+ /// \param y second argument
+ /// \param z third argument
+ /// \return square root of sum of squares without internal over- or underflows
+ /// \exception FE_INVALID if \a x, \a y or \a z is signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding of the final square root
+ inline half hypot(half x, half y, half z)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ detail::internal_t fx = detail::half2float<detail::internal_t>(x.data_), fy = detail::half2float<detail::internal_t>(y.data_), fz = detail::half2float<detail::internal_t>(z.data_);
+ return half(detail::binary, detail::float2half<half::round_style>(std::sqrt(fx*fx+fy*fy+fz*fz)));
+ #else
+ int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, absz = z.data_ & 0x7FFF, expx = 0, expy = 0, expz = 0;
+ if(!absx)
+ return hypot(y, z);
+ if(!absy)
+ return hypot(x, z);
+ if(!absz)
+ return hypot(x, y);
+ if(absx >= 0x7C00 || absy >= 0x7C00 || absz >= 0x7C00)
+ return half(detail::binary, (absx==0x7C00) ? detail::select(0x7C00, detail::select(y.data_, z.data_)) :
+ (absy==0x7C00) ? detail::select(0x7C00, detail::select(x.data_, z.data_)) :
+ (absz==0x7C00) ? detail::select(0x7C00, detail::select(x.data_, y.data_)) :
+ detail::signal(x.data_, y.data_, z.data_));
+ if(absz > absy)
+ std::swap(absy, absz);
+ if(absy > absx)
+ std::swap(absx, absy);
+ if(absz > absy)
+ std::swap(absy, absz);
+ for(; absx<0x400; absx<<=1,--expx) ;
+ for(; absy<0x400; absy<<=1,--expy) ;
+ for(; absz<0x400; absz<<=1,--expz) ;
+ detail::uint32 mx = (absx&0x3FF) | 0x400, my = (absy&0x3FF) | 0x400, mz = (absz&0x3FF) | 0x400;
+ mx *= mx;
+ my *= my;
+ mz *= mz;
+ int ix = mx >> 21, iy = my >> 21, iz = mz >> 21;
+ expx = 2*(expx+(absx>>10)) - 15 + ix;
+ expy = 2*(expy+(absy>>10)) - 15 + iy;
+ expz = 2*(expz+(absz>>10)) - 15 + iz;
+ mx <<= 10 - ix;
+ my <<= 10 - iy;
+ mz <<= 10 - iz;
+ int d = expy - expz;
+ mz = (d<30) ? ((mz>>d)|((mz&((static_cast<detail::uint32>(1)<<d)-1))!=0)) : 1;
+ my += mz;
+ if(my & 0x80000000)
+ {
+ my = (my>>1) | (my&1);
+ if(++expy > expx)
+ {
+ std::swap(mx, my);
+ std::swap(expx, expy);
+ }
+ }
+ d = expx - expy;
+ my = (d<30) ? ((my>>d)|((my&((static_cast<detail::uint32>(1)<<d)-1))!=0)) : 1;
+ return half(detail::binary, detail::hypot_post<half::round_style>(mx+my, expx));
+ #endif
+ }
+
+ /// Power function.
+ /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in ~0.00025% of inputs.
+ ///
+ /// **See also:** Documentation for [std::pow](https://en.cppreference.com/w/cpp/numeric/math/pow).
+ /// \param x base
+ /// \param y exponent
+ /// \return \a x raised to \a y
+ /// \exception FE_INVALID if \a x or \a y is signaling NaN or if \a x is finite an negative and \a y is finite and not integral
+ /// \exception FE_DIVBYZERO if \a x is 0 and \a y is negative
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half pow(half x, half y)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::pow(detail::half2float<detail::internal_t>(x.data_), detail::half2float<detail::internal_t>(y.data_))));
+ #else
+ int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, exp = -15;
+ if(!absy || x.data_ == 0x3C00)
+ return half(detail::binary, detail::select(0x3C00, (x.data_==0x3C00) ? y.data_ : x.data_));
+ bool is_int = absy >= 0x6400 || (absy>=0x3C00 && !(absy&((1<<(25-(absy>>10)))-1)));
+ unsigned int sign = x.data_ & (static_cast<unsigned>((absy<0x6800)&&is_int&&((absy>>(25-(absy>>10)))&1))<<15);
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) :
+ (absy==0x7C00) ? ((absx==0x3C00) ? 0x3C00 : (!absx && y.data_==0xFC00) ? detail::pole() :
+ (0x7C00&-((y.data_>>15)^(absx>0x3C00)))) : (sign|(0x7C00&((y.data_>>15)-1U))));
+ if(!absx)
+ return half(detail::binary, (y.data_&0x8000) ? detail::pole(sign) : sign);
+ if((x.data_&0x8000) && !is_int)
+ return half(detail::binary, detail::invalid());
+ if(x.data_ == 0xBC00)
+ return half(detail::binary, sign|0x3C00);
+ if(y.data_ == 0x3800)
+ return sqrt(x);
+ if(y.data_ == 0x3C00)
+ return half(detail::binary, detail::check_underflow(x.data_));
+ if(y.data_ == 0x4000)
+ return x * x;
+ for(; absx<0x400; absx<<=1,--exp) ;
+ detail::uint32 ilog = exp + (absx>>10), msign = detail::sign_mask(ilog), f, m =
+ (((ilog<<27)+((detail::log2(static_cast<detail::uint32>((absx&0x3FF)|0x400)<<20)+8)>>4))^msign) - msign;
+ for(exp=-11; m<0x80000000; m<<=1,--exp) ;
+ for(; absy<0x400; absy<<=1,--exp) ;
+ m = detail::multiply64(m, static_cast<detail::uint32>((absy&0x3FF)|0x400)<<21);
+ int i = m >> 31;
+ exp += (absy>>10) + i;
+ m <<= 1 - i;
+ if(exp < 0)
+ {
+ f = m >> -exp;
+ exp = 0;
+ }
+ else
+ {
+ f = (m<<exp) & 0x7FFFFFFF;
+ exp = m >> (31-exp);
+ }
+ return half(detail::binary, detail::exp2_post<half::round_style,false>(detail::exp2(f), exp, ((msign&1)^(y.data_>>15))!=0, sign));
+ #endif
+ }
+
+ /// \}
+ /// \anchor trigonometric
+ /// \name Trigonometric functions
+ /// \{
+
+ /// Compute sine and cosine simultaneously.
+ /// This returns the same results as sin() and cos() but is faster than calling each function individually.
+ ///
+ /// This function is exact to rounding for all rounding modes.
+ /// \param arg function argument
+ /// \param sin variable to take sine of \a arg
+ /// \param cos variable to take cosine of \a arg
+ /// \exception FE_INVALID for signaling NaN or infinity
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline void sincos(half arg, half *sin, half *cos)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ detail::internal_t f = detail::half2float<detail::internal_t>(arg.data_);
+ *sin = half(detail::binary, detail::float2half<half::round_style>(std::sin(f)));
+ *cos = half(detail::binary, detail::float2half<half::round_style>(std::cos(f)));
+ #else
+ int abs = arg.data_ & 0x7FFF, sign = arg.data_ >> 15, k;
+ if(abs >= 0x7C00)
+ *sin = *cos = half(detail::binary, (abs==0x7C00) ? detail::invalid() : detail::signal(arg.data_));
+ else if(!abs)
+ {
+ *sin = arg;
+ *cos = half(detail::binary, 0x3C00);
+ }
+ else if(abs < 0x2500)
+ {
+ *sin = half(detail::binary, detail::rounded<half::round_style,true>(arg.data_-1, 1, 1));
+ *cos = half(detail::binary, detail::rounded<half::round_style,true>(0x3BFF, 1, 1));
+ }
+ else
+ {
+ if(half::round_style != std::round_to_nearest)
+ {
+ switch(abs)
+ {
+ case 0x48B7:
+ *sin = half(detail::binary, detail::rounded<half::round_style,true>((~arg.data_&0x8000)|0x1D07, 1, 1));
+ *cos = half(detail::binary, detail::rounded<half::round_style,true>(0xBBFF, 1, 1));
+ return;
+ case 0x598C:
+ *sin = half(detail::binary, detail::rounded<half::round_style,true>((arg.data_&0x8000)|0x3BFF, 1, 1));
+ *cos = half(detail::binary, detail::rounded<half::round_style,true>(0x80FC, 1, 1));
+ return;
+ case 0x6A64:
+ *sin = half(detail::binary, detail::rounded<half::round_style,true>((~arg.data_&0x8000)|0x3BFE, 1, 1));
+ *cos = half(detail::binary, detail::rounded<half::round_style,true>(0x27FF, 1, 1));
+ return;
+ case 0x6D8C:
+ *sin = half(detail::binary, detail::rounded<half::round_style,true>((arg.data_&0x8000)|0x0FE6, 1, 1));
+ *cos = half(detail::binary, detail::rounded<half::round_style,true>(0x3BFF, 1, 1));
+ return;
+ }
+ }
+ std::pair<detail::uint32,detail::uint32> sc = detail::sincos(detail::angle_arg(abs, k), 28);
+ switch(k & 3)
+ {
+ case 1: sc = std::make_pair(sc.second, -sc.first); break;
+ case 2: sc = std::make_pair(-sc.first, -sc.second); break;
+ case 3: sc = std::make_pair(-sc.second, sc.first); break;
+ }
+ *sin = half(detail::binary, detail::fixed2half<half::round_style,30,true,true,true>((sc.first^-static_cast<detail::uint32>(sign))+sign));
+ *cos = half(detail::binary, detail::fixed2half<half::round_style,30,true,true,true>(sc.second));
+ }
+ #endif
+ }
+
+ /// Sine function.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::sin](https://en.cppreference.com/w/cpp/numeric/math/sin).
+ /// \param arg function argument
+ /// \return sine value of \a arg
+ /// \exception FE_INVALID for signaling NaN or infinity
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half sin(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::sin(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, k;
+ if(!abs)
+ return arg;
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? detail::invalid() : detail::signal(arg.data_));
+ if(abs < 0x2900)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_-1, 1, 1));
+ if(half::round_style != std::round_to_nearest)
+ switch(abs)
+ {
+ case 0x48B7: return half(detail::binary, detail::rounded<half::round_style,true>((~arg.data_&0x8000)|0x1D07, 1, 1));
+ case 0x6A64: return half(detail::binary, detail::rounded<half::round_style,true>((~arg.data_&0x8000)|0x3BFE, 1, 1));
+ case 0x6D8C: return half(detail::binary, detail::rounded<half::round_style,true>((arg.data_&0x8000)|0x0FE6, 1, 1));
+ }
+ std::pair<detail::uint32,detail::uint32> sc = detail::sincos(detail::angle_arg(abs, k), 28);
+ detail::uint32 sign = -static_cast<detail::uint32>(((k>>1)&1)^(arg.data_>>15));
+ return half(detail::binary, detail::fixed2half<half::round_style,30,true,true,true>((((k&1) ? sc.second : sc.first)^sign) - sign));
+ #endif
+ }
+
+ /// Cosine function.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::cos](https://en.cppreference.com/w/cpp/numeric/math/cos).
+ /// \param arg function argument
+ /// \return cosine value of \a arg
+ /// \exception FE_INVALID for signaling NaN or infinity
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half cos(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::cos(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, k;
+ if(!abs)
+ return half(detail::binary, 0x3C00);
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? detail::invalid() : detail::signal(arg.data_));
+ if(abs < 0x2500)
+ return half(detail::binary, detail::rounded<half::round_style,true>(0x3BFF, 1, 1));
+ if(half::round_style != std::round_to_nearest && abs == 0x598C)
+ return half(detail::binary, detail::rounded<half::round_style,true>(0x80FC, 1, 1));
+ std::pair<detail::uint32,detail::uint32> sc = detail::sincos(detail::angle_arg(abs, k), 28);
+ detail::uint32 sign = -static_cast<detail::uint32>(((k>>1)^k)&1);
+ return half(detail::binary, detail::fixed2half<half::round_style,30,true,true,true>((((k&1) ? sc.first : sc.second)^sign) - sign));
+ #endif
+ }
+
+ /// Tangent function.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::tan](https://en.cppreference.com/w/cpp/numeric/math/tan).
+ /// \param arg function argument
+ /// \return tangent value of \a arg
+ /// \exception FE_INVALID for signaling NaN or infinity
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half tan(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::tan(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp = 13, k;
+ if(!abs)
+ return arg;
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? detail::invalid() : detail::signal(arg.data_));
+ if(abs < 0x2700)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_, 0, 1));
+ if(half::round_style != std::round_to_nearest)
+ switch(abs)
+ {
+ case 0x658C: return half(detail::binary, detail::rounded<half::round_style,true>((arg.data_&0x8000)|0x07E6, 1, 1));
+ case 0x7330: return half(detail::binary, detail::rounded<half::round_style,true>((~arg.data_&0x8000)|0x4B62, 1, 1));
+ }
+ std::pair<detail::uint32,detail::uint32> sc = detail::sincos(detail::angle_arg(abs, k), 30);
+ if(k & 1)
+ sc = std::make_pair(-sc.second, sc.first);
+ detail::uint32 signy = detail::sign_mask(sc.first), signx = detail::sign_mask(sc.second);
+ detail::uint32 my = (sc.first^signy) - signy, mx = (sc.second^signx) - signx;
+ for(; my<0x80000000; my<<=1,--exp) ;
+ for(; mx<0x80000000; mx<<=1,++exp) ;
+ return half(detail::binary, detail::tangent_post<half::round_style>(my, mx, exp, (signy^signx^arg.data_)&0x8000));
+ #endif
+ }
+
+ /// Arc sine.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::asin](https://en.cppreference.com/w/cpp/numeric/math/asin).
+ /// \param arg function argument
+ /// \return arc sine value of \a arg
+ /// \exception FE_INVALID for signaling NaN or if abs(\a arg) > 1
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half asin(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::asin(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000;
+ if(!abs)
+ return arg;
+ if(abs >= 0x3C00)
+ return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : (abs>0x3C00) ? detail::invalid() :
+ detail::rounded<half::round_style,true>(sign|0x3E48, 0, 1));
+ if(abs < 0x2900)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_, 0, 1));
+ if(half::round_style != std::round_to_nearest && (abs == 0x2B44 || abs == 0x2DC3))
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_+1, 1, 1));
+ std::pair<detail::uint32,detail::uint32> sc = detail::atan2_args(abs);
+ detail::uint32 m = detail::atan2(sc.first, sc.second, (half::round_style==std::round_to_nearest) ? 27 : 26);
+ return half(detail::binary, detail::fixed2half<half::round_style,30,false,true,true>(m, 14, sign));
+ #endif
+ }
+
+ /// Arc cosine function.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::acos](https://en.cppreference.com/w/cpp/numeric/math/acos).
+ /// \param arg function argument
+ /// \return arc cosine value of \a arg
+ /// \exception FE_INVALID for signaling NaN or if abs(\a arg) > 1
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half acos(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::acos(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ >> 15;
+ if(!abs)
+ return half(detail::binary, detail::rounded<half::round_style,true>(0x3E48, 0, 1));
+ if(abs >= 0x3C00)
+ return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : (abs>0x3C00) ? detail::invalid() :
+ sign ? detail::rounded<half::round_style,true>(0x4248, 0, 1) : 0);
+ std::pair<detail::uint32,detail::uint32> cs = detail::atan2_args(abs);
+ detail::uint32 m = detail::atan2(cs.second, cs.first, 28);
+ return half(detail::binary, detail::fixed2half<half::round_style,31,false,true,true>(sign ? (0xC90FDAA2-m) : m, 15, 0, sign));
+ #endif
+ }
+
+ /// Arc tangent function.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::atan](https://en.cppreference.com/w/cpp/numeric/math/atan).
+ /// \param arg function argument
+ /// \return arc tangent value of \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half atan(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::atan(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000;
+ if(!abs)
+ return arg;
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? detail::rounded<half::round_style,true>(sign|0x3E48, 0, 1) : detail::signal(arg.data_));
+ if(abs <= 0x2700)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_-1, 1, 1));
+ int exp = (abs>>10) + (abs<=0x3FF);
+ detail::uint32 my = (abs&0x3FF) | ((abs>0x3FF)<<10);
+ detail::uint32 m = (exp>15) ? detail::atan2(my<<19, 0x20000000>>(exp-15), (half::round_style==std::round_to_nearest) ? 26 : 24) :
+ detail::atan2(my<<(exp+4), 0x20000000, (half::round_style==std::round_to_nearest) ? 30 : 28);
+ return half(detail::binary, detail::fixed2half<half::round_style,30,false,true,true>(m, 14, sign));
+ #endif
+ }
+
+ /// Arc tangent function.
+ /// This function may be 1 ULP off the correctly rounded exact result in ~0.005% of inputs for `std::round_to_nearest`,
+ /// in ~0.1% of inputs for `std::round_toward_zero` and in ~0.02% of inputs for any other rounding mode.
+ ///
+ /// **See also:** Documentation for [std::atan2](https://en.cppreference.com/w/cpp/numeric/math/atan2).
+ /// \param y numerator
+ /// \param x denominator
+ /// \return arc tangent value
+ /// \exception FE_INVALID if \a x or \a y is signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half atan2(half y, half x)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::atan2(detail::half2float<detail::internal_t>(y.data_), detail::half2float<detail::internal_t>(x.data_))));
+ #else
+ unsigned int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, signx = x.data_ >> 15, signy = y.data_ & 0x8000;
+ if(absx >= 0x7C00 || absy >= 0x7C00)
+ {
+ if(absx > 0x7C00 || absy > 0x7C00)
+ return half(detail::binary, detail::signal(x.data_, y.data_));
+ if(absy == 0x7C00)
+ return half(detail::binary, (absx<0x7C00) ? detail::rounded<half::round_style,true>(signy|0x3E48, 0, 1) :
+ signx ? detail::rounded<half::round_style,true>(signy|0x40B6, 0, 1) :
+ detail::rounded<half::round_style,true>(signy|0x3A48, 0, 1));
+ return (x.data_==0x7C00) ? half(detail::binary, signy) : half(detail::binary, detail::rounded<half::round_style,true>(signy|0x4248, 0, 1));
+ }
+ if(!absy)
+ return signx ? half(detail::binary, detail::rounded<half::round_style,true>(signy|0x4248, 0, 1)) : y;
+ if(!absx)
+ return half(detail::binary, detail::rounded<half::round_style,true>(signy|0x3E48, 0, 1));
+ int d = (absy>>10) + (absy<=0x3FF) - (absx>>10) - (absx<=0x3FF);
+ if(d > (signx ? 18 : 12))
+ return half(detail::binary, detail::rounded<half::round_style,true>(signy|0x3E48, 0, 1));
+ if(signx && d < -11)
+ return half(detail::binary, detail::rounded<half::round_style,true>(signy|0x4248, 0, 1));
+ if(!signx && d < ((half::round_style==std::round_toward_zero) ? -15 : -9))
+ {
+ for(; absy<0x400; absy<<=1,--d) ;
+ detail::uint32 mx = ((absx<<1)&0x7FF) | 0x800, my = ((absy<<1)&0x7FF) | 0x800;
+ int i = my < mx;
+ d -= i;
+ if(d < -25)
+ return half(detail::binary, detail::underflow<half::round_style>(signy));
+ my <<= 11 + i;
+ return half(detail::binary, detail::fixed2half<half::round_style,11,false,false,true>(my/mx, d+14, signy, my%mx!=0));
+ }
+ detail::uint32 m = detail::atan2( ((absy&0x3FF)|((absy>0x3FF)<<10))<<(19+((d<0) ? d : (d>0) ? 0 : -1)),
+ ((absx&0x3FF)|((absx>0x3FF)<<10))<<(19-((d>0) ? d : (d<0) ? 0 : 1)));
+ return half(detail::binary, detail::fixed2half<half::round_style,31,false,true,true>(signx ? (0xC90FDAA2-m) : m, 15, signy, signx));
+ #endif
+ }
+
+ /// \}
+ /// \anchor hyperbolic
+ /// \name Hyperbolic functions
+ /// \{
+
+ /// Hyperbolic sine.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::sinh](https://en.cppreference.com/w/cpp/numeric/math/sinh).
+ /// \param arg function argument
+ /// \return hyperbolic sine value of \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half sinh(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::sinh(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp;
+ if(!abs || abs >= 0x7C00)
+ return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg;
+ if(abs <= 0x2900)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_, 0, 1));
+ std::pair<detail::uint32,detail::uint32> mm = detail::hyperbolic_args(abs, exp, (half::round_style==std::round_to_nearest) ? 29 : 27);
+ detail::uint32 m = mm.first - mm.second;
+ for(exp+=13; m<0x80000000 && exp; m<<=1,--exp) ;
+ unsigned int sign = arg.data_ & 0x8000;
+ if(exp > 29)
+ return half(detail::binary, detail::overflow<half::round_style>(sign));
+ return half(detail::binary, detail::fixed2half<half::round_style,31,false,false,true>(m, exp, sign));
+ #endif
+ }
+
+ /// Hyperbolic cosine.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::cosh](https://en.cppreference.com/w/cpp/numeric/math/cosh).
+ /// \param arg function argument
+ /// \return hyperbolic cosine value of \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half cosh(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::cosh(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp;
+ if(!abs)
+ return half(detail::binary, 0x3C00);
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : 0x7C00);
+ std::pair<detail::uint32,detail::uint32> mm = detail::hyperbolic_args(abs, exp, (half::round_style==std::round_to_nearest) ? 23 : 26);
+ detail::uint32 m = mm.first + mm.second, i = (~m&0xFFFFFFFF) >> 31;
+ m = (m>>i) | (m&i) | 0x80000000;
+ if((exp+=13+i) > 29)
+ return half(detail::binary, detail::overflow<half::round_style>());
+ return half(detail::binary, detail::fixed2half<half::round_style,31,false,false,true>(m, exp));
+ #endif
+ }
+
+ /// Hyperbolic tangent.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::tanh](https://en.cppreference.com/w/cpp/numeric/math/tanh).
+ /// \param arg function argument
+ /// \return hyperbolic tangent value of \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half tanh(half arg)
+ {
+ #ifdef HALF_ARITHMETIC_TYPE
+ return half(detail::binary, detail::float2half<half::round_style>(std::tanh(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp;
+ if(!abs)
+ return arg;
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : (arg.data_-0x4000));
+ if(abs >= 0x4500)
+ return half(detail::binary, detail::rounded<half::round_style,true>((arg.data_&0x8000)|0x3BFF, 1, 1));
+ if(abs < 0x2700)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_-1, 1, 1));
+ if(half::round_style != std::round_to_nearest && abs == 0x2D3F)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_-3, 0, 1));
+ std::pair<detail::uint32,detail::uint32> mm = detail::hyperbolic_args(abs, exp, 27);
+ detail::uint32 my = mm.first - mm.second - (half::round_style!=std::round_to_nearest), mx = mm.first + mm.second, i = (~mx&0xFFFFFFFF) >> 31;
+ for(exp=13; my<0x80000000; my<<=1,--exp) ;
+ mx = (mx>>i) | 0x80000000;
+ return half(detail::binary, detail::tangent_post<half::round_style>(my, mx, exp-i, arg.data_&0x8000));
+ #endif
+ }
+
+ /// Hyperbolic area sine.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::asinh](https://en.cppreference.com/w/cpp/numeric/math/asinh).
+ /// \param arg function argument
+ /// \return area sine value of \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half asinh(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::asinh(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF;
+ if(!abs || abs >= 0x7C00)
+ return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg;
+ if(abs <= 0x2900)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_-1, 1, 1));
+ if(half::round_style != std::round_to_nearest)
+ switch(abs)
+ {
+ case 0x32D4: return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_-13, 1, 1));
+ case 0x3B5B: return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_-197, 1, 1));
+ }
+ return half(detail::binary, detail::area<half::round_style,true>(arg.data_));
+ #endif
+ }
+
+ /// Hyperbolic area cosine.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::acosh](https://en.cppreference.com/w/cpp/numeric/math/acosh).
+ /// \param arg function argument
+ /// \return area cosine value of \a arg
+ /// \exception FE_INVALID for signaling NaN or arguments <1
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half acosh(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::acosh(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF;
+ if((arg.data_&0x8000) || abs < 0x3C00)
+ return half(detail::binary, (abs<=0x7C00) ? detail::invalid() : detail::signal(arg.data_));
+ if(abs == 0x3C00)
+ return half(detail::binary, 0);
+ if(arg.data_ >= 0x7C00)
+ return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg;
+ return half(detail::binary, detail::area<half::round_style,false>(arg.data_));
+ #endif
+ }
+
+ /// Hyperbolic area tangent.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::atanh](https://en.cppreference.com/w/cpp/numeric/math/atanh).
+ /// \param arg function argument
+ /// \return area tangent value of \a arg
+ /// \exception FE_INVALID for signaling NaN or if abs(\a arg) > 1
+ /// \exception FE_DIVBYZERO for +/-1
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half atanh(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::atanh(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF, exp = 0;
+ if(!abs)
+ return arg;
+ if(abs >= 0x3C00)
+ return half(detail::binary, (abs==0x3C00) ? detail::pole(arg.data_&0x8000) : (abs<=0x7C00) ? detail::invalid() : detail::signal(arg.data_));
+ if(abs < 0x2700)
+ return half(detail::binary, detail::rounded<half::round_style,true>(arg.data_, 0, 1));
+ detail::uint32 m = static_cast<detail::uint32>((abs&0x3FF)|((abs>0x3FF)<<10)) << ((abs>>10)+(abs<=0x3FF)+6), my = 0x80000000 + m, mx = 0x80000000 - m;
+ for(; mx<0x80000000; mx<<=1,++exp) ;
+ int i = my >= mx, s;
+ return half(detail::binary, detail::log2_post<half::round_style,0xB8AA3B2A>(detail::log2(
+ (detail::divide64(my>>i, mx, s)+1)>>1, 27)+0x10, exp+i-1, 16, arg.data_&0x8000));
+ #endif
+ }
+
+ /// \}
+ /// \anchor special
+ /// \name Error and gamma functions
+ /// \{
+
+ /// Error function.
+ /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in <0.5% of inputs.
+ ///
+ /// **See also:** Documentation for [std::erf](https://en.cppreference.com/w/cpp/numeric/math/erf).
+ /// \param arg function argument
+ /// \return error function value of \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half erf(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::erf(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ unsigned int abs = arg.data_ & 0x7FFF;
+ if(!abs || abs >= 0x7C00)
+ return (abs>=0x7C00) ? half(detail::binary, (abs==0x7C00) ? (arg.data_-0x4000) : detail::signal(arg.data_)) : arg;
+ if(abs >= 0x4200)
+ return half(detail::binary, detail::rounded<half::round_style,true>((arg.data_&0x8000)|0x3BFF, 1, 1));
+ return half(detail::binary, detail::erf<half::round_style,false>(arg.data_));
+ #endif
+ }
+
+ /// Complementary error function.
+ /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in <0.5% of inputs.
+ ///
+ /// **See also:** Documentation for [std::erfc](https://en.cppreference.com/w/cpp/numeric/math/erfc).
+ /// \param arg function argument
+ /// \return 1 minus error function value of \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half erfc(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::erfc(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000;
+ if(abs >= 0x7C00)
+ return (abs>=0x7C00) ? half(detail::binary, (abs==0x7C00) ? (sign>>1) : detail::signal(arg.data_)) : arg;
+ if(!abs)
+ return half(detail::binary, 0x3C00);
+ if(abs >= 0x4400)
+ return half(detail::binary, detail::rounded<half::round_style,true>((sign>>1)-(sign>>15), sign>>15, 1));
+ return half(detail::binary, detail::erf<half::round_style,true>(arg.data_));
+ #endif
+ }
+
+ /// Natural logarithm of gamma function.
+ /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in ~0.025% of inputs.
+ ///
+ /// **See also:** Documentation for [std::lgamma](https://en.cppreference.com/w/cpp/numeric/math/lgamma).
+ /// \param arg function argument
+ /// \return natural logarith of gamma function for \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_DIVBYZERO for 0 or negative integer arguments
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half lgamma(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::lgamma(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ int abs = arg.data_ & 0x7FFF;
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? 0x7C00 : detail::signal(arg.data_));
+ if(!abs || arg.data_ >= 0xE400 || (arg.data_ >= 0xBC00 && !(abs&((1<<(25-(abs>>10)))-1))))
+ return half(detail::binary, detail::pole());
+ if(arg.data_ == 0x3C00 || arg.data_ == 0x4000)
+ return half(detail::binary, 0);
+ return half(detail::binary, detail::gamma<half::round_style,true>(arg.data_));
+ #endif
+ }
+
+ /// Gamma function.
+ /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in <0.25% of inputs.
+ ///
+ /// **See also:** Documentation for [std::tgamma](https://en.cppreference.com/w/cpp/numeric/math/tgamma).
+ /// \param arg function argument
+ /// \return gamma function value of \a arg
+ /// \exception FE_INVALID for signaling NaN, negative infinity or negative integer arguments
+ /// \exception FE_DIVBYZERO for 0
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half tgamma(half arg)
+ {
+ #if defined(HALF_ARITHMETIC_TYPE) && HALF_ENABLE_CPP11_CMATH
+ return half(detail::binary, detail::float2half<half::round_style>(std::tgamma(detail::half2float<detail::internal_t>(arg.data_))));
+ #else
+ unsigned int abs = arg.data_ & 0x7FFF;
+ if(!abs)
+ return half(detail::binary, detail::pole(arg.data_));
+ if(abs >= 0x7C00)
+ return (arg.data_==0x7C00) ? arg : half(detail::binary, detail::signal(arg.data_));
+ if(arg.data_ >= 0xE400 || (arg.data_ >= 0xBC00 && !(abs&((1<<(25-(abs>>10)))-1))))
+ return half(detail::binary, detail::invalid());
+ if(arg.data_ >= 0xCA80)
+ return half(detail::binary, detail::underflow<half::round_style>((1-((abs>>(25-(abs>>10)))&1))<<15));
+ if(arg.data_ <= 0x100 || (arg.data_ >= 0x4900 && arg.data_ < 0x8000))
+ return half(detail::binary, detail::overflow<half::round_style>());
+ if(arg.data_ == 0x3C00)
+ return arg;
+ return half(detail::binary, detail::gamma<half::round_style,false>(arg.data_));
+ #endif
+ }
+
+ /// \}
+ /// \anchor rounding
+ /// \name Rounding
+ /// \{
+
+ /// Nearest integer not less than half value.
+ /// **See also:** Documentation for [std::ceil](https://en.cppreference.com/w/cpp/numeric/math/ceil).
+ /// \param arg half to round
+ /// \return nearest integer not less than \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_INEXACT if value had to be rounded
+ inline half ceil(half arg) { return half(detail::binary, detail::integral<std::round_toward_infinity,true,true>(arg.data_)); }
+
+ /// Nearest integer not greater than half value.
+ /// **See also:** Documentation for [std::floor](https://en.cppreference.com/w/cpp/numeric/math/floor).
+ /// \param arg half to round
+ /// \return nearest integer not greater than \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_INEXACT if value had to be rounded
+ inline half floor(half arg) { return half(detail::binary, detail::integral<std::round_toward_neg_infinity,true,true>(arg.data_)); }
+
+ /// Nearest integer not greater in magnitude than half value.
+ /// **See also:** Documentation for [std::trunc](https://en.cppreference.com/w/cpp/numeric/math/trunc).
+ /// \param arg half to round
+ /// \return nearest integer not greater in magnitude than \a arg
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_INEXACT if value had to be rounded
+ inline half trunc(half arg) { return half(detail::binary, detail::integral<std::round_toward_zero,true,true>(arg.data_)); }
+
+ /// Nearest integer.
+ /// **See also:** Documentation for [std::round](https://en.cppreference.com/w/cpp/numeric/math/round).
+ /// \param arg half to round
+ /// \return nearest integer, rounded away from zero in half-way cases
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_INEXACT if value had to be rounded
+ inline half round(half arg) { return half(detail::binary, detail::integral<std::round_to_nearest,false,true>(arg.data_)); }
+
+ /// Nearest integer.
+ /// **See also:** Documentation for [std::lround](https://en.cppreference.com/w/cpp/numeric/math/round).
+ /// \param arg half to round
+ /// \return nearest integer, rounded away from zero in half-way cases
+ /// \exception FE_INVALID if value is not representable as `long`
+ inline long lround(half arg) { return detail::half2int<std::round_to_nearest,false,false,long>(arg.data_); }
+
+ /// Nearest integer using half's internal rounding mode.
+ /// **See also:** Documentation for [std::rint](https://en.cppreference.com/w/cpp/numeric/math/rint).
+ /// \param arg half expression to round
+ /// \return nearest integer using default rounding mode
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_INEXACT if value had to be rounded
+ inline half rint(half arg) { return half(detail::binary, detail::integral<half::round_style,true,true>(arg.data_)); }
+
+ /// Nearest integer using half's internal rounding mode.
+ /// **See also:** Documentation for [std::lrint](https://en.cppreference.com/w/cpp/numeric/math/rint).
+ /// \param arg half expression to round
+ /// \return nearest integer using default rounding mode
+ /// \exception FE_INVALID if value is not representable as `long`
+ /// \exception FE_INEXACT if value had to be rounded
+ inline long lrint(half arg) { return detail::half2int<half::round_style,true,true,long>(arg.data_); }
+
+ /// Nearest integer using half's internal rounding mode.
+ /// **See also:** Documentation for [std::nearbyint](https://en.cppreference.com/w/cpp/numeric/math/nearbyint).
+ /// \param arg half expression to round
+ /// \return nearest integer using default rounding mode
+ /// \exception FE_INVALID for signaling NaN
+ inline half nearbyint(half arg) { return half(detail::binary, detail::integral<half::round_style,true,false>(arg.data_)); }
+#if HALF_ENABLE_CPP11_LONG_LONG
+ /// Nearest integer.
+ /// **See also:** Documentation for [std::llround](https://en.cppreference.com/w/cpp/numeric/math/round).
+ /// \param arg half to round
+ /// \return nearest integer, rounded away from zero in half-way cases
+ /// \exception FE_INVALID if value is not representable as `long long`
+ inline long long llround(half arg) { return detail::half2int<std::round_to_nearest,false,false,long long>(arg.data_); }
+
+ /// Nearest integer using half's internal rounding mode.
+ /// **See also:** Documentation for [std::llrint](https://en.cppreference.com/w/cpp/numeric/math/rint).
+ /// \param arg half expression to round
+ /// \return nearest integer using default rounding mode
+ /// \exception FE_INVALID if value is not representable as `long long`
+ /// \exception FE_INEXACT if value had to be rounded
+ inline long long llrint(half arg) { return detail::half2int<half::round_style,true,true,long long>(arg.data_); }
+#endif
+
+ /// \}
+ /// \anchor float
+ /// \name Floating point manipulation
+ /// \{
+
+ /// Decompress floating-point number.
+ /// **See also:** Documentation for [std::frexp](https://en.cppreference.com/w/cpp/numeric/math/frexp).
+ /// \param arg number to decompress
+ /// \param exp address to store exponent at
+ /// \return significant in range [0.5, 1)
+ /// \exception FE_INVALID for signaling NaN
+ inline half frexp(half arg, int *exp)
+ {
+ *exp = 0;
+ unsigned int abs = arg.data_ & 0x7FFF;
+ if(abs >= 0x7C00 || !abs)
+ return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg;
+ for(; abs<0x400; abs<<=1,--*exp) ;
+ *exp += (abs>>10) - 14;
+ return half(detail::binary, (arg.data_&0x8000)|0x3800|(abs&0x3FF));
+ }
+
+ /// Multiply by power of two.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::scalbln](https://en.cppreference.com/w/cpp/numeric/math/scalbn).
+ /// \param arg number to modify
+ /// \param exp power of two to multiply with
+ /// \return \a arg multplied by 2 raised to \a exp
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half scalbln(half arg, long exp)
+ {
+ unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000;
+ if(abs >= 0x7C00 || !abs)
+ return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg;
+ for(; abs<0x400; abs<<=1,--exp) ;
+ exp += abs >> 10;
+ if(exp > 30)
+ return half(detail::binary, detail::overflow<half::round_style>(sign));
+ else if(exp < -10)
+ return half(detail::binary, detail::underflow<half::round_style>(sign));
+ else if(exp > 0)
+ return half(detail::binary, sign|(exp<<10)|(abs&0x3FF));
+ unsigned int m = (abs&0x3FF) | 0x400;
+ return half(detail::binary, detail::rounded<half::round_style,false>(sign|(m>>(1-exp)), (m>>-exp)&1, (m&((1<<-exp)-1))!=0));
+ }
+
+ /// Multiply by power of two.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::scalbn](https://en.cppreference.com/w/cpp/numeric/math/scalbn).
+ /// \param arg number to modify
+ /// \param exp power of two to multiply with
+ /// \return \a arg multplied by 2 raised to \a exp
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half scalbn(half arg, int exp) { return scalbln(arg, exp); }
+
+ /// Multiply by power of two.
+ /// This function is exact to rounding for all rounding modes.
+ ///
+ /// **See also:** Documentation for [std::ldexp](https://en.cppreference.com/w/cpp/numeric/math/ldexp).
+ /// \param arg number to modify
+ /// \param exp power of two to multiply with
+ /// \return \a arg multplied by 2 raised to \a exp
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ inline half ldexp(half arg, int exp) { return scalbln(arg, exp); }
+
+ /// Extract integer and fractional parts.
+ /// **See also:** Documentation for [std::modf](https://en.cppreference.com/w/cpp/numeric/math/modf).
+ /// \param arg number to decompress
+ /// \param iptr address to store integer part at
+ /// \return fractional part
+ /// \exception FE_INVALID for signaling NaN
+ inline half modf(half arg, half *iptr)
+ {
+ unsigned int abs = arg.data_ & 0x7FFF;
+ if(abs > 0x7C00)
+ {
+ arg = half(detail::binary, detail::signal(arg.data_));
+ return *iptr = arg, arg;
+ }
+ if(abs >= 0x6400)
+ return *iptr = arg, half(detail::binary, arg.data_&0x8000);
+ if(abs < 0x3C00)
+ return iptr->data_ = arg.data_ & 0x8000, arg;
+ unsigned int exp = abs >> 10, mask = (1<<(25-exp)) - 1, m = arg.data_ & mask;
+ iptr->data_ = arg.data_ & ~mask;
+ if(!m)
+ return half(detail::binary, arg.data_&0x8000);
+ for(; m<0x400; m<<=1,--exp) ;
+ return half(detail::binary, (arg.data_&0x8000)|(exp<<10)|(m&0x3FF));
+ }
+
+ /// Extract exponent.
+ /// **See also:** Documentation for [std::ilogb](https://en.cppreference.com/w/cpp/numeric/math/ilogb).
+ /// \param arg number to query
+ /// \return floating-point exponent
+ /// \retval FP_ILOGB0 for zero
+ /// \retval FP_ILOGBNAN for NaN
+ /// \retval INT_MAX for infinity
+ /// \exception FE_INVALID for 0 or infinite values
+ inline int ilogb(half arg)
+ {
+ int abs = arg.data_ & 0x7FFF, exp;
+ if(!abs || abs >= 0x7C00)
+ {
+ detail::raise(FE_INVALID);
+ return !abs ? FP_ILOGB0 : (abs==0x7C00) ? INT_MAX : FP_ILOGBNAN;
+ }
+ for(exp=(abs>>10)-15; abs<0x200; abs<<=1,--exp) ;
+ return exp;
+ }
+
+ /// Extract exponent.
+ /// **See also:** Documentation for [std::logb](https://en.cppreference.com/w/cpp/numeric/math/logb).
+ /// \param arg number to query
+ /// \return floating-point exponent
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_DIVBYZERO for 0
+ inline half logb(half arg)
+ {
+ int abs = arg.data_ & 0x7FFF, exp;
+ if(!abs)
+ return half(detail::binary, detail::pole(0x8000));
+ if(abs >= 0x7C00)
+ return half(detail::binary, (abs==0x7C00) ? 0x7C00 : detail::signal(arg.data_));
+ for(exp=(abs>>10)-15; abs<0x200; abs<<=1,--exp) ;
+ unsigned int value = static_cast<unsigned>(exp<0) << 15;
+ if(exp)
+ {
+ unsigned int m = std::abs(exp) << 6;
+ for(exp=18; m<0x400; m<<=1,--exp) ;
+ value |= (exp<<10) + m;
+ }
+ return half(detail::binary, value);
+ }
+
+ /// Next representable value.
+ /// **See also:** Documentation for [std::nextafter](https://en.cppreference.com/w/cpp/numeric/math/nextafter).
+ /// \param from value to compute next representable value for
+ /// \param to direction towards which to compute next value
+ /// \return next representable value after \a from in direction towards \a to
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW for infinite result from finite argument
+ /// \exception FE_UNDERFLOW for subnormal result
+ inline half nextafter(half from, half to)
+ {
+ int fabs = from.data_ & 0x7FFF, tabs = to.data_ & 0x7FFF;
+ if(fabs > 0x7C00 || tabs > 0x7C00)
+ return half(detail::binary, detail::signal(from.data_, to.data_));
+ if(from.data_ == to.data_ || !(fabs|tabs))
+ return to;
+ if(!fabs)
+ {
+ detail::raise(FE_UNDERFLOW, !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT);
+ return half(detail::binary, (to.data_&0x8000)+1);
+ }
+ unsigned int out = from.data_ + (((from.data_>>15)^static_cast<unsigned>(
+ (from.data_^(0x8000|(0x8000-(from.data_>>15))))<(to.data_^(0x8000|(0x8000-(to.data_>>15))))))<<1) - 1;
+ detail::raise(FE_OVERFLOW, fabs<0x7C00 && (out&0x7C00)==0x7C00);
+ detail::raise(FE_UNDERFLOW, !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT && (out&0x7C00)<0x400);
+ return half(detail::binary, out);
+ }
+
+ /// Next representable value.
+ /// **See also:** Documentation for [std::nexttoward](https://en.cppreference.com/w/cpp/numeric/math/nexttoward).
+ /// \param from value to compute next representable value for
+ /// \param to direction towards which to compute next value
+ /// \return next representable value after \a from in direction towards \a to
+ /// \exception FE_INVALID for signaling NaN
+ /// \exception FE_OVERFLOW for infinite result from finite argument
+ /// \exception FE_UNDERFLOW for subnormal result
+ inline half nexttoward(half from, long double to)
+ {
+ int fabs = from.data_ & 0x7FFF;
+ if(fabs > 0x7C00)
+ return half(detail::binary, detail::signal(from.data_));
+ long double lfrom = static_cast<long double>(from);
+ if(detail::builtin_isnan(to) || lfrom == to)
+ return half(static_cast<float>(to));
+ if(!fabs)
+ {
+ detail::raise(FE_UNDERFLOW, !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT);
+ return half(detail::binary, (static_cast<unsigned>(detail::builtin_signbit(to))<<15)+1);
+ }
+ unsigned int out = from.data_ + (((from.data_>>15)^static_cast<unsigned>(lfrom<to))<<1) - 1;
+ detail::raise(FE_OVERFLOW, (out&0x7FFF)==0x7C00);
+ detail::raise(FE_UNDERFLOW, !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT && (out&0x7FFF)<0x400);
+ return half(detail::binary, out);
+ }
+
+ /// Take sign.
+ /// **See also:** Documentation for [std::copysign](https://en.cppreference.com/w/cpp/numeric/math/copysign).
+ /// \param x value to change sign for
+ /// \param y value to take sign from
+ /// \return value equal to \a x in magnitude and to \a y in sign
+ inline HALF_CONSTEXPR half copysign(half x, half y) { return half(detail::binary, x.data_^((x.data_^y.data_)&0x8000)); }
+
+ /// \}
+ /// \anchor classification
+ /// \name Floating point classification
+ /// \{
+
+ /// Classify floating-point value.
+ /// **See also:** Documentation for [std::fpclassify](https://en.cppreference.com/w/cpp/numeric/math/fpclassify).
+ /// \param arg number to classify
+ /// \retval FP_ZERO for positive and negative zero
+ /// \retval FP_SUBNORMAL for subnormal numbers
+ /// \retval FP_INFINITY for positive and negative infinity
+ /// \retval FP_NAN for NaNs
+ /// \retval FP_NORMAL for all other (normal) values
+ inline HALF_CONSTEXPR int fpclassify(half arg)
+ {
+ return !(arg.data_&0x7FFF) ? FP_ZERO :
+ ((arg.data_&0x7FFF)<0x400) ? FP_SUBNORMAL :
+ ((arg.data_&0x7FFF)<0x7C00) ? FP_NORMAL :
+ ((arg.data_&0x7FFF)==0x7C00) ? FP_INFINITE :
+ FP_NAN;
+ }
+
+ /// Check if finite number.
+ /// **See also:** Documentation for [std::isfinite](https://en.cppreference.com/w/cpp/numeric/math/isfinite).
+ /// \param arg number to check
+ /// \retval true if neither infinity nor NaN
+ /// \retval false else
+ inline HALF_CONSTEXPR bool isfinite(half arg) { return (arg.data_&0x7C00) != 0x7C00; }
+
+ /// Check for infinity.
+ /// **See also:** Documentation for [std::isinf](https://en.cppreference.com/w/cpp/numeric/math/isinf).
+ /// \param arg number to check
+ /// \retval true for positive or negative infinity
+ /// \retval false else
+ inline HALF_CONSTEXPR bool isinf(half arg) { return (arg.data_&0x7FFF) == 0x7C00; }
+
+ /// Check for NaN.
+ /// **See also:** Documentation for [std::isnan](https://en.cppreference.com/w/cpp/numeric/math/isnan).
+ /// \param arg number to check
+ /// \retval true for NaNs
+ /// \retval false else
+ inline HALF_CONSTEXPR bool isnan(half arg) { return (arg.data_&0x7FFF) > 0x7C00; }
+
+ /// Check if normal number.
+ /// **See also:** Documentation for [std::isnormal](https://en.cppreference.com/w/cpp/numeric/math/isnormal).
+ /// \param arg number to check
+ /// \retval true if normal number
+ /// \retval false if either subnormal, zero, infinity or NaN
+ inline HALF_CONSTEXPR bool isnormal(half arg) { return ((arg.data_&0x7C00)!=0) & ((arg.data_&0x7C00)!=0x7C00); }
+
+ /// Check sign.
+ /// **See also:** Documentation for [std::signbit](https://en.cppreference.com/w/cpp/numeric/math/signbit).
+ /// \param arg number to check
+ /// \retval true for negative number
+ /// \retval false for positive number
+ inline HALF_CONSTEXPR bool signbit(half arg) { return (arg.data_&0x8000) != 0; }
+
+ /// \}
+ /// \anchor compfunc
+ /// \name Comparison
+ /// \{
+
+ /// Quiet comparison for greater than.
+ /// **See also:** Documentation for [std::isgreater](https://en.cppreference.com/w/cpp/numeric/math/isgreater).
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if \a x greater than \a y
+ /// \retval false else
+ inline HALF_CONSTEXPR bool isgreater(half x, half y)
+ {
+ return ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) > ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)) && !isnan(x) && !isnan(y);
+ }
+
+ /// Quiet comparison for greater equal.
+ /// **See also:** Documentation for [std::isgreaterequal](https://en.cppreference.com/w/cpp/numeric/math/isgreaterequal).
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if \a x greater equal \a y
+ /// \retval false else
+ inline HALF_CONSTEXPR bool isgreaterequal(half x, half y)
+ {
+ return ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) >= ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)) && !isnan(x) && !isnan(y);
+ }
+
+ /// Quiet comparison for less than.
+ /// **See also:** Documentation for [std::isless](https://en.cppreference.com/w/cpp/numeric/math/isless).
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if \a x less than \a y
+ /// \retval false else
+ inline HALF_CONSTEXPR bool isless(half x, half y)
+ {
+ return ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) < ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)) && !isnan(x) && !isnan(y);
+ }
+
+ /// Quiet comparison for less equal.
+ /// **See also:** Documentation for [std::islessequal](https://en.cppreference.com/w/cpp/numeric/math/islessequal).
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if \a x less equal \a y
+ /// \retval false else
+ inline HALF_CONSTEXPR bool islessequal(half x, half y)
+ {
+ return ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) <= ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)) && !isnan(x) && !isnan(y);
+ }
+
+ /// Quiet comarison for less or greater.
+ /// **See also:** Documentation for [std::islessgreater](https://en.cppreference.com/w/cpp/numeric/math/islessgreater).
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if either less or greater
+ /// \retval false else
+ inline HALF_CONSTEXPR bool islessgreater(half x, half y)
+ {
+ return x.data_!=y.data_ && ((x.data_|y.data_)&0x7FFF) && !isnan(x) && !isnan(y);
+ }
+
+ /// Quiet check if unordered.
+ /// **See also:** Documentation for [std::isunordered](https://en.cppreference.com/w/cpp/numeric/math/isunordered).
+ /// \param x first operand
+ /// \param y second operand
+ /// \retval true if unordered (one or two NaN operands)
+ /// \retval false else
+ inline HALF_CONSTEXPR bool isunordered(half x, half y) { return isnan(x) || isnan(y); }
+
+ /// \}
+ /// \anchor casting
+ /// \name Casting
+ /// \{
+
+ /// Cast to or from half-precision floating-point number.
+ /// This casts between [half](\ref half_float::half) and any built-in arithmetic type. The values are converted
+ /// directly using the default rounding mode, without any roundtrip over `float` that a `static_cast` would otherwise do.
+ ///
+ /// Using this cast with neither of the two types being a [half](\ref half_float::half) or with any of the two types
+ /// not being a built-in arithmetic type (apart from [half](\ref half_float::half), of course) results in a compiler
+ /// error and casting between [half](\ref half_float::half)s returns the argument unmodified.
+ /// \tparam T destination type (half or built-in arithmetic type)
+ /// \tparam U source type (half or built-in arithmetic type)
+ /// \param arg value to cast
+ /// \return \a arg converted to destination type
+ /// \exception FE_INVALID if \a T is integer type and result is not representable as \a T
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ template<typename T,typename U> T half_cast(U arg) { return detail::half_caster<T,U>::cast(arg); }
+
+ /// Cast to or from half-precision floating-point number.
+ /// This casts between [half](\ref half_float::half) and any built-in arithmetic type. The values are converted
+ /// directly using the specified rounding mode, without any roundtrip over `float` that a `static_cast` would otherwise do.
+ ///
+ /// Using this cast with neither of the two types being a [half](\ref half_float::half) or with any of the two types
+ /// not being a built-in arithmetic type (apart from [half](\ref half_float::half), of course) results in a compiler
+ /// error and casting between [half](\ref half_float::half)s returns the argument unmodified.
+ /// \tparam T destination type (half or built-in arithmetic type)
+ /// \tparam R rounding mode to use.
+ /// \tparam U source type (half or built-in arithmetic type)
+ /// \param arg value to cast
+ /// \return \a arg converted to destination type
+ /// \exception FE_INVALID if \a T is integer type and result is not representable as \a T
+ /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding
+ template<typename T,std::float_round_style R,typename U> T half_cast(U arg) { return detail::half_caster<T,U,R>::cast(arg); }
+ /// \}
+
+ /// \}
+ /// \anchor errors
+ /// \name Error handling
+ /// \{
+
+ /// Clear exception flags.
+ /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled,
+ /// but in that case manual flag management is the only way to raise flags.
+ ///
+ /// **See also:** Documentation for [std::feclearexcept](https://en.cppreference.com/w/cpp/numeric/fenv/feclearexcept).
+ /// \param excepts OR of exceptions to clear
+ /// \retval 0 all selected flags cleared successfully
+ inline int feclearexcept(int excepts) { detail::errflags() &= ~excepts; return 0; }
+
+ /// Test exception flags.
+ /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled,
+ /// but in that case manual flag management is the only way to raise flags.
+ ///
+ /// **See also:** Documentation for [std::fetestexcept](https://en.cppreference.com/w/cpp/numeric/fenv/fetestexcept).
+ /// \param excepts OR of exceptions to test
+ /// \return OR of selected exceptions if raised
+ inline int fetestexcept(int excepts) { return detail::errflags() & excepts; }
+
+ /// Raise exception flags.
+ /// This raises the specified floating point exceptions and also invokes any additional automatic exception handling as
+ /// configured with the [HALF_ERRHANDLIG_...](\ref HALF_ERRHANDLING_ERRNO) preprocessor symbols.
+ /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled,
+ /// but in that case manual flag management is the only way to raise flags.
+ ///
+ /// **See also:** Documentation for [std::feraiseexcept](https://en.cppreference.com/w/cpp/numeric/fenv/feraiseexcept).
+ /// \param excepts OR of exceptions to raise
+ /// \retval 0 all selected exceptions raised successfully
+ inline int feraiseexcept(int excepts) { detail::errflags() |= excepts; detail::raise(excepts); return 0; }
+
+ /// Save exception flags.
+ /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled,
+ /// but in that case manual flag management is the only way to raise flags.
+ ///
+ /// **See also:** Documentation for [std::fegetexceptflag](https://en.cppreference.com/w/cpp/numeric/fenv/feexceptflag).
+ /// \param flagp adress to store flag state at
+ /// \param excepts OR of flags to save
+ /// \retval 0 for success
+ inline int fegetexceptflag(int *flagp, int excepts) { *flagp = detail::errflags() & excepts; return 0; }
+
+ /// Restore exception flags.
+ /// This only copies the specified exception state (including unset flags) without incurring any additional exception handling.
+ /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled,
+ /// but in that case manual flag management is the only way to raise flags.
+ ///
+ /// **See also:** Documentation for [std::fesetexceptflag](https://en.cppreference.com/w/cpp/numeric/fenv/feexceptflag).
+ /// \param flagp adress to take flag state from
+ /// \param excepts OR of flags to restore
+ /// \retval 0 for success
+ inline int fesetexceptflag(const int *flagp, int excepts) { detail::errflags() = (detail::errflags()|(*flagp&excepts)) & (*flagp|~excepts); return 0; }
+
+ /// Throw C++ exceptions based on set exception flags.
+ /// This function manually throws a corresponding C++ exception if one of the specified flags is set,
+ /// no matter if automatic throwing (via [HALF_ERRHANDLING_THROW_...](\ref HALF_ERRHANDLING_THROW_INVALID)) is enabled or not.
+ /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled,
+ /// but in that case manual flag management is the only way to raise flags.
+ /// \param excepts OR of exceptions to test
+ /// \param msg error message to use for exception description
+ /// \throw std::domain_error if `FE_INVALID` or `FE_DIVBYZERO` is selected and set
+ /// \throw std::overflow_error if `FE_OVERFLOW` is selected and set
+ /// \throw std::underflow_error if `FE_UNDERFLOW` is selected and set
+ /// \throw std::range_error if `FE_INEXACT` is selected and set
+ inline void fethrowexcept(int excepts, const char *msg = "")
+ {
+ excepts &= detail::errflags();
+ if(excepts & (FE_INVALID|FE_DIVBYZERO))
+ throw std::domain_error(msg);
+ if(excepts & FE_OVERFLOW)
+ throw std::overflow_error(msg);
+ if(excepts & FE_UNDERFLOW)
+ throw std::underflow_error(msg);
+ if(excepts & FE_INEXACT)
+ throw std::range_error(msg);
+ }
+ /// \}
+}
+
+
+#undef HALF_UNUSED_NOERR
+#undef HALF_CONSTEXPR
+#undef HALF_CONSTEXPR_CONST
+#undef HALF_CONSTEXPR_NOERR
+#undef HALF_NOEXCEPT
+#undef HALF_NOTHROW
+#undef HALF_THREAD_LOCAL
+#undef HALF_TWOS_COMPLEMENT_INT
+#ifdef HALF_POP_WARNINGS
+ #pragma warning(pop)
+ #undef HALF_POP_WARNINGS
+#endif
+
+#endif
diff --git a/runtime/3rdparty/jsoncpp/CMakeLists.txt b/runtime/3rdparty/jsoncpp/CMakeLists.txt
new file mode 100644
index 000000000..5720cec5b
--- /dev/null
+++ b/runtime/3rdparty/jsoncpp/CMakeLists.txt
@@ -0,0 +1,6 @@
+file(GLOB_RECURSE SRCS "*.cpp")
+
+add_library(jsoncpp STATIC ${SRCS})
+set_property(TARGET jsoncpp PROPERTY POSITION_INDEPENDENT_CODE ON)
+set_property(TARGET jsoncpp APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
diff --git a/runtime/3rdparty/jsoncpp/README.md b/runtime/3rdparty/jsoncpp/README.md
new file mode 100644
index 000000000..da5a06d71
--- /dev/null
+++ b/runtime/3rdparty/jsoncpp/README.md
@@ -0,0 +1,11 @@
+# Origin of source code
+
+This library is based on Json-cpp amalgated header and cpp files(https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated)
+
+# Background
+
+Since jsoncpp on tizen does not support static jsoncpp library, nnfw project will link this local library.
+
+# Version
+
+- 1.7.7 : https://github.com/open-source-parsers/jsoncpp/archive/1.7.7.tar.gz
diff --git a/runtime/3rdparty/jsoncpp/json/json-forwards.h b/runtime/3rdparty/jsoncpp/json/json-forwards.h
new file mode 100644
index 000000000..9fe95c055
--- /dev/null
+++ b/runtime/3rdparty/jsoncpp/json/json-forwards.h
@@ -0,0 +1,315 @@
+/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json-forwards.h"
+/// This header provides forward declaration for all JsonCpp types.
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+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.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
+#define JSON_FORWARD_AMALGATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+#include <stddef.h>
+#include <string> //typedef String
+#include <stdint.h> //typedef int64_t, uint64_t
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include <cpptl/config.h>
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER) // MSVC
+#if _MSC_VER <= 1200 // MSVC 6
+ // Microsoft Visual Studio 6 only support conversion from __int64 to double
+ // (no conversion from unsigned __int64).
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
+// characters in the debug information)
+// All projects I've ever seen with VS6 were using this globally (not bothering
+// with pragma push/pop).
+#pragma warning(disable : 4786)
+#endif // MSVC 6
+
+#if _MSC_VER >= 1500 // MSVC 2008
+ /// Indicates that the following function is deprecated.
+#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif
+
+#endif // defined(_MSC_VER)
+
+// In c++11 the override keyword allows you to explicity define that a function
+// is intended to override the base-class version. This makes the code more
+// managable and fixes a set of common hard-to-find bugs.
+#if __cplusplus >= 201103L
+#define JSONCPP_OVERRIDE override
+#elif defined(_MSC_VER) && _MSC_VER > 1600
+#define JSONCPP_OVERRIDE override
+#else
+#define JSONCPP_OVERRIDE
+#endif
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // MSVC >= 2010
+
+#ifdef __clang__
+#if __has_feature(cxx_rvalue_references)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // has_feature
+
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // GXX_EXPERIMENTAL
+
+#endif // __clang__ || __GNUC__
+
+#endif // not defined JSON_HAS_RVALUE_REFERENCES
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+#define JSON_HAS_RVALUE_REFERENCES 0
+#endif
+
+#ifdef __clang__
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
+#endif // GNUC version
+#endif // __clang__ || __GNUC__
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+#if __GNUC__ >= 6
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#endif
+
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "version.h"
+
+#if JSONCPP_USING_SECURE_MEMORY
+#include "allocator.h" //typedef Allocator
+#endif
+
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json
+{
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else // if defined(_MSC_VER) // Other platforms, use long long
+typedef int64_t Int64;
+typedef uint64_t UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+#if JSONCPP_USING_SECURE_MEMORY
+#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char>>
+#define JSONCPP_OSTRINGSTREAM \
+ std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char>>
+#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>>
+#define JSONCPP_ISTRINGSTREAM \
+ std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char>>
+#define JSONCPP_ISTREAM std::istream
+#else
+#define JSONCPP_STRING std::string
+#define JSONCPP_OSTRINGSTREAM std::ostringstream
+#define JSONCPP_OSTREAM std::ostream
+#define JSONCPP_ISTRINGSTREAM std::istringstream
+#define JSONCPP_ISTREAM std::istream
+#endif // if JSONCPP_USING_SECURE_MEMORY
+} // end namespace Json
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json
+{
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+#endif // ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
diff --git a/runtime/3rdparty/jsoncpp/json/json.h b/runtime/3rdparty/jsoncpp/json/json.h
new file mode 100644
index 000000000..19c591267
--- /dev/null
+++ b/runtime/3rdparty/jsoncpp/json/json.h
@@ -0,0 +1,2133 @@
+/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json.h"
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+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.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+#ifndef JSON_AMALGATED_H_INCLUDED
+#define JSON_AMALGATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+// DO NOT EDIT. This file (and "version") is generated by CMake.
+// Run CMake configure step to update it.
+#ifndef JSON_VERSION_H_INCLUDED
+#define JSON_VERSION_H_INCLUDED
+
+#define JSONCPP_VERSION_STRING "1.7.7"
+#define JSONCPP_VERSION_MAJOR 1
+#define JSONCPP_VERSION_MINOR 7
+#define JSONCPP_VERSION_PATCH 7
+#define JSONCPP_VERSION_QUALIFIER
+#define JSONCPP_VERSION_HEXA \
+ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
+
+#ifdef JSONCPP_USING_SECURE_MEMORY
+#undef JSONCPP_USING_SECURE_MEMORY
+#endif
+#define JSONCPP_USING_SECURE_MEMORY 0
+// If non-zero, the library zeroes any memory that it has allocated before
+// it frees its memory.
+
+#endif // JSON_VERSION_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+#include <stddef.h>
+#include <string> //typedef String
+#include <stdint.h> //typedef int64_t, uint64_t
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include <cpptl/config.h>
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER) // MSVC
+#if _MSC_VER <= 1200 // MSVC 6
+ // Microsoft Visual Studio 6 only support conversion from __int64 to double
+ // (no conversion from unsigned __int64).
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
+// characters in the debug information)
+// All projects I've ever seen with VS6 were using this globally (not bothering
+// with pragma push/pop).
+#pragma warning(disable : 4786)
+#endif // MSVC 6
+
+#if _MSC_VER >= 1500 // MSVC 2008
+ /// Indicates that the following function is deprecated.
+#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif
+
+#endif // defined(_MSC_VER)
+
+// In c++11 the override keyword allows you to explicity define that a function
+// is intended to override the base-class version. This makes the code more
+// managable and fixes a set of common hard-to-find bugs.
+#if __cplusplus >= 201103L
+#define JSONCPP_OVERRIDE override
+#elif defined(_MSC_VER) && _MSC_VER > 1600
+#define JSONCPP_OVERRIDE override
+#else
+#define JSONCPP_OVERRIDE
+#endif
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // MSVC >= 2010
+
+#ifdef __clang__
+#if __has_feature(cxx_rvalue_references)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // has_feature
+
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // GXX_EXPERIMENTAL
+
+#endif // __clang__ || __GNUC__
+
+#endif // not defined JSON_HAS_RVALUE_REFERENCES
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+#define JSON_HAS_RVALUE_REFERENCES 0
+#endif
+
+#ifdef __clang__
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
+#endif // GNUC version
+#endif // __clang__ || __GNUC__
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+#if __GNUC__ >= 6
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#endif
+
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "version.h"
+
+#if JSONCPP_USING_SECURE_MEMORY
+#include "allocator.h" //typedef Allocator
+#endif
+
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json
+{
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else // if defined(_MSC_VER) // Other platforms, use long long
+typedef int64_t Int64;
+typedef uint64_t UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+#if JSONCPP_USING_SECURE_MEMORY
+#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char>>
+#define JSONCPP_OSTRINGSTREAM \
+ std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char>>
+#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>>
+#define JSONCPP_ISTRINGSTREAM \
+ std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char>>
+#define JSONCPP_ISTREAM std::istream
+#else
+#define JSONCPP_STRING std::string
+#define JSONCPP_OSTRINGSTREAM std::ostringstream
+#define JSONCPP_OSTREAM std::ostream
+#define JSONCPP_ISTRINGSTREAM std::istringstream
+#define JSONCPP_ISTREAM std::istream
+#endif // if JSONCPP_USING_SECURE_MEMORY
+} // end namespace Json
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json
+{
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+#define CPPTL_JSON_FEATURES_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json
+{
+
+/** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+class JSON_API Features
+{
+public:
+ /** \brief A configuration that allows all features and assumes all strings
+ * are UTF-8.
+ * - C & C++ comments are allowed
+ * - Root object can be any JSON value
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features all();
+
+ /** \brief A configuration that is strictly compatible with the JSON
+ * specification.
+ * - Comments are forbidden.
+ * - Root object must be either an array or an object value.
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features strictMode();
+
+ /** \brief Initialize the configuration like JsonConfig::allFeatures;
+ */
+ Features();
+
+ /// \c true if comments are allowed. Default: \c true.
+ bool allowComments_;
+
+ /// \c true if root must be either an array or an object value. Default: \c
+ /// false.
+ bool strictRoot_;
+
+ /// \c true if dropped null placeholders are allowed. Default: \c false.
+ bool allowDroppedNullPlaceholders_;
+
+ /// \c true if numeric object key are allowed. Default: \c false.
+ bool allowNumericKeys_;
+};
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/value.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_H_INCLUDED
+#define CPPTL_JSON_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <string>
+#include <vector>
+#include <exception>
+
+#ifndef JSON_USE_CPPTL_SMALLMAP
+#include <map>
+#else
+#include <cpptl/smallmap.h>
+#endif
+#ifdef JSON_USE_CPPTL
+#include <cpptl/forwards.h>
+#endif
+
+// Conditional NORETURN attribute on the throw functions would:
+// a) suppress false positives from static code analysis
+// b) possibly improve optimization opportunities.
+#if !defined(JSONCPP_NORETURN)
+#if defined(_MSC_VER)
+#define JSONCPP_NORETURN __declspec(noreturn)
+#elif defined(__GNUC__)
+#define JSONCPP_NORETURN __attribute__((__noreturn__))
+#else
+#define JSONCPP_NORETURN
+#endif
+#endif
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json
+{
+
+/** Base class for all exceptions we throw.
+ *
+ * We use nothing but these internally. Of course, STL can throw others.
+ */
+class JSON_API Exception : public std::exception
+{
+public:
+ Exception(JSONCPP_STRING const &msg);
+ ~Exception() throw() JSONCPP_OVERRIDE;
+ char const *what() const throw() JSONCPP_OVERRIDE;
+
+protected:
+ JSONCPP_STRING msg_;
+};
+
+/** Exceptions which the user cannot easily avoid.
+ *
+ * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
+ *
+ * \remark derived from Json::Exception
+ */
+class JSON_API RuntimeError : public Exception
+{
+public:
+ RuntimeError(JSONCPP_STRING const &msg);
+};
+
+/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
+ *
+ * These are precondition-violations (user bugs) and internal errors (our bugs).
+ *
+ * \remark derived from Json::Exception
+ */
+class JSON_API LogicError : public Exception
+{
+public:
+ LogicError(JSONCPP_STRING const &msg);
+};
+
+/// used internally
+JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const &msg);
+/// used internally
+JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const &msg);
+
+/** \brief Type of the value held by a Value object.
+ */
+enum ValueType
+{
+ nullValue = 0, ///< 'null' value
+ intValue, ///< signed integer value
+ uintValue, ///< unsigned integer value
+ realValue, ///< double value
+ stringValue, ///< UTF-8 string value
+ booleanValue, ///< bool value
+ arrayValue, ///< array value (ordered list)
+ objectValue ///< object value (collection of name/value pairs).
+};
+
+enum CommentPlacement
+{
+ commentBefore = 0, ///< a comment placed on the line before a value
+ commentAfterOnSameLine, ///< a comment just after a value on the same line
+ commentAfter, ///< a comment on the line after a value (only make sense for
+ /// root value)
+ numberOfCommentPlacement
+};
+
+//# ifdef JSON_USE_CPPTL
+// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
+// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
+//# endif
+
+/** \brief Lightweight wrapper to tag static string.
+ *
+ * Value constructor and objectValue member assignement takes advantage of the
+ * StaticString and avoid the cost of string duplication when storing the
+ * string or the member name.
+ *
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+class JSON_API StaticString
+{
+public:
+ explicit StaticString(const char *czstring) : c_str_(czstring) {}
+
+ operator const char *() const { return c_str_; }
+
+ const char *c_str() const { return c_str_; }
+
+private:
+ const char *c_str_;
+};
+
+/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
+ *
+ * This class is a discriminated union wrapper that can represents a:
+ * - signed integer [range: Value::minInt - Value::maxInt]
+ * - unsigned integer (range: 0 - Value::maxUInt)
+ * - double
+ * - UTF-8 string
+ * - boolean
+ * - 'null'
+ * - an ordered list of Value
+ * - collection of name/value pairs (javascript object)
+ *
+ * The type of the held value is represented by a #ValueType and
+ * can be obtained using type().
+ *
+ * Values of an #objectValue or #arrayValue can be accessed using operator[]()
+ * methods.
+ * Non-const methods will automatically create the a #nullValue element
+ * if it does not exist.
+ * The sequence of an #arrayValue will be automatically resized and initialized
+ * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+ *
+ * The get() methods can be used to obtain default value in the case the
+ * required element does not exist.
+ *
+ * It is possible to iterate over the list of a #objectValue values using
+ * the getMemberNames() method.
+ *
+ * \note #Value string-length fit in size_t, but keys must be < 2^30.
+ * (The reason is an implementation detail.) A #CharReader will raise an
+ * exception if a bound is exceeded to avoid security holes in your app,
+ * but the Value API does *not* check bounds. That is the responsibility
+ * of the caller.
+ */
+class JSON_API Value
+{
+ friend class ValueIteratorBase;
+
+public:
+ typedef std::vector<JSONCPP_STRING> Members;
+ typedef ValueIterator iterator;
+ typedef ValueConstIterator const_iterator;
+ typedef Json::UInt UInt;
+ typedef Json::Int Int;
+#if defined(JSON_HAS_INT64)
+ typedef Json::UInt64 UInt64;
+ typedef Json::Int64 Int64;
+#endif // defined(JSON_HAS_INT64)
+ typedef Json::LargestInt LargestInt;
+ typedef Json::LargestUInt LargestUInt;
+ typedef Json::ArrayIndex ArrayIndex;
+
+ static const Value
+ &null; ///< We regret this reference to a global instance; prefer the simpler Value().
+ static const Value &nullRef; ///< just a kludge for binary-compatibility; same as null
+ static Value const &nullSingleton(); ///< Prefer this to null or nullRef.
+
+ /// Minimum signed integer value that can be stored in a Json::Value.
+ static const LargestInt minLargestInt;
+ /// Maximum signed integer value that can be stored in a Json::Value.
+ static const LargestInt maxLargestInt;
+ /// Maximum unsigned integer value that can be stored in a Json::Value.
+ static const LargestUInt maxLargestUInt;
+
+ /// Minimum signed int value that can be stored in a Json::Value.
+ static const Int minInt;
+ /// Maximum signed int value that can be stored in a Json::Value.
+ static const Int maxInt;
+ /// Maximum unsigned int value that can be stored in a Json::Value.
+ static const UInt maxUInt;
+
+#if defined(JSON_HAS_INT64)
+ /// Minimum signed 64 bits int value that can be stored in a Json::Value.
+ static const Int64 minInt64;
+ /// Maximum signed 64 bits int value that can be stored in a Json::Value.
+ static const Int64 maxInt64;
+ /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
+ static const UInt64 maxUInt64;
+#endif // defined(JSON_HAS_INT64)
+
+private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+ class CZString
+ {
+ public:
+ enum DuplicationPolicy
+ {
+ noDuplication = 0,
+ duplicate,
+ duplicateOnCopy
+ };
+ CZString(ArrayIndex index);
+ CZString(char const *str, unsigned length, DuplicationPolicy allocate);
+ CZString(CZString const &other);
+#if JSON_HAS_RVALUE_REFERENCES
+ CZString(CZString &&other);
+#endif
+ ~CZString();
+ CZString &operator=(CZString other);
+ bool operator<(CZString const &other) const;
+ bool operator==(CZString const &other) const;
+ ArrayIndex index() const;
+ // const char* c_str() const; ///< \deprecated
+ char const *data() const;
+ unsigned length() const;
+ bool isStaticString() const;
+
+ private:
+ void swap(CZString &other);
+
+ struct StringStorage
+ {
+ unsigned policy_ : 2;
+ unsigned length_ : 30; // 1GB max
+ };
+
+ char const *cstr_; // actually, a prefixed string, unless policy is noDup
+ union {
+ ArrayIndex index_;
+ StringStorage storage_;
+ };
+ };
+
+public:
+#ifndef JSON_USE_CPPTL_SMALLMAP
+ typedef std::map<CZString, Value> ObjectValues;
+#else
+ typedef CppTL::SmallMap<CZString, Value> ObjectValues;
+#endif // ifndef JSON_USE_CPPTL_SMALLMAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+public:
+ /** \brief Create a default Value of the given type.
+
+ This is a very useful constructor.
+ To create an empty array, pass arrayValue.
+ To create an empty object, pass objectValue.
+ Another Value can then be set to this one by assignment.
+This is useful since clear() and resize() will not alter types.
+
+ Examples:
+\code
+Json::Value null_value; // null
+Json::Value arr_value(Json::arrayValue); // []
+Json::Value obj_value(Json::objectValue); // {}
+\endcode
+ */
+ Value(ValueType type = nullValue);
+ Value(Int value);
+ Value(UInt value);
+#if defined(JSON_HAS_INT64)
+ Value(Int64 value);
+ Value(UInt64 value);
+#endif // if defined(JSON_HAS_INT64)
+ Value(double value);
+ Value(const char *value); ///< Copy til first 0. (NULL causes to seg-fault.)
+ Value(const char *begin, const char *end); ///< Copy all, incl zeroes.
+ /** \brief Constructs a value from a static string.
+
+ * Like other value string constructor but do not duplicate the string for
+ * internal storage. The given string must remain alive after the call to this
+ * constructor.
+ * \note This works only for null-terminated strings. (We cannot change the
+ * size of this class, so we have nowhere to store the length,
+ * which might be computed later for various operations.)
+ *
+ * Example of usage:
+ * \code
+ * static StaticString foo("some text");
+ * Json::Value aValue(foo);
+ * \endcode
+ */
+ Value(const StaticString &value);
+ Value(const JSONCPP_STRING &value); ///< Copy data() til size(). Embedded zeroes too.
+#ifdef JSON_USE_CPPTL
+ Value(const CppTL::ConstString &value);
+#endif
+ Value(bool value);
+ /// Deep copy.
+ Value(const Value &other);
+#if JSON_HAS_RVALUE_REFERENCES
+ /// Move constructor
+ Value(Value &&other);
+#endif
+ ~Value();
+
+ /// Deep copy, then swap(other).
+ /// \note Over-write existing comments. To preserve comments, use #swapPayload().
+ Value &operator=(Value other);
+ /// Swap everything.
+ void swap(Value &other);
+ /// Swap values but leave comments and source offsets in place.
+ void swapPayload(Value &other);
+
+ ValueType type() const;
+
+ /// Compare payload only, not comments etc.
+ bool operator<(const Value &other) const;
+ bool operator<=(const Value &other) const;
+ bool operator>=(const Value &other) const;
+ bool operator>(const Value &other) const;
+ bool operator==(const Value &other) const;
+ bool operator!=(const Value &other) const;
+ int compare(const Value &other) const;
+
+ const char *asCString() const; ///< Embedded zeroes could cause you trouble!
+#if JSONCPP_USING_SECURE_MEMORY
+ unsigned getCStringLength() const; // Allows you to understand the length of the CString
+#endif
+ JSONCPP_STRING asString() const; ///< Embedded zeroes are possible.
+ /** Get raw char* of string-value.
+ * \return false if !string. (Seg-fault if str or end are NULL.)
+ */
+ bool getString(char const **begin, char const **end) const;
+#ifdef JSON_USE_CPPTL
+ CppTL::ConstString asConstString() const;
+#endif
+ Int asInt() const;
+ UInt asUInt() const;
+#if defined(JSON_HAS_INT64)
+ Int64 asInt64() const;
+ UInt64 asUInt64() const;
+#endif // if defined(JSON_HAS_INT64)
+ LargestInt asLargestInt() const;
+ LargestUInt asLargestUInt() const;
+ float asFloat() const;
+ double asDouble() const;
+ bool asBool() const;
+
+ bool isNull() const;
+ bool isBool() const;
+ bool isInt() const;
+ bool isInt64() const;
+ bool isUInt() const;
+ bool isUInt64() const;
+ bool isIntegral() const;
+ bool isDouble() const;
+ bool isNumeric() const;
+ bool isString() const;
+ bool isArray() const;
+ bool isObject() const;
+
+ bool isConvertibleTo(ValueType other) const;
+
+ /// Number of values in array or object
+ ArrayIndex size() const;
+
+ /// \brief Return true if empty array, empty object, or null;
+ /// otherwise, false.
+ bool empty() const;
+
+ /// Return isNull()
+ bool operator!() const;
+
+ /// Remove all object members and array elements.
+ /// \pre type() is arrayValue, objectValue, or nullValue
+ /// \post type() is unchanged
+ void clear();
+
+ /// Resize the array to size elements.
+ /// New elements are initialized to null.
+ /// May only be called on nullValue or arrayValue.
+ /// \pre type() is arrayValue or nullValue
+ /// \post type() is arrayValue
+ void resize(ArrayIndex size);
+
+ /// Access an array element (zero based index ).
+ /// If the array contains less than index element, then null value are
+ /// inserted
+ /// in the array so that its size is index+1.
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ Value &operator[](ArrayIndex index);
+
+ /// Access an array element (zero based index ).
+ /// If the array contains less than index element, then null value are
+ /// inserted
+ /// in the array so that its size is index+1.
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ Value &operator[](int index);
+
+ /// Access an array element (zero based index )
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ const Value &operator[](ArrayIndex index) const;
+
+ /// Access an array element (zero based index )
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ const Value &operator[](int index) const;
+
+ /// If the array contains at least index+1 elements, returns the element
+ /// value,
+ /// otherwise returns defaultValue.
+ Value get(ArrayIndex index, const Value &defaultValue) const;
+ /// Return true if index < size().
+ bool isValidIndex(ArrayIndex index) const;
+ /// \brief Append value to array at the end.
+ ///
+ /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+ Value &append(const Value &value);
+
+ /// Access an object value by name, create a null member if it does not exist.
+ /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
+ /// Exceeding that will cause an exception.
+ Value &operator[](const char *key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ const Value &operator[](const char *key) const;
+ /// Access an object value by name, create a null member if it does not exist.
+ /// \param key may contain embedded nulls.
+ Value &operator[](const JSONCPP_STRING &key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ /// \param key may contain embedded nulls.
+ const Value &operator[](const JSONCPP_STRING &key) const;
+ /** \brief Access an object value by name, create a null member if it does not
+ exist.
+
+ * If the object has no entry for that name, then the member name used to store
+ * the new entry is not duplicated.
+ * Example of use:
+ * \code
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+ Value &operator[](const StaticString &key);
+#ifdef JSON_USE_CPPTL
+ /// Access an object value by name, create a null member if it does not exist.
+ Value &operator[](const CppTL::ConstString &key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ const Value &operator[](const CppTL::ConstString &key) const;
+#endif
+ /// Return the member named key if it exist, defaultValue otherwise.
+ /// \note deep copy
+ Value get(const char *key, const Value &defaultValue) const;
+ /// Return the member named key if it exist, defaultValue otherwise.
+ /// \note deep copy
+ /// \note key may contain embedded nulls.
+ Value get(const char *begin, const char *end, const Value &defaultValue) const;
+ /// Return the member named key if it exist, defaultValue otherwise.
+ /// \note deep copy
+ /// \param key may contain embedded nulls.
+ Value get(const JSONCPP_STRING &key, const Value &defaultValue) const;
+#ifdef JSON_USE_CPPTL
+ /// Return the member named key if it exist, defaultValue otherwise.
+ /// \note deep copy
+ Value get(const CppTL::ConstString &key, const Value &defaultValue) const;
+#endif
+ /// Most general and efficient version of isMember()const, get()const,
+ /// and operator[]const
+ /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
+ Value const *find(char const *begin, char const *end) const;
+ /// Most general and efficient version of object-mutators.
+ /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
+ /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
+ Value const *demand(char const *begin, char const *end);
+ /// \brief Remove and return the named member.
+ ///
+ /// Do nothing if it did not exist.
+ /// \return the removed Value, or null.
+ /// \pre type() is objectValue or nullValue
+ /// \post type() is unchanged
+ /// \deprecated
+ Value removeMember(const char *key);
+ /// Same as removeMember(const char*)
+ /// \param key may contain embedded nulls.
+ /// \deprecated
+ Value removeMember(const JSONCPP_STRING &key);
+ /// Same as removeMember(const char* begin, const char* end, Value* removed),
+ /// but 'key' is null-terminated.
+ bool removeMember(const char *key, Value *removed);
+ /** \brief Remove the named map member.
+
+ Update 'removed' iff removed.
+ \param key may contain embedded nulls.
+ \return true iff removed (no exceptions)
+ */
+ bool removeMember(JSONCPP_STRING const &key, Value *removed);
+ /// Same as removeMember(JSONCPP_STRING const& key, Value* removed)
+ bool removeMember(const char *begin, const char *end, Value *removed);
+ /** \brief Remove the indexed array element.
+
+ O(n) expensive operations.
+ Update 'removed' iff removed.
+ \return true iff removed (no exceptions)
+ */
+ bool removeIndex(ArrayIndex i, Value *removed);
+
+ /// Return true if the object has a member named key.
+ /// \note 'key' must be null-terminated.
+ bool isMember(const char *key) const;
+ /// Return true if the object has a member named key.
+ /// \param key may contain embedded nulls.
+ bool isMember(const JSONCPP_STRING &key) const;
+ /// Same as isMember(JSONCPP_STRING const& key)const
+ bool isMember(const char *begin, const char *end) const;
+#ifdef JSON_USE_CPPTL
+ /// Return true if the object has a member named key.
+ bool isMember(const CppTL::ConstString &key) const;
+#endif
+
+ /// \brief Return a list of the member names.
+ ///
+ /// If null, return an empty list.
+ /// \pre type() is objectValue or nullValue
+ /// \post if type() was nullValue, it remains nullValue
+ Members getMemberNames() const;
+
+ //# ifdef JSON_USE_CPPTL
+ // EnumMemberNames enumMemberNames() const;
+ // EnumValues enumValues() const;
+ //# endif
+
+ /// \deprecated Always pass len.
+ JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.")
+ void setComment(const char *comment, CommentPlacement placement);
+ /// Comments must be //... or /* ... */
+ void setComment(const char *comment, size_t len, CommentPlacement placement);
+ /// Comments must be //... or /* ... */
+ void setComment(const JSONCPP_STRING &comment, CommentPlacement placement);
+ bool hasComment(CommentPlacement placement) const;
+ /// Include delimiters and embedded newlines.
+ JSONCPP_STRING getComment(CommentPlacement placement) const;
+
+ JSONCPP_STRING toStyledString() const;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator begin();
+ iterator end();
+
+ // Accessors for the [start, limit) range of bytes within the JSON text from
+ // which this value was parsed, if any.
+ void setOffsetStart(ptrdiff_t start);
+ void setOffsetLimit(ptrdiff_t limit);
+ ptrdiff_t getOffsetStart() const;
+ ptrdiff_t getOffsetLimit() const;
+
+private:
+ void initBasic(ValueType type, bool allocated = false);
+
+ Value &resolveReference(const char *key);
+ Value &resolveReference(const char *key, const char *end);
+
+ struct CommentInfo
+ {
+ CommentInfo();
+ ~CommentInfo();
+
+ void setComment(const char *text, size_t len);
+
+ char *comment_;
+ };
+
+ // struct MemberNamesTransform
+ //{
+ // typedef const char *result_type;
+ // const char *operator()( const CZString &name ) const
+ // {
+ // return name.c_str();
+ // }
+ //};
+
+ union ValueHolder {
+ LargestInt int_;
+ LargestUInt uint_;
+ double real_;
+ bool bool_;
+ char *string_; // actually ptr to unsigned, followed by str, unless !allocated_
+ ObjectValues *map_;
+ } value_;
+ ValueType type_ : 8;
+ unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
+ // If not allocated_, string_ must be null-terminated.
+ CommentInfo *comments_;
+
+ // [start, limit) byte offsets in the source JSON text from which this Value
+ // was extracted.
+ ptrdiff_t start_;
+ ptrdiff_t limit_;
+};
+
+/** \brief Experimental and untested: represents an element of the "path" to
+ * access a node.
+ */
+class JSON_API PathArgument
+{
+public:
+ friend class Path;
+
+ PathArgument();
+ PathArgument(ArrayIndex index);
+ PathArgument(const char *key);
+ PathArgument(const JSONCPP_STRING &key);
+
+private:
+ enum Kind
+ {
+ kindNone = 0,
+ kindIndex,
+ kindKey
+ };
+ JSONCPP_STRING key_;
+ ArrayIndex index_;
+ Kind kind_;
+};
+
+/** \brief Experimental and untested: represents a "path" to access a node.
+ *
+ * Syntax:
+ * - "." => root node
+ * - ".[n]" => elements at index 'n' of root node (an array value)
+ * - ".name" => member named 'name' of root node (an object value)
+ * - ".name1.name2.name3"
+ * - ".[0][1][2].name1[3]"
+ * - ".%" => member name is provided as parameter
+ * - ".[%]" => index is provied as parameter
+ */
+class JSON_API Path
+{
+public:
+ Path(const JSONCPP_STRING &path, const PathArgument &a1 = PathArgument(),
+ const PathArgument &a2 = PathArgument(), const PathArgument &a3 = PathArgument(),
+ const PathArgument &a4 = PathArgument(), const PathArgument &a5 = PathArgument());
+
+ const Value &resolve(const Value &root) const;
+ Value resolve(const Value &root, const Value &defaultValue) const;
+ /// Creates the "path" to access the specified node and returns a reference on
+ /// the node.
+ Value &make(Value &root) const;
+
+private:
+ typedef std::vector<const PathArgument *> InArgs;
+ typedef std::vector<PathArgument> Args;
+
+ void makePath(const JSONCPP_STRING &path, const InArgs &in);
+ void addPathInArg(const JSONCPP_STRING &path, const InArgs &in, InArgs::const_iterator &itInArg,
+ PathArgument::Kind kind);
+ void invalidPath(const JSONCPP_STRING &path, int location);
+
+ Args args_;
+};
+
+/** \brief base class for Value iterators.
+ *
+ */
+class JSON_API ValueIteratorBase
+{
+public:
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef ValueIteratorBase SelfType;
+
+ bool operator==(const SelfType &other) const { return isEqual(other); }
+
+ bool operator!=(const SelfType &other) const { return !isEqual(other); }
+
+ difference_type operator-(const SelfType &other) const { return other.computeDistance(*this); }
+
+ /// Return either the index or the member name of the referenced value as a
+ /// Value.
+ Value key() const;
+
+ /// Return the index of the referenced Value, or -1 if it is not an arrayValue.
+ UInt index() const;
+
+ /// Return the member name of the referenced Value, or "" if it is not an
+ /// objectValue.
+ /// \note Avoid `c_str()` on result, as embedded zeroes are possible.
+ JSONCPP_STRING name() const;
+
+ /// Return the member name of the referenced Value. "" if it is not an
+ /// objectValue.
+ /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
+ JSONCPP_DEPRECATED("Use `key = name();` instead.")
+ char const *memberName() const;
+ /// Return the member name of the referenced Value, or NULL if it is not an
+ /// objectValue.
+ /// \note Better version than memberName(). Allows embedded nulls.
+ char const *memberName(char const **end) const;
+
+protected:
+ Value &deref() const;
+
+ void increment();
+
+ void decrement();
+
+ difference_type computeDistance(const SelfType &other) const;
+
+ bool isEqual(const SelfType &other) const;
+
+ void copy(const SelfType &other);
+
+private:
+ Value::ObjectValues::iterator current_;
+ // Indicates that iterator is for a null value.
+ bool isNull_;
+
+public:
+ // For some reason, BORLAND needs these at the end, rather
+ // than earlier. No idea why.
+ ValueIteratorBase();
+ explicit ValueIteratorBase(const Value::ObjectValues::iterator &current);
+};
+
+/** \brief const iterator for object and array value.
+ *
+ */
+class JSON_API ValueConstIterator : public ValueIteratorBase
+{
+ friend class Value;
+
+public:
+ typedef const Value value_type;
+ // typedef unsigned int size_t;
+ // typedef int difference_type;
+ typedef const Value &reference;
+ typedef const Value *pointer;
+ typedef ValueConstIterator SelfType;
+
+ ValueConstIterator();
+ ValueConstIterator(ValueIterator const &other);
+
+private:
+ /*! \internal Use by Value to create an iterator.
+ */
+ explicit ValueConstIterator(const Value::ObjectValues::iterator &current);
+
+public:
+ SelfType &operator=(const ValueIteratorBase &other);
+
+ SelfType operator++(int)
+ {
+ SelfType temp(*this);
+ ++*this;
+ return temp;
+ }
+
+ SelfType operator--(int)
+ {
+ SelfType temp(*this);
+ --*this;
+ return temp;
+ }
+
+ SelfType &operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ SelfType &operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ reference operator*() const { return deref(); }
+
+ pointer operator->() const { return &deref(); }
+};
+
+/** \brief Iterator for object and array value.
+ */
+class JSON_API ValueIterator : public ValueIteratorBase
+{
+ friend class Value;
+
+public:
+ typedef Value value_type;
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef Value &reference;
+ typedef Value *pointer;
+ typedef ValueIterator SelfType;
+
+ ValueIterator();
+ explicit ValueIterator(const ValueConstIterator &other);
+ ValueIterator(const ValueIterator &other);
+
+private:
+ /*! \internal Use by Value to create an iterator.
+ */
+ explicit ValueIterator(const Value::ObjectValues::iterator &current);
+
+public:
+ SelfType &operator=(const SelfType &other);
+
+ SelfType operator++(int)
+ {
+ SelfType temp(*this);
+ ++*this;
+ return temp;
+ }
+
+ SelfType operator--(int)
+ {
+ SelfType temp(*this);
+ --*this;
+ return temp;
+ }
+
+ SelfType &operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ SelfType &operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ reference operator*() const { return deref(); }
+
+ pointer operator->() const { return &deref(); }
+};
+
+} // namespace Json
+
+namespace std
+{
+/// Specialize std::swap() for Json::Value.
+template <> inline void swap(Json::Value &a, Json::Value &b) { a.swap(b); }
+}
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/value.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/reader.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+#define CPPTL_JSON_READER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "features.h"
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <deque>
+#include <iosfwd>
+#include <stack>
+#include <string>
+#include <istream>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json
+{
+
+/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
+ *Value.
+ *
+ * \deprecated Use CharReader and CharReaderBuilder.
+ */
+class JSON_API Reader
+{
+public:
+ typedef char Char;
+ typedef const Char *Location;
+
+ /** \brief An error tagged with where in the JSON text it was encountered.
+ *
+ * The offsets give the [start, limit) range of bytes within the text. Note
+ * that this is bytes, not codepoints.
+ *
+ */
+ struct StructuredError
+ {
+ ptrdiff_t offset_start;
+ ptrdiff_t offset_limit;
+ JSONCPP_STRING message;
+ };
+
+ /** \brief Constructs a Reader allowing all features
+ * for parsing.
+ */
+ Reader();
+
+ /** \brief Constructs a Reader allowing the specified feature set
+ * for parsing.
+ */
+ Reader(const Features &features);
+
+ /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+ * document.
+ * \param document UTF-8 encoded string containing the document to read.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param collectComments \c true to collect comment and allow writing them
+ * back during
+ * serialization, \c false to discard comments.
+ * This parameter is ignored if
+ * Features::allowComments_
+ * is \c false.
+ * \return \c true if the document was successfully parsed, \c false if an
+ * error occurred.
+ */
+ bool parse(const std::string &document, Value &root, bool collectComments = true);
+
+ /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+ document.
+ * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
+ document to read.
+ * \param endDoc Pointer on the end of the UTF-8 encoded string of the
+ document to read.
+ * Must be >= beginDoc.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param collectComments \c true to collect comment and allow writing them
+ back during
+ * serialization, \c false to discard comments.
+ * This parameter is ignored if
+ Features::allowComments_
+ * is \c false.
+ * \return \c true if the document was successfully parsed, \c false if an
+ error occurred.
+ */
+ bool parse(const char *beginDoc, const char *endDoc, Value &root, bool collectComments = true);
+
+ /// \brief Parse from input stream.
+ /// \see Json::operator>>(std::istream&, Json::Value&).
+ bool parse(JSONCPP_ISTREAM &is, Value &root, bool collectComments = true);
+
+ /** \brief Returns a user friendly string that list errors in the parsed
+ * document.
+ * \return Formatted error message with the list of errors with their location
+ * in
+ * the parsed document. An empty string is returned if no error
+ * occurred
+ * during parsing.
+ * \deprecated Use getFormattedErrorMessages() instead (typo fix).
+ */
+ JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
+ JSONCPP_STRING getFormatedErrorMessages() const;
+
+ /** \brief Returns a user friendly string that list errors in the parsed
+ * document.
+ * \return Formatted error message with the list of errors with their location
+ * in
+ * the parsed document. An empty string is returned if no error
+ * occurred
+ * during parsing.
+ */
+ JSONCPP_STRING getFormattedErrorMessages() const;
+
+ /** \brief Returns a vector of structured erros encounted while parsing.
+ * \return A (possibly empty) vector of StructuredError objects. Currently
+ * only one error can be returned, but the caller should tolerate
+ * multiple
+ * errors. This can occur if the parser recovers from a non-fatal
+ * parse error and then encounters additional errors.
+ */
+ std::vector<StructuredError> getStructuredErrors() const;
+
+ /** \brief Add a semantic error message.
+ * \param value JSON Value location associated with the error
+ * \param message The error message.
+ * \return \c true if the error was successfully added, \c false if the
+ * Value offset exceeds the document size.
+ */
+ bool pushError(const Value &value, const JSONCPP_STRING &message);
+
+ /** \brief Add a semantic error message with extra context.
+ * \param value JSON Value location associated with the error
+ * \param message The error message.
+ * \param extra Additional JSON Value location to contextualize the error
+ * \return \c true if the error was successfully added, \c false if either
+ * Value offset exceeds the document size.
+ */
+ bool pushError(const Value &value, const JSONCPP_STRING &message, const Value &extra);
+
+ /** \brief Return whether there are any errors.
+ * \return \c true if there are no errors to report \c false if
+ * errors have occurred.
+ */
+ bool good() const;
+
+private:
+ enum TokenType
+ {
+ tokenEndOfStream = 0,
+ tokenObjectBegin,
+ tokenObjectEnd,
+ tokenArrayBegin,
+ tokenArrayEnd,
+ tokenString,
+ tokenNumber,
+ tokenTrue,
+ tokenFalse,
+ tokenNull,
+ tokenArraySeparator,
+ tokenMemberSeparator,
+ tokenComment,
+ tokenError
+ };
+
+ class Token
+ {
+ public:
+ TokenType type_;
+ Location start_;
+ Location end_;
+ };
+
+ class ErrorInfo
+ {
+ public:
+ Token token_;
+ JSONCPP_STRING message_;
+ Location extra_;
+ };
+
+ typedef std::deque<ErrorInfo> Errors;
+
+ bool readToken(Token &token);
+ void skipSpaces();
+ bool match(Location pattern, int patternLength);
+ bool readComment();
+ bool readCStyleComment();
+ bool readCppStyleComment();
+ bool readString();
+ void readNumber();
+ bool readValue();
+ bool readObject(Token &token);
+ bool readArray(Token &token);
+ bool decodeNumber(Token &token);
+ bool decodeNumber(Token &token, Value &decoded);
+ bool decodeString(Token &token);
+ bool decodeString(Token &token, JSONCPP_STRING &decoded);
+ bool decodeDouble(Token &token);
+ bool decodeDouble(Token &token, Value &decoded);
+ bool decodeUnicodeCodePoint(Token &token, Location &current, Location end, unsigned int &unicode);
+ bool decodeUnicodeEscapeSequence(Token &token, Location &current, Location end,
+ unsigned int &unicode);
+ bool addError(const JSONCPP_STRING &message, Token &token, Location extra = 0);
+ bool recoverFromError(TokenType skipUntilToken);
+ bool addErrorAndRecover(const JSONCPP_STRING &message, Token &token, TokenType skipUntilToken);
+ void skipUntilSpace();
+ Value &currentValue();
+ Char getNextChar();
+ void getLocationLineAndColumn(Location location, int &line, int &column) const;
+ JSONCPP_STRING getLocationLineAndColumn(Location location) const;
+ void addComment(Location begin, Location end, CommentPlacement placement);
+ void skipCommentTokens(Token &token);
+
+ typedef std::stack<Value *> Nodes;
+ Nodes nodes_;
+ Errors errors_;
+ JSONCPP_STRING document_;
+ Location begin_;
+ Location end_;
+ Location current_;
+ Location lastValueEnd_;
+ Value *lastValue_;
+ JSONCPP_STRING commentsBefore_;
+ Features features_;
+ bool collectComments_;
+}; // Reader
+
+/** Interface for reading JSON from a char array.
+ */
+class JSON_API CharReader
+{
+public:
+ virtual ~CharReader() {}
+ /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+ document.
+ * The document must be a UTF-8 encoded string containing the document to read.
+ *
+ * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
+ document to read.
+ * \param endDoc Pointer on the end of the UTF-8 encoded string of the
+ document to read.
+ * Must be >= beginDoc.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param errs [out] Formatted error messages (if not NULL)
+ * a user friendly string that lists errors in the parsed
+ * document.
+ * \return \c true if the document was successfully parsed, \c false if an
+ error occurred.
+ */
+ virtual bool parse(char const *beginDoc, char const *endDoc, Value *root,
+ JSONCPP_STRING *errs) = 0;
+
+ class JSON_API Factory
+ {
+ public:
+ virtual ~Factory() {}
+ /** \brief Allocate a CharReader via operator new().
+ * \throw std::exception if something goes wrong (e.g. invalid settings)
+ */
+ virtual CharReader *newCharReader() const = 0;
+ }; // Factory
+}; // CharReader
+
+/** \brief Build a CharReader implementation.
+
+Usage:
+\code
+ using namespace Json;
+ CharReaderBuilder builder;
+ builder["collectComments"] = false;
+ Value value;
+ JSONCPP_STRING errs;
+ bool ok = parseFromStream(builder, std::cin, &value, &errs);
+\endcode
+*/
+class JSON_API CharReaderBuilder : public CharReader::Factory
+{
+public:
+ // Note: We use a Json::Value so that we can add data-members to this class
+ // without a major version bump.
+ /** Configuration of this builder.
+ These are case-sensitive.
+ Available settings (case-sensitive):
+ - `"collectComments": false or true`
+ - true to collect comment and allow writing them
+ back during serialization, false to discard comments.
+ This parameter is ignored if allowComments is false.
+ - `"allowComments": false or true`
+ - true if comments are allowed.
+ - `"strictRoot": false or true`
+ - true if root must be either an array or an object value
+ - `"allowDroppedNullPlaceholders": false or true`
+ - true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
+ - `"allowNumericKeys": false or true`
+ - true if numeric object keys are allowed.
+ - `"allowSingleQuotes": false or true`
+ - true if '' are allowed for strings (both keys and values)
+ - `"stackLimit": integer`
+ - Exceeding stackLimit (recursive depth of `readValue()`) will
+ cause an exception.
+ - This is a security issue (seg-faults caused by deeply nested JSON),
+ so the default is low.
+ - `"failIfExtra": false or true`
+ - If true, `parse()` returns false when extra non-whitespace trails
+ the JSON value in the input string.
+ - `"rejectDupKeys": false or true`
+ - If true, `parse()` returns false when a key is duplicated within an object.
+ - `"allowSpecialFloats": false or true`
+ - If true, special float values (NaNs and infinities) are allowed
+ and their values are lossfree restorable.
+
+ You can examine 'settings_` yourself
+ to see the defaults. You can also write and read them just like any
+ JSON Value.
+ \sa setDefaults()
+ */
+ Json::Value settings_;
+
+ CharReaderBuilder();
+ ~CharReaderBuilder() JSONCPP_OVERRIDE;
+
+ CharReader *newCharReader() const JSONCPP_OVERRIDE;
+
+ /** \return true if 'settings' are legal and consistent;
+ * otherwise, indicate bad settings via 'invalid'.
+ */
+ bool validate(Json::Value *invalid) const;
+
+ /** A simple way to update a specific setting.
+ */
+ Value &operator[](JSONCPP_STRING key);
+
+ /** Called by ctor, but you can use this to reset settings_.
+ * \pre 'settings' != NULL (but Json::null is fine)
+ * \remark Defaults:
+ * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
+ */
+ static void setDefaults(Json::Value *settings);
+ /** Same as old Features::strictMode().
+ * \pre 'settings' != NULL (but Json::null is fine)
+ * \remark Defaults:
+ * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
+ */
+ static void strictMode(Json::Value *settings);
+};
+
+/** Consume entire stream and use its begin/end.
+ * Someday we might have a real StreamReader, but for now this
+ * is convenient.
+ */
+bool JSON_API parseFromStream(CharReader::Factory const &, JSONCPP_ISTREAM &, Value *root,
+ std::string *errs);
+
+/** \brief Read from 'sin' into 'root'.
+
+ Always keep comments from the input JSON.
+
+ This can be used to read a file into a particular sub-object.
+ For example:
+ \code
+ Json::Value root;
+ cin >> root["dir"]["file"];
+ cout << root;
+ \endcode
+ Result:
+ \verbatim
+ {
+ "dir": {
+ "file": {
+ // The input stream JSON would be nested here.
+ }
+ }
+ }
+ \endverbatim
+ \throw std::exception on parse error.
+ \see Json::operator<<()
+*/
+JSON_API JSONCPP_ISTREAM &operator>>(JSONCPP_ISTREAM &, Value &);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/reader.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/writer.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_WRITER_H_INCLUDED
+#define JSON_WRITER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <vector>
+#include <string>
+#include <ostream>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json
+{
+
+class Value;
+
+/**
+
+Usage:
+\code
+ using namespace Json;
+ void writeToStdout(StreamWriter::Factory const& factory, Value const& value) {
+ std::unique_ptr<StreamWriter> const writer(
+ factory.newStreamWriter());
+ writer->write(value, &std::cout);
+ std::cout << std::endl; // add lf and flush
+ }
+\endcode
+*/
+class JSON_API StreamWriter
+{
+protected:
+ JSONCPP_OSTREAM *sout_; // not owned; will not delete
+public:
+ StreamWriter();
+ virtual ~StreamWriter();
+ /** Write Value into document as configured in sub-class.
+ Do not take ownership of sout, but maintain a reference during function.
+ \pre sout != NULL
+ \return zero on success (For now, we always return zero, so check the stream instead.)
+ \throw std::exception possibly, depending on configuration
+ */
+ virtual int write(Value const &root, JSONCPP_OSTREAM *sout) = 0;
+
+ /** \brief A simple abstract factory.
+ */
+ class JSON_API Factory
+ {
+ public:
+ virtual ~Factory();
+ /** \brief Allocate a CharReader via operator new().
+ * \throw std::exception if something goes wrong (e.g. invalid settings)
+ */
+ virtual StreamWriter *newStreamWriter() const = 0;
+ }; // Factory
+}; // StreamWriter
+
+/** \brief Write into stringstream, then return string, for convenience.
+ * A StreamWriter will be created from the factory, used, and then deleted.
+ */
+JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const &factory, Value const &root);
+
+/** \brief Build a StreamWriter implementation.
+
+Usage:
+\code
+ using namespace Json;
+ Value value = ...;
+ StreamWriterBuilder builder;
+ builder["commentStyle"] = "None";
+ builder["indentation"] = " "; // or whatever you like
+ std::unique_ptr<Json::StreamWriter> writer(
+ builder.newStreamWriter());
+ writer->write(value, &std::cout);
+ std::cout << std::endl; // add lf and flush
+\endcode
+*/
+class JSON_API StreamWriterBuilder : public StreamWriter::Factory
+{
+public:
+ // Note: We use a Json::Value so that we can add data-members to this class
+ // without a major version bump.
+ /** Configuration of this builder.
+ Available settings (case-sensitive):
+ - "commentStyle": "None" or "All"
+ - "indentation": "<anything>"
+ - "enableYAMLCompatibility": false or true
+ - slightly change the whitespace around colons
+ - "dropNullPlaceholders": false or true
+ - Drop the "null" string from the writer's output for nullValues.
+ Strictly speaking, this is not valid JSON. But when the output is being
+ fed to a browser's Javascript, it makes for smaller output and the
+ browser can handle the output just fine.
+ - "useSpecialFloats": false or true
+ - If true, outputs non-finite floating point values in the following way:
+ NaN values as "NaN", positive infinity as "Infinity", and negative infinity
+ as "-Infinity".
+
+ You can examine 'settings_` yourself
+ to see the defaults. You can also write and read them just like any
+ JSON Value.
+ \sa setDefaults()
+ */
+ Json::Value settings_;
+
+ StreamWriterBuilder();
+ ~StreamWriterBuilder() JSONCPP_OVERRIDE;
+
+ /**
+ * \throw std::exception if something goes wrong (e.g. invalid settings)
+ */
+ StreamWriter *newStreamWriter() const JSONCPP_OVERRIDE;
+
+ /** \return true if 'settings' are legal and consistent;
+ * otherwise, indicate bad settings via 'invalid'.
+ */
+ bool validate(Json::Value *invalid) const;
+ /** A simple way to update a specific setting.
+ */
+ Value &operator[](JSONCPP_STRING key);
+
+ /** Called by ctor, but you can use this to reset settings_.
+ * \pre 'settings' != NULL (but Json::null is fine)
+ * \remark Defaults:
+ * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
+ */
+ static void setDefaults(Json::Value *settings);
+};
+
+/** \brief Abstract class for writers.
+ * \deprecated Use StreamWriter. (And really, this is an implementation detail.)
+ */
+class JSON_API Writer
+{
+public:
+ virtual ~Writer();
+
+ virtual JSONCPP_STRING write(const Value &root) = 0;
+};
+
+/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
+ *without formatting (not human friendly).
+ *
+ * The JSON document is written in a single line. It is not intended for 'human'
+ *consumption,
+ * but may be usefull to support feature such as RPC where bandwith is limited.
+ * \sa Reader, Value
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API FastWriter : public Writer
+{
+
+public:
+ FastWriter();
+ ~FastWriter() JSONCPP_OVERRIDE {}
+
+ void enableYAMLCompatibility();
+
+ /** \brief Drop the "null" string from the writer's output for nullValues.
+ * Strictly speaking, this is not valid JSON. But when the output is being
+ * fed to a browser's Javascript, it makes for smaller output and the
+ * browser can handle the output just fine.
+ */
+ void dropNullPlaceholders();
+
+ void omitEndingLineFeed();
+
+public: // overridden from Writer
+ JSONCPP_STRING write(const Value &root) JSONCPP_OVERRIDE;
+
+private:
+ void writeValue(const Value &value);
+
+ JSONCPP_STRING document_;
+ bool yamlCompatiblityEnabled_;
+ bool dropNullPlaceholders_;
+ bool omitEndingLineFeed_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ *human friendly way.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ * - if empty then print {} without indent and line break
+ * - if not empty the print '{', line break & indent, print one value per
+ *line
+ * and then unindent and line break and print '}'.
+ * - Array value:
+ * - if empty then print [] without indent and line break
+ * - if the array contains no object value, empty array or some other value
+ *types,
+ * and all the values fit on one lines, then print the array on a single
+ *line.
+ * - otherwise, it the values do not fit on one line, or the array contains
+ * object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ *#CommentPlacement.
+ *
+ * \sa Reader, Value, Value::setComment()
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API StyledWriter : public Writer
+{
+public:
+ StyledWriter();
+ ~StyledWriter() JSONCPP_OVERRIDE {}
+
+public: // overridden from Writer
+ /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+ * \param root Value to serialize.
+ * \return String containing the JSON document that represents the root value.
+ */
+ JSONCPP_STRING write(const Value &root) JSONCPP_OVERRIDE;
+
+private:
+ void writeValue(const Value &value);
+ void writeArrayValue(const Value &value);
+ bool isMultineArray(const Value &value);
+ void pushValue(const JSONCPP_STRING &value);
+ void writeIndent();
+ void writeWithIndent(const JSONCPP_STRING &value);
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue(const Value &root);
+ void writeCommentAfterValueOnSameLine(const Value &root);
+ bool hasCommentForValue(const Value &value);
+ static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING &text);
+
+ typedef std::vector<JSONCPP_STRING> ChildValues;
+
+ ChildValues childValues_;
+ JSONCPP_STRING document_;
+ JSONCPP_STRING indentString_;
+ unsigned int rightMargin_;
+ unsigned int indentSize_;
+ bool addChildValues_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ human friendly way,
+ to a stream rather than to a string.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ * - if empty then print {} without indent and line break
+ * - if not empty the print '{', line break & indent, print one value per
+ line
+ * and then unindent and line break and print '}'.
+ * - Array value:
+ * - if empty then print [] without indent and line break
+ * - if the array contains no object value, empty array or some other value
+ types,
+ * and all the values fit on one lines, then print the array on a single
+ line.
+ * - otherwise, it the values do not fit on one line, or the array contains
+ * object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ #CommentPlacement.
+ *
+ * \param indentation Each level will be indented by this amount extra.
+ * \sa Reader, Value, Value::setComment()
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API StyledStreamWriter
+{
+public:
+ StyledStreamWriter(JSONCPP_STRING indentation = "\t");
+ ~StyledStreamWriter() {}
+
+public:
+ /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+ * \param out Stream to write to. (Can be ostringstream, e.g.)
+ * \param root Value to serialize.
+ * \note There is no point in deriving from Writer, since write() should not
+ * return a value.
+ */
+ void write(JSONCPP_OSTREAM &out, const Value &root);
+
+private:
+ void writeValue(const Value &value);
+ void writeArrayValue(const Value &value);
+ bool isMultineArray(const Value &value);
+ void pushValue(const JSONCPP_STRING &value);
+ void writeIndent();
+ void writeWithIndent(const JSONCPP_STRING &value);
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue(const Value &root);
+ void writeCommentAfterValueOnSameLine(const Value &root);
+ bool hasCommentForValue(const Value &value);
+ static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING &text);
+
+ typedef std::vector<JSONCPP_STRING> ChildValues;
+
+ ChildValues childValues_;
+ JSONCPP_OSTREAM *document_;
+ JSONCPP_STRING indentString_;
+ unsigned int rightMargin_;
+ JSONCPP_STRING indentation_;
+ bool addChildValues_ : 1;
+ bool indented_ : 1;
+};
+
+#if defined(JSON_HAS_INT64)
+JSONCPP_STRING JSON_API valueToString(Int value);
+JSONCPP_STRING JSON_API valueToString(UInt value);
+#endif // if defined(JSON_HAS_INT64)
+JSONCPP_STRING JSON_API valueToString(LargestInt value);
+JSONCPP_STRING JSON_API valueToString(LargestUInt value);
+JSONCPP_STRING JSON_API valueToString(double value);
+JSONCPP_STRING JSON_API valueToString(bool value);
+JSONCPP_STRING JSON_API valueToQuotedString(const char *value);
+
+/// \brief Output using the StyledStreamWriter.
+/// \see Json::operator>>()
+JSON_API JSONCPP_OSTREAM &operator<<(JSONCPP_OSTREAM &, const Value &root);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // JSON_WRITER_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/writer.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/assertions.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+#include <stdlib.h>
+#include <sstream>
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+/** It should not be possible for a maliciously designed file to
+ * cause an abort() or seg-fault, so these macros are used only
+ * for pre-condition violations and internal logic errors.
+ */
+#if JSON_USE_EXCEPTION
+
+// @todo <= add detail about condition in exception
+#define JSON_ASSERT(condition) \
+ { \
+ if (!(condition)) \
+ { \
+ Json::throwLogicError("assert json failed"); \
+ } \
+ }
+
+#define JSON_FAIL_MESSAGE(message) \
+ { \
+ JSONCPP_OSTRINGSTREAM oss; \
+ oss << message; \
+ Json::throwLogicError(oss.str()); \
+ abort(); \
+ }
+
+#else // JSON_USE_EXCEPTION
+
+#define JSON_ASSERT(condition) assert(condition)
+
+// The call to assert() will show the failure message in debug builds. In
+// release builds we abort, for a core-dump or debugger.
+#define JSON_FAIL_MESSAGE(message) \
+ { \
+ JSONCPP_OSTRINGSTREAM oss; \
+ oss << message; \
+ assert(false && oss.str().c_str()); \
+ abort(); \
+ }
+
+#endif
+
+#define JSON_ASSERT_MESSAGE(condition, message) \
+ if (!(condition)) \
+ { \
+ JSON_FAIL_MESSAGE(message); \
+ }
+
+#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/assertions.h
+// //////////////////////////////////////////////////////////////////////
+
+#endif // ifndef JSON_AMALGATED_H_INCLUDED
diff --git a/runtime/3rdparty/jsoncpp/jsoncpp.cpp b/runtime/3rdparty/jsoncpp/jsoncpp.cpp
new file mode 100644
index 000000000..5b3cd691d
--- /dev/null
+++ b/runtime/3rdparty/jsoncpp/jsoncpp.cpp
@@ -0,0 +1,5651 @@
+/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json.h"
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+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.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+#include "json/json.h"
+
+#ifndef JSON_IS_AMALGAMATION
+#error "Compile with -I PATH_TO_JSON_DIRECTORY"
+#endif
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_tool.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+#ifndef NO_LOCALE_SUPPORT
+#include <clocale>
+#endif
+
+/* This header provides common string manipulation support, such as UTF-8,
+ * portable conversion from/to string...
+ *
+ * It is an internal header that must not be exposed.
+ */
+
+namespace Json
+{
+static char getDecimalPoint()
+{
+#ifdef NO_LOCALE_SUPPORT
+ return '\0';
+#else
+ struct lconv *lc = localeconv();
+ return lc ? *(lc->decimal_point) : '\0';
+#endif
+}
+
+/// Converts a unicode code-point to UTF-8.
+static inline JSONCPP_STRING codePointToUTF8(unsigned int cp)
+{
+ JSONCPP_STRING result;
+
+ // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+ if (cp <= 0x7f)
+ {
+ result.resize(1);
+ result[0] = static_cast<char>(cp);
+ }
+ else if (cp <= 0x7FF)
+ {
+ result.resize(2);
+ result[1] = static_cast<char>(0x80 | (0x3f & cp));
+ result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
+ }
+ else if (cp <= 0xFFFF)
+ {
+ result.resize(3);
+ result[2] = static_cast<char>(0x80 | (0x3f & cp));
+ result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+ result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
+ }
+ else if (cp <= 0x10FFFF)
+ {
+ result.resize(4);
+ result[3] = static_cast<char>(0x80 | (0x3f & cp));
+ result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+ result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
+ result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
+ }
+
+ return result;
+}
+
+/// Returns true if ch is a control character (in range [1,31]).
+static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
+
+enum
+{
+ /// Constant that specify the size of the buffer that must be passed to
+ /// uintToString.
+ uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
+};
+
+// Defines a char buffer for use with uintToString().
+typedef char UIntToStringBuffer[uintToStringBufferSize];
+
+/** Converts an unsigned integer to string.
+ * @param value Unsigned interger to convert to string
+ * @param current Input/Output string buffer.
+ * Must have at least uintToStringBufferSize chars free.
+ */
+static inline void uintToString(LargestUInt value, char *&current)
+{
+ *--current = 0;
+ do
+ {
+ *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
+ value /= 10;
+ } while (value != 0);
+}
+
+/** Change ',' to '.' everywhere in buffer.
+ *
+ * We had a sophisticated way, but it did not work in WinCE.
+ * @see https://github.com/open-source-parsers/jsoncpp/pull/9
+ */
+static inline void fixNumericLocale(char *begin, char *end)
+{
+ while (begin < end)
+ {
+ if (*begin == ',')
+ {
+ *begin = '.';
+ }
+ ++begin;
+ }
+}
+
+static inline void fixNumericLocaleInput(char *begin, char *end)
+{
+ char decimalPoint = getDecimalPoint();
+ if (decimalPoint != '\0' && decimalPoint != '.')
+ {
+ while (begin < end)
+ {
+ if (*begin == '.')
+ {
+ *begin = decimalPoint;
+ }
+ ++begin;
+ }
+ }
+}
+
+} // namespace Json {
+
+#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_tool.h
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_reader.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/reader.h>
+#include <json/value.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <cstdio>
+#include <cassert>
+#include <cstring>
+#include <istream>
+#include <sstream>
+#include <memory>
+#include <set>
+#include <limits>
+
+#if defined(_MSC_VER)
+#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
+#define snprintf sprintf_s
+#elif _MSC_VER >= 1900 // VC++ 14.0 and above
+#define snprintf std::snprintf
+#else
+#define snprintf _snprintf
+#endif
+#elif defined(__ANDROID__) || defined(__QNXNTO__)
+#define snprintf snprintf
+#elif __cplusplus >= 201103L
+#if !defined(__MINGW32__) && !defined(__CYGWIN__)
+#define snprintf std::snprintf
+#endif
+#endif
+
+#if defined(__QNXNTO__)
+#define sscanf std::sscanf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+static int const stackLimit_g = 1000;
+static int stackDepth_g = 0; // see readValue()
+
+namespace Json
+{
+
+#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
+typedef std::unique_ptr<CharReader> CharReaderPtr;
+#else
+typedef std::auto_ptr<CharReader> CharReaderPtr;
+#endif
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features()
+ : allowComments_(true), strictRoot_(false), allowDroppedNullPlaceholders_(false),
+ allowNumericKeys_(false)
+{
+}
+
+Features Features::all() { return Features(); }
+
+Features Features::strictMode()
+{
+ Features features;
+ features.allowComments_ = false;
+ features.strictRoot_ = true;
+ features.allowDroppedNullPlaceholders_ = false;
+ features.allowNumericKeys_ = false;
+ return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+static bool containsNewLine(Reader::Location begin, Reader::Location end)
+{
+ for (; begin < end; ++begin)
+ if (*begin == '\n' || *begin == '\r')
+ return true;
+ return false;
+}
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader()
+ : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), lastValue_(),
+ commentsBefore_(), features_(Features::all()), collectComments_()
+{
+}
+
+Reader::Reader(const Features &features)
+ : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), lastValue_(),
+ commentsBefore_(), features_(features), collectComments_()
+{
+}
+
+bool Reader::parse(const std::string &document, Value &root, bool collectComments)
+{
+ JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity());
+ std::swap(documentCopy, document_);
+ const char *begin = document_.c_str();
+ const char *end = begin + document_.length();
+ return parse(begin, end, root, collectComments);
+}
+
+bool Reader::parse(std::istream &sin, Value &root, bool collectComments)
+{
+ // std::istream_iterator<char> begin(sin);
+ // std::istream_iterator<char> end;
+ // Those would allow streamed input from a file, if parse() were a
+ // template function.
+
+ // Since JSONCPP_STRING is reference-counted, this at least does not
+ // create an extra copy.
+ JSONCPP_STRING doc;
+ std::getline(sin, doc, (char)EOF);
+ return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
+}
+
+bool Reader::parse(const char *beginDoc, const char *endDoc, Value &root, bool collectComments)
+{
+ if (!features_.allowComments_)
+ {
+ collectComments = false;
+ }
+
+ begin_ = beginDoc;
+ end_ = endDoc;
+ collectComments_ = collectComments;
+ current_ = begin_;
+ lastValueEnd_ = 0;
+ lastValue_ = 0;
+ commentsBefore_ = "";
+ errors_.clear();
+ while (!nodes_.empty())
+ nodes_.pop();
+ nodes_.push(&root);
+
+ stackDepth_g = 0; // Yes, this is bad coding, but options are limited.
+ bool successful = readValue();
+ Token token;
+ skipCommentTokens(token);
+ if (collectComments_ && !commentsBefore_.empty())
+ root.setComment(commentsBefore_, commentAfter);
+ if (features_.strictRoot_)
+ {
+ if (!root.isArray() && !root.isObject())
+ {
+ // Set error location to start of doc, ideally should be first token found
+ // in doc
+ token.type_ = tokenError;
+ token.start_ = beginDoc;
+ token.end_ = endDoc;
+ addError("A valid JSON document must be either an array or an object value.", token);
+ return false;
+ }
+ }
+ return successful;
+}
+
+bool Reader::readValue()
+{
+ // This is a non-reentrant way to support a stackLimit. Terrible!
+ // But this deprecated class has a security problem: Bad input can
+ // cause a seg-fault. This seems like a fair, binary-compatible way
+ // to prevent the problem.
+ if (stackDepth_g >= stackLimit_g)
+ throwRuntimeError("Exceeded stackLimit in readValue().");
+ ++stackDepth_g;
+
+ Token token;
+ skipCommentTokens(token);
+ bool successful = true;
+
+ if (collectComments_ && !commentsBefore_.empty())
+ {
+ currentValue().setComment(commentsBefore_, commentBefore);
+ commentsBefore_ = "";
+ }
+
+ switch (token.type_)
+ {
+ case tokenObjectBegin:
+ successful = readObject(token);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ case tokenArrayBegin:
+ successful = readArray(token);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ case tokenNumber:
+ successful = decodeNumber(token);
+ break;
+ case tokenString:
+ successful = decodeString(token);
+ break;
+ case tokenTrue:
+ {
+ Value v(true);
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenFalse:
+ {
+ Value v(false);
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenNull:
+ {
+ Value v;
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenArraySeparator:
+ case tokenObjectEnd:
+ case tokenArrayEnd:
+ if (features_.allowDroppedNullPlaceholders_)
+ {
+ // "Un-read" the current token and mark the current value as a null
+ // token.
+ current_--;
+ Value v;
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(current_ - begin_ - 1);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ } // Else, fall through...
+ default:
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return addError("Syntax error: value, object or array expected.", token);
+ }
+
+ if (collectComments_)
+ {
+ lastValueEnd_ = current_;
+ lastValue_ = &currentValue();
+ }
+
+ --stackDepth_g;
+ return successful;
+}
+
+void Reader::skipCommentTokens(Token &token)
+{
+ if (features_.allowComments_)
+ {
+ do
+ {
+ readToken(token);
+ } while (token.type_ == tokenComment);
+ }
+ else
+ {
+ readToken(token);
+ }
+}
+
+bool Reader::readToken(Token &token)
+{
+ skipSpaces();
+ token.start_ = current_;
+ Char c = getNextChar();
+ bool ok = true;
+ switch (c)
+ {
+ case '{':
+ token.type_ = tokenObjectBegin;
+ break;
+ case '}':
+ token.type_ = tokenObjectEnd;
+ break;
+ case '[':
+ token.type_ = tokenArrayBegin;
+ break;
+ case ']':
+ token.type_ = tokenArrayEnd;
+ break;
+ case '"':
+ token.type_ = tokenString;
+ ok = readString();
+ break;
+ case '/':
+ token.type_ = tokenComment;
+ ok = readComment();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ token.type_ = tokenNumber;
+ readNumber();
+ break;
+ case 't':
+ token.type_ = tokenTrue;
+ ok = match("rue", 3);
+ break;
+ case 'f':
+ token.type_ = tokenFalse;
+ ok = match("alse", 4);
+ break;
+ case 'n':
+ token.type_ = tokenNull;
+ ok = match("ull", 3);
+ break;
+ case ',':
+ token.type_ = tokenArraySeparator;
+ break;
+ case ':':
+ token.type_ = tokenMemberSeparator;
+ break;
+ case 0:
+ token.type_ = tokenEndOfStream;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ if (!ok)
+ token.type_ = tokenError;
+ token.end_ = current_;
+ return true;
+}
+
+void Reader::skipSpaces()
+{
+ while (current_ != end_)
+ {
+ Char c = *current_;
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+ ++current_;
+ else
+ break;
+ }
+}
+
+bool Reader::match(Location pattern, int patternLength)
+{
+ if (end_ - current_ < patternLength)
+ return false;
+ int index = patternLength;
+ while (index--)
+ if (current_[index] != pattern[index])
+ return false;
+ current_ += patternLength;
+ return true;
+}
+
+bool Reader::readComment()
+{
+ Location commentBegin = current_ - 1;
+ Char c = getNextChar();
+ bool successful = false;
+ if (c == '*')
+ successful = readCStyleComment();
+ else if (c == '/')
+ successful = readCppStyleComment();
+ if (!successful)
+ return false;
+
+ if (collectComments_)
+ {
+ CommentPlacement placement = commentBefore;
+ if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin))
+ {
+ if (c != '*' || !containsNewLine(commentBegin, current_))
+ placement = commentAfterOnSameLine;
+ }
+
+ addComment(commentBegin, current_, placement);
+ }
+ return true;
+}
+
+static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end)
+{
+ JSONCPP_STRING normalized;
+ normalized.reserve(static_cast<size_t>(end - begin));
+ Reader::Location current = begin;
+ while (current != end)
+ {
+ char c = *current++;
+ if (c == '\r')
+ {
+ if (current != end && *current == '\n')
+ // convert dos EOL
+ ++current;
+ // convert Mac EOL
+ normalized += '\n';
+ }
+ else
+ {
+ normalized += c;
+ }
+ }
+ return normalized;
+}
+
+void Reader::addComment(Location begin, Location end, CommentPlacement placement)
+{
+ assert(collectComments_);
+ const JSONCPP_STRING &normalized = normalizeEOL(begin, end);
+ if (placement == commentAfterOnSameLine)
+ {
+ assert(lastValue_ != 0);
+ lastValue_->setComment(normalized, placement);
+ }
+ else
+ {
+ commentsBefore_ += normalized;
+ }
+}
+
+bool Reader::readCStyleComment()
+{
+ while ((current_ + 1) < end_)
+ {
+ Char c = getNextChar();
+ if (c == '*' && *current_ == '/')
+ break;
+ }
+ return getNextChar() == '/';
+}
+
+bool Reader::readCppStyleComment()
+{
+ while (current_ != end_)
+ {
+ Char c = getNextChar();
+ if (c == '\n')
+ break;
+ if (c == '\r')
+ {
+ // Consume DOS EOL. It will be normalized in addComment.
+ if (current_ != end_ && *current_ == '\n')
+ getNextChar();
+ // Break on Moc OS 9 EOL.
+ break;
+ }
+ }
+ return true;
+}
+
+void Reader::readNumber()
+{
+ const char *p = current_;
+ char c = '0'; // stopgap for already consumed character
+ // integral part
+ while (c >= '0' && c <= '9')
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ // fractional part
+ if (c == '.')
+ {
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ while (c >= '0' && c <= '9')
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ }
+ // exponential part
+ if (c == 'e' || c == 'E')
+ {
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ if (c == '+' || c == '-')
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ while (c >= '0' && c <= '9')
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ }
+}
+
+bool Reader::readString()
+{
+ Char c = '\0';
+ while (current_ != end_)
+ {
+ c = getNextChar();
+ if (c == '\\')
+ getNextChar();
+ else if (c == '"')
+ break;
+ }
+ return c == '"';
+}
+
+bool Reader::readObject(Token &tokenStart)
+{
+ Token tokenName;
+ JSONCPP_STRING name;
+ Value init(objectValue);
+ currentValue().swapPayload(init);
+ currentValue().setOffsetStart(tokenStart.start_ - begin_);
+ while (readToken(tokenName))
+ {
+ bool initialTokenOk = true;
+ while (tokenName.type_ == tokenComment && initialTokenOk)
+ initialTokenOk = readToken(tokenName);
+ if (!initialTokenOk)
+ break;
+ if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+ return true;
+ name = "";
+ if (tokenName.type_ == tokenString)
+ {
+ if (!decodeString(tokenName, name))
+ return recoverFromError(tokenObjectEnd);
+ }
+ else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_)
+ {
+ Value numberName;
+ if (!decodeNumber(tokenName, numberName))
+ return recoverFromError(tokenObjectEnd);
+ name = JSONCPP_STRING(numberName.asCString());
+ }
+ else
+ {
+ break;
+ }
+
+ Token colon;
+ if (!readToken(colon) || colon.type_ != tokenMemberSeparator)
+ {
+ return addErrorAndRecover("Missing ':' after object member name", colon, tokenObjectEnd);
+ }
+ Value &value = currentValue()[name];
+ nodes_.push(&value);
+ bool ok = readValue();
+ nodes_.pop();
+ if (!ok) // error already set
+ return recoverFromError(tokenObjectEnd);
+
+ Token comma;
+ if (!readToken(comma) || (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+ comma.type_ != tokenComment))
+ {
+ return addErrorAndRecover("Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+ }
+ bool finalizeTokenOk = true;
+ while (comma.type_ == tokenComment && finalizeTokenOk)
+ finalizeTokenOk = readToken(comma);
+ if (comma.type_ == tokenObjectEnd)
+ return true;
+ }
+ return addErrorAndRecover("Missing '}' or object member name", tokenName, tokenObjectEnd);
+}
+
+bool Reader::readArray(Token &tokenStart)
+{
+ Value init(arrayValue);
+ currentValue().swapPayload(init);
+ currentValue().setOffsetStart(tokenStart.start_ - begin_);
+ skipSpaces();
+ if (current_ != end_ && *current_ == ']') // empty array
+ {
+ Token endArray;
+ readToken(endArray);
+ return true;
+ }
+ int index = 0;
+ for (;;)
+ {
+ Value &value = currentValue()[index++];
+ nodes_.push(&value);
+ bool ok = readValue();
+ nodes_.pop();
+ if (!ok) // error already set
+ return recoverFromError(tokenArrayEnd);
+
+ Token token;
+ // Accept Comment after last item in the array.
+ ok = readToken(token);
+ while (token.type_ == tokenComment && ok)
+ {
+ ok = readToken(token);
+ }
+ bool badTokenType = (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+ if (!ok || badTokenType)
+ {
+ return addErrorAndRecover("Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+ }
+ if (token.type_ == tokenArrayEnd)
+ break;
+ }
+ return true;
+}
+
+bool Reader::decodeNumber(Token &token)
+{
+ Value decoded;
+ if (!decodeNumber(token, decoded))
+ return false;
+ currentValue().swapPayload(decoded);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeNumber(Token &token, Value &decoded)
+{
+ // Attempts to parse the number as an integer. If the number is
+ // larger than the maximum supported value of an integer then
+ // we decode the number as a double.
+ Location current = token.start_;
+ bool isNegative = *current == '-';
+ if (isNegative)
+ ++current;
+ // TODO: Help the compiler do the div and mod at compile time or get rid of them.
+ Value::LargestUInt maxIntegerValue =
+ isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 : Value::maxLargestUInt;
+ Value::LargestUInt threshold = maxIntegerValue / 10;
+ Value::LargestUInt value = 0;
+ while (current < token.end_)
+ {
+ Char c = *current++;
+ if (c < '0' || c > '9')
+ return decodeDouble(token, decoded);
+ Value::UInt digit(static_cast<Value::UInt>(c - '0'));
+ if (value >= threshold)
+ {
+ // We've hit or exceeded the max value divided by 10 (rounded down). If
+ // a) we've only just touched the limit, b) this is the last digit, and
+ // c) it's small enough to fit in that rounding delta, we're okay.
+ // Otherwise treat this number as a double to avoid overflow.
+ if (value > threshold || current != token.end_ || digit > maxIntegerValue % 10)
+ {
+ return decodeDouble(token, decoded);
+ }
+ }
+ value = value * 10 + digit;
+ }
+ if (isNegative && value == maxIntegerValue)
+ decoded = Value::minLargestInt;
+ else if (isNegative)
+ decoded = -Value::LargestInt(value);
+ else if (value <= Value::LargestUInt(Value::maxInt))
+ decoded = Value::LargestInt(value);
+ else
+ decoded = value;
+ return true;
+}
+
+bool Reader::decodeDouble(Token &token)
+{
+ Value decoded;
+ if (!decodeDouble(token, decoded))
+ return false;
+ currentValue().swapPayload(decoded);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeDouble(Token &token, Value &decoded)
+{
+ double value = 0;
+ JSONCPP_STRING buffer(token.start_, token.end_);
+ JSONCPP_ISTRINGSTREAM is(buffer);
+ if (!(is >> value))
+ return addError("'" + JSONCPP_STRING(token.start_, token.end_) + "' is not a number.", token);
+ decoded = value;
+ return true;
+}
+
+bool Reader::decodeString(Token &token)
+{
+ JSONCPP_STRING decoded_string;
+ if (!decodeString(token, decoded_string))
+ return false;
+ Value decoded(decoded_string);
+ currentValue().swapPayload(decoded);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeString(Token &token, JSONCPP_STRING &decoded)
+{
+ decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
+ Location current = token.start_ + 1; // skip '"'
+ Location end = token.end_ - 1; // do not include '"'
+ while (current != end)
+ {
+ Char c = *current++;
+ if (c == '"')
+ break;
+ else if (c == '\\')
+ {
+ if (current == end)
+ return addError("Empty escape sequence in string", token, current);
+ Char escape = *current++;
+ switch (escape)
+ {
+ case '"':
+ decoded += '"';
+ break;
+ case '/':
+ decoded += '/';
+ break;
+ case '\\':
+ decoded += '\\';
+ break;
+ case 'b':
+ decoded += '\b';
+ break;
+ case 'f':
+ decoded += '\f';
+ break;
+ case 'n':
+ decoded += '\n';
+ break;
+ case 'r':
+ decoded += '\r';
+ break;
+ case 't':
+ decoded += '\t';
+ break;
+ case 'u':
+ {
+ unsigned int unicode;
+ if (!decodeUnicodeCodePoint(token, current, end, unicode))
+ return false;
+ decoded += codePointToUTF8(unicode);
+ }
+ break;
+ default:
+ return addError("Bad escape sequence in string", token, current);
+ }
+ }
+ else
+ {
+ decoded += c;
+ }
+ }
+ return true;
+}
+
+bool Reader::decodeUnicodeCodePoint(Token &token, Location &current, Location end,
+ unsigned int &unicode)
+{
+
+ if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+ return false;
+ if (unicode >= 0xD800 && unicode <= 0xDBFF)
+ {
+ // surrogate pairs
+ if (end - current < 6)
+ return addError("additional six characters expected to parse unicode surrogate pair.", token,
+ current);
+ unsigned int surrogatePair;
+ if (*(current++) == '\\' && *(current++) == 'u')
+ {
+ if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair))
+ {
+ unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+ }
+ else
+ return false;
+ }
+ else
+ return addError("expecting another \\u token to begin the second half of "
+ "a unicode surrogate pair",
+ token, current);
+ }
+ return true;
+}
+
+bool Reader::decodeUnicodeEscapeSequence(Token &token, Location &current, Location end,
+ unsigned int &ret_unicode)
+{
+ if (end - current < 4)
+ return addError("Bad unicode escape sequence in string: four digits expected.", token, current);
+ int unicode = 0;
+ for (int index = 0; index < 4; ++index)
+ {
+ Char c = *current++;
+ unicode *= 16;
+ if (c >= '0' && c <= '9')
+ unicode += c - '0';
+ else if (c >= 'a' && c <= 'f')
+ unicode += c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ unicode += c - 'A' + 10;
+ else
+ return addError("Bad unicode escape sequence in string: hexadecimal digit expected.", token,
+ current);
+ }
+ ret_unicode = static_cast<unsigned int>(unicode);
+ return true;
+}
+
+bool Reader::addError(const JSONCPP_STRING &message, Token &token, Location extra)
+{
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = extra;
+ errors_.push_back(info);
+ return false;
+}
+
+bool Reader::recoverFromError(TokenType skipUntilToken)
+{
+ size_t const errorCount = errors_.size();
+ Token skip;
+ for (;;)
+ {
+ if (!readToken(skip))
+ errors_.resize(errorCount); // discard errors caused by recovery
+ if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+ break;
+ }
+ errors_.resize(errorCount);
+ return false;
+}
+
+bool Reader::addErrorAndRecover(const JSONCPP_STRING &message, Token &token,
+ TokenType skipUntilToken)
+{
+ addError(message, token);
+ return recoverFromError(skipUntilToken);
+}
+
+Value &Reader::currentValue() { return *(nodes_.top()); }
+
+Reader::Char Reader::getNextChar()
+{
+ if (current_ == end_)
+ return 0;
+ return *current_++;
+}
+
+void Reader::getLocationLineAndColumn(Location location, int &line, int &column) const
+{
+ Location current = begin_;
+ Location lastLineStart = current;
+ line = 0;
+ while (current < location && current != end_)
+ {
+ Char c = *current++;
+ if (c == '\r')
+ {
+ if (*current == '\n')
+ ++current;
+ lastLineStart = current;
+ ++line;
+ }
+ else if (c == '\n')
+ {
+ lastLineStart = current;
+ ++line;
+ }
+ }
+ // column & line start at 1
+ column = int(location - lastLineStart) + 1;
+ ++line;
+}
+
+JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const
+{
+ int line, column;
+ getLocationLineAndColumn(location, line, column);
+ char buffer[18 + 16 + 16 + 1];
+ snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+ return buffer;
+}
+
+// Deprecated. Preserved for backward compatibility
+JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFormattedErrorMessages(); }
+
+JSONCPP_STRING Reader::getFormattedErrorMessages() const
+{
+ JSONCPP_STRING formattedMessage;
+ for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError)
+ {
+ const ErrorInfo &error = *itError;
+ formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+ formattedMessage += " " + error.message_ + "\n";
+ if (error.extra_)
+ formattedMessage += "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+ }
+ return formattedMessage;
+}
+
+std::vector<Reader::StructuredError> Reader::getStructuredErrors() const
+{
+ std::vector<Reader::StructuredError> allErrors;
+ for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError)
+ {
+ const ErrorInfo &error = *itError;
+ Reader::StructuredError structured;
+ structured.offset_start = error.token_.start_ - begin_;
+ structured.offset_limit = error.token_.end_ - begin_;
+ structured.message = error.message_;
+ allErrors.push_back(structured);
+ }
+ return allErrors;
+}
+
+bool Reader::pushError(const Value &value, const JSONCPP_STRING &message)
+{
+ ptrdiff_t const length = end_ - begin_;
+ if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
+ return false;
+ Token token;
+ token.type_ = tokenError;
+ token.start_ = begin_ + value.getOffsetStart();
+ token.end_ = end_ + value.getOffsetLimit();
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = 0;
+ errors_.push_back(info);
+ return true;
+}
+
+bool Reader::pushError(const Value &value, const JSONCPP_STRING &message, const Value &extra)
+{
+ ptrdiff_t const length = end_ - begin_;
+ if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
+ extra.getOffsetLimit() > length)
+ return false;
+ Token token;
+ token.type_ = tokenError;
+ token.start_ = begin_ + value.getOffsetStart();
+ token.end_ = begin_ + value.getOffsetLimit();
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = begin_ + extra.getOffsetStart();
+ errors_.push_back(info);
+ return true;
+}
+
+bool Reader::good() const { return !errors_.size(); }
+
+// exact copy of Features
+class OurFeatures
+{
+public:
+ static OurFeatures all();
+ bool allowComments_;
+ bool strictRoot_;
+ bool allowDroppedNullPlaceholders_;
+ bool allowNumericKeys_;
+ bool allowSingleQuotes_;
+ bool failIfExtra_;
+ bool rejectDupKeys_;
+ bool allowSpecialFloats_;
+ int stackLimit_;
+}; // OurFeatures
+
+// exact copy of Implementation of class Features
+// ////////////////////////////////
+
+OurFeatures OurFeatures::all() { return OurFeatures(); }
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+// exact copy of Reader, renamed to OurReader
+class OurReader
+{
+public:
+ typedef char Char;
+ typedef const Char *Location;
+ struct StructuredError
+ {
+ ptrdiff_t offset_start;
+ ptrdiff_t offset_limit;
+ JSONCPP_STRING message;
+ };
+
+ OurReader(OurFeatures const &features);
+ bool parse(const char *beginDoc, const char *endDoc, Value &root, bool collectComments = true);
+ JSONCPP_STRING getFormattedErrorMessages() const;
+ std::vector<StructuredError> getStructuredErrors() const;
+ bool pushError(const Value &value, const JSONCPP_STRING &message);
+ bool pushError(const Value &value, const JSONCPP_STRING &message, const Value &extra);
+ bool good() const;
+
+private:
+ OurReader(OurReader const &); // no impl
+ void operator=(OurReader const &); // no impl
+
+ enum TokenType
+ {
+ tokenEndOfStream = 0,
+ tokenObjectBegin,
+ tokenObjectEnd,
+ tokenArrayBegin,
+ tokenArrayEnd,
+ tokenString,
+ tokenNumber,
+ tokenTrue,
+ tokenFalse,
+ tokenNull,
+ tokenNaN,
+ tokenPosInf,
+ tokenNegInf,
+ tokenArraySeparator,
+ tokenMemberSeparator,
+ tokenComment,
+ tokenError
+ };
+
+ class Token
+ {
+ public:
+ TokenType type_;
+ Location start_;
+ Location end_;
+ };
+
+ class ErrorInfo
+ {
+ public:
+ Token token_;
+ JSONCPP_STRING message_;
+ Location extra_;
+ };
+
+ typedef std::deque<ErrorInfo> Errors;
+
+ bool readToken(Token &token);
+ void skipSpaces();
+ bool match(Location pattern, int patternLength);
+ bool readComment();
+ bool readCStyleComment();
+ bool readCppStyleComment();
+ bool readString();
+ bool readStringSingleQuote();
+ bool readNumber(bool checkInf);
+ bool readValue();
+ bool readObject(Token &token);
+ bool readArray(Token &token);
+ bool decodeNumber(Token &token);
+ bool decodeNumber(Token &token, Value &decoded);
+ bool decodeString(Token &token);
+ bool decodeString(Token &token, JSONCPP_STRING &decoded);
+ bool decodeDouble(Token &token);
+ bool decodeDouble(Token &token, Value &decoded);
+ bool decodeUnicodeCodePoint(Token &token, Location &current, Location end, unsigned int &unicode);
+ bool decodeUnicodeEscapeSequence(Token &token, Location &current, Location end,
+ unsigned int &unicode);
+ bool addError(const JSONCPP_STRING &message, Token &token, Location extra = 0);
+ bool recoverFromError(TokenType skipUntilToken);
+ bool addErrorAndRecover(const JSONCPP_STRING &message, Token &token, TokenType skipUntilToken);
+ void skipUntilSpace();
+ Value &currentValue();
+ Char getNextChar();
+ void getLocationLineAndColumn(Location location, int &line, int &column) const;
+ JSONCPP_STRING getLocationLineAndColumn(Location location) const;
+ void addComment(Location begin, Location end, CommentPlacement placement);
+ void skipCommentTokens(Token &token);
+
+ typedef std::stack<Value *> Nodes;
+ Nodes nodes_;
+ Errors errors_;
+ JSONCPP_STRING document_;
+ Location begin_;
+ Location end_;
+ Location current_;
+ Location lastValueEnd_;
+ Value *lastValue_;
+ JSONCPP_STRING commentsBefore_;
+ int stackDepth_;
+
+ OurFeatures const features_;
+ bool collectComments_;
+}; // OurReader
+
+// complete copy of Read impl, for OurReader
+
+OurReader::OurReader(OurFeatures const &features)
+ : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), lastValue_(),
+ commentsBefore_(), stackDepth_(0), features_(features), collectComments_()
+{
+}
+
+bool OurReader::parse(const char *beginDoc, const char *endDoc, Value &root, bool collectComments)
+{
+ if (!features_.allowComments_)
+ {
+ collectComments = false;
+ }
+
+ begin_ = beginDoc;
+ end_ = endDoc;
+ collectComments_ = collectComments;
+ current_ = begin_;
+ lastValueEnd_ = 0;
+ lastValue_ = 0;
+ commentsBefore_ = "";
+ errors_.clear();
+ while (!nodes_.empty())
+ nodes_.pop();
+ nodes_.push(&root);
+
+ stackDepth_ = 0;
+ bool successful = readValue();
+ Token token;
+ skipCommentTokens(token);
+ if (features_.failIfExtra_)
+ {
+ if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream)
+ {
+ addError("Extra non-whitespace after JSON value.", token);
+ return false;
+ }
+ }
+ if (collectComments_ && !commentsBefore_.empty())
+ root.setComment(commentsBefore_, commentAfter);
+ if (features_.strictRoot_)
+ {
+ if (!root.isArray() && !root.isObject())
+ {
+ // Set error location to start of doc, ideally should be first token found
+ // in doc
+ token.type_ = tokenError;
+ token.start_ = beginDoc;
+ token.end_ = endDoc;
+ addError("A valid JSON document must be either an array or an object value.", token);
+ return false;
+ }
+ }
+ return successful;
+}
+
+bool OurReader::readValue()
+{
+ if (stackDepth_ >= features_.stackLimit_)
+ throwRuntimeError("Exceeded stackLimit in readValue().");
+ ++stackDepth_;
+ Token token;
+ skipCommentTokens(token);
+ bool successful = true;
+
+ if (collectComments_ && !commentsBefore_.empty())
+ {
+ currentValue().setComment(commentsBefore_, commentBefore);
+ commentsBefore_ = "";
+ }
+
+ switch (token.type_)
+ {
+ case tokenObjectBegin:
+ successful = readObject(token);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ case tokenArrayBegin:
+ successful = readArray(token);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ case tokenNumber:
+ successful = decodeNumber(token);
+ break;
+ case tokenString:
+ successful = decodeString(token);
+ break;
+ case tokenTrue:
+ {
+ Value v(true);
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenFalse:
+ {
+ Value v(false);
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenNull:
+ {
+ Value v;
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenNaN:
+ {
+ Value v(std::numeric_limits<double>::quiet_NaN());
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenPosInf:
+ {
+ Value v(std::numeric_limits<double>::infinity());
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenNegInf:
+ {
+ Value v(-std::numeric_limits<double>::infinity());
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ }
+ break;
+ case tokenArraySeparator:
+ case tokenObjectEnd:
+ case tokenArrayEnd:
+ if (features_.allowDroppedNullPlaceholders_)
+ {
+ // "Un-read" the current token and mark the current value as a null
+ // token.
+ current_--;
+ Value v;
+ currentValue().swapPayload(v);
+ currentValue().setOffsetStart(current_ - begin_ - 1);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ } // else, fall through ...
+ default:
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return addError("Syntax error: value, object or array expected.", token);
+ }
+
+ if (collectComments_)
+ {
+ lastValueEnd_ = current_;
+ lastValue_ = &currentValue();
+ }
+
+ --stackDepth_;
+ return successful;
+}
+
+void OurReader::skipCommentTokens(Token &token)
+{
+ if (features_.allowComments_)
+ {
+ do
+ {
+ readToken(token);
+ } while (token.type_ == tokenComment);
+ }
+ else
+ {
+ readToken(token);
+ }
+}
+
+bool OurReader::readToken(Token &token)
+{
+ skipSpaces();
+ token.start_ = current_;
+ Char c = getNextChar();
+ bool ok = true;
+ switch (c)
+ {
+ case '{':
+ token.type_ = tokenObjectBegin;
+ break;
+ case '}':
+ token.type_ = tokenObjectEnd;
+ break;
+ case '[':
+ token.type_ = tokenArrayBegin;
+ break;
+ case ']':
+ token.type_ = tokenArrayEnd;
+ break;
+ case '"':
+ token.type_ = tokenString;
+ ok = readString();
+ break;
+ case '\'':
+ if (features_.allowSingleQuotes_)
+ {
+ token.type_ = tokenString;
+ ok = readStringSingleQuote();
+ break;
+ } // else continue
+ case '/':
+ token.type_ = tokenComment;
+ ok = readComment();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ token.type_ = tokenNumber;
+ readNumber(false);
+ break;
+ case '-':
+ if (readNumber(true))
+ {
+ token.type_ = tokenNumber;
+ }
+ else
+ {
+ token.type_ = tokenNegInf;
+ ok = features_.allowSpecialFloats_ && match("nfinity", 7);
+ }
+ break;
+ case 't':
+ token.type_ = tokenTrue;
+ ok = match("rue", 3);
+ break;
+ case 'f':
+ token.type_ = tokenFalse;
+ ok = match("alse", 4);
+ break;
+ case 'n':
+ token.type_ = tokenNull;
+ ok = match("ull", 3);
+ break;
+ case 'N':
+ if (features_.allowSpecialFloats_)
+ {
+ token.type_ = tokenNaN;
+ ok = match("aN", 2);
+ }
+ else
+ {
+ ok = false;
+ }
+ break;
+ case 'I':
+ if (features_.allowSpecialFloats_)
+ {
+ token.type_ = tokenPosInf;
+ ok = match("nfinity", 7);
+ }
+ else
+ {
+ ok = false;
+ }
+ break;
+ case ',':
+ token.type_ = tokenArraySeparator;
+ break;
+ case ':':
+ token.type_ = tokenMemberSeparator;
+ break;
+ case 0:
+ token.type_ = tokenEndOfStream;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ if (!ok)
+ token.type_ = tokenError;
+ token.end_ = current_;
+ return true;
+}
+
+void OurReader::skipSpaces()
+{
+ while (current_ != end_)
+ {
+ Char c = *current_;
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+ ++current_;
+ else
+ break;
+ }
+}
+
+bool OurReader::match(Location pattern, int patternLength)
+{
+ if (end_ - current_ < patternLength)
+ return false;
+ int index = patternLength;
+ while (index--)
+ if (current_[index] != pattern[index])
+ return false;
+ current_ += patternLength;
+ return true;
+}
+
+bool OurReader::readComment()
+{
+ Location commentBegin = current_ - 1;
+ Char c = getNextChar();
+ bool successful = false;
+ if (c == '*')
+ successful = readCStyleComment();
+ else if (c == '/')
+ successful = readCppStyleComment();
+ if (!successful)
+ return false;
+
+ if (collectComments_)
+ {
+ CommentPlacement placement = commentBefore;
+ if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin))
+ {
+ if (c != '*' || !containsNewLine(commentBegin, current_))
+ placement = commentAfterOnSameLine;
+ }
+
+ addComment(commentBegin, current_, placement);
+ }
+ return true;
+}
+
+void OurReader::addComment(Location begin, Location end, CommentPlacement placement)
+{
+ assert(collectComments_);
+ const JSONCPP_STRING &normalized = normalizeEOL(begin, end);
+ if (placement == commentAfterOnSameLine)
+ {
+ assert(lastValue_ != 0);
+ lastValue_->setComment(normalized, placement);
+ }
+ else
+ {
+ commentsBefore_ += normalized;
+ }
+}
+
+bool OurReader::readCStyleComment()
+{
+ while ((current_ + 1) < end_)
+ {
+ Char c = getNextChar();
+ if (c == '*' && *current_ == '/')
+ break;
+ }
+ return getNextChar() == '/';
+}
+
+bool OurReader::readCppStyleComment()
+{
+ while (current_ != end_)
+ {
+ Char c = getNextChar();
+ if (c == '\n')
+ break;
+ if (c == '\r')
+ {
+ // Consume DOS EOL. It will be normalized in addComment.
+ if (current_ != end_ && *current_ == '\n')
+ getNextChar();
+ // Break on Moc OS 9 EOL.
+ break;
+ }
+ }
+ return true;
+}
+
+bool OurReader::readNumber(bool checkInf)
+{
+ const char *p = current_;
+ if (checkInf && p != end_ && *p == 'I')
+ {
+ current_ = ++p;
+ return false;
+ }
+ char c = '0'; // stopgap for already consumed character
+ // integral part
+ while (c >= '0' && c <= '9')
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ // fractional part
+ if (c == '.')
+ {
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ while (c >= '0' && c <= '9')
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ }
+ // exponential part
+ if (c == 'e' || c == 'E')
+ {
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ if (c == '+' || c == '-')
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ while (c >= '0' && c <= '9')
+ c = (current_ = p) < end_ ? *p++ : '\0';
+ }
+ return true;
+}
+bool OurReader::readString()
+{
+ Char c = 0;
+ while (current_ != end_)
+ {
+ c = getNextChar();
+ if (c == '\\')
+ getNextChar();
+ else if (c == '"')
+ break;
+ }
+ return c == '"';
+}
+
+bool OurReader::readStringSingleQuote()
+{
+ Char c = 0;
+ while (current_ != end_)
+ {
+ c = getNextChar();
+ if (c == '\\')
+ getNextChar();
+ else if (c == '\'')
+ break;
+ }
+ return c == '\'';
+}
+
+bool OurReader::readObject(Token &tokenStart)
+{
+ Token tokenName;
+ JSONCPP_STRING name;
+ Value init(objectValue);
+ currentValue().swapPayload(init);
+ currentValue().setOffsetStart(tokenStart.start_ - begin_);
+ while (readToken(tokenName))
+ {
+ bool initialTokenOk = true;
+ while (tokenName.type_ == tokenComment && initialTokenOk)
+ initialTokenOk = readToken(tokenName);
+ if (!initialTokenOk)
+ break;
+ if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+ return true;
+ name = "";
+ if (tokenName.type_ == tokenString)
+ {
+ if (!decodeString(tokenName, name))
+ return recoverFromError(tokenObjectEnd);
+ }
+ else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_)
+ {
+ Value numberName;
+ if (!decodeNumber(tokenName, numberName))
+ return recoverFromError(tokenObjectEnd);
+ name = numberName.asString();
+ }
+ else
+ {
+ break;
+ }
+
+ Token colon;
+ if (!readToken(colon) || colon.type_ != tokenMemberSeparator)
+ {
+ return addErrorAndRecover("Missing ':' after object member name", colon, tokenObjectEnd);
+ }
+ if (name.length() >= (1U << 30))
+ throwRuntimeError("keylength >= 2^30");
+ if (features_.rejectDupKeys_ && currentValue().isMember(name))
+ {
+ JSONCPP_STRING msg = "Duplicate key: '" + name + "'";
+ return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
+ }
+ Value &value = currentValue()[name];
+ nodes_.push(&value);
+ bool ok = readValue();
+ nodes_.pop();
+ if (!ok) // error already set
+ return recoverFromError(tokenObjectEnd);
+
+ Token comma;
+ if (!readToken(comma) || (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+ comma.type_ != tokenComment))
+ {
+ return addErrorAndRecover("Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+ }
+ bool finalizeTokenOk = true;
+ while (comma.type_ == tokenComment && finalizeTokenOk)
+ finalizeTokenOk = readToken(comma);
+ if (comma.type_ == tokenObjectEnd)
+ return true;
+ }
+ return addErrorAndRecover("Missing '}' or object member name", tokenName, tokenObjectEnd);
+}
+
+bool OurReader::readArray(Token &tokenStart)
+{
+ Value init(arrayValue);
+ currentValue().swapPayload(init);
+ currentValue().setOffsetStart(tokenStart.start_ - begin_);
+ skipSpaces();
+ if (current_ != end_ && *current_ == ']') // empty array
+ {
+ Token endArray;
+ readToken(endArray);
+ return true;
+ }
+ int index = 0;
+ for (;;)
+ {
+ Value &value = currentValue()[index++];
+ nodes_.push(&value);
+ bool ok = readValue();
+ nodes_.pop();
+ if (!ok) // error already set
+ return recoverFromError(tokenArrayEnd);
+
+ Token token;
+ // Accept Comment after last item in the array.
+ ok = readToken(token);
+ while (token.type_ == tokenComment && ok)
+ {
+ ok = readToken(token);
+ }
+ bool badTokenType = (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+ if (!ok || badTokenType)
+ {
+ return addErrorAndRecover("Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+ }
+ if (token.type_ == tokenArrayEnd)
+ break;
+ }
+ return true;
+}
+
+bool OurReader::decodeNumber(Token &token)
+{
+ Value decoded;
+ if (!decodeNumber(token, decoded))
+ return false;
+ currentValue().swapPayload(decoded);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool OurReader::decodeNumber(Token &token, Value &decoded)
+{
+ // Attempts to parse the number as an integer. If the number is
+ // larger than the maximum supported value of an integer then
+ // we decode the number as a double.
+ Location current = token.start_;
+ bool isNegative = *current == '-';
+ if (isNegative)
+ ++current;
+ // TODO: Help the compiler do the div and mod at compile time or get rid of them.
+ Value::LargestUInt maxIntegerValue =
+ isNegative ? Value::LargestUInt(-Value::minLargestInt) : Value::maxLargestUInt;
+ Value::LargestUInt threshold = maxIntegerValue / 10;
+ Value::LargestUInt value = 0;
+ while (current < token.end_)
+ {
+ Char c = *current++;
+ if (c < '0' || c > '9')
+ return decodeDouble(token, decoded);
+ Value::UInt digit(static_cast<Value::UInt>(c - '0'));
+ if (value >= threshold)
+ {
+ // We've hit or exceeded the max value divided by 10 (rounded down). If
+ // a) we've only just touched the limit, b) this is the last digit, and
+ // c) it's small enough to fit in that rounding delta, we're okay.
+ // Otherwise treat this number as a double to avoid overflow.
+ if (value > threshold || current != token.end_ || digit > maxIntegerValue % 10)
+ {
+ return decodeDouble(token, decoded);
+ }
+ }
+ value = value * 10 + digit;
+ }
+ if (isNegative)
+ decoded = -Value::LargestInt(value);
+ else if (value <= Value::LargestUInt(Value::maxInt))
+ decoded = Value::LargestInt(value);
+ else
+ decoded = value;
+ return true;
+}
+
+bool OurReader::decodeDouble(Token &token)
+{
+ Value decoded;
+ if (!decodeDouble(token, decoded))
+ return false;
+ currentValue().swapPayload(decoded);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool OurReader::decodeDouble(Token &token, Value &decoded)
+{
+ double value = 0;
+ const int bufferSize = 32;
+ int count;
+ ptrdiff_t const length = token.end_ - token.start_;
+
+ // Sanity check to avoid buffer overflow exploits.
+ if (length < 0)
+ {
+ return addError("Unable to parse token length", token);
+ }
+ size_t const ulength = static_cast<size_t>(length);
+
+ // Avoid using a string constant for the format control string given to
+ // sscanf, as this can cause hard to debug crashes on OS X. See here for more
+ // info:
+ //
+ // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
+ char format[] = "%lf";
+
+ if (length <= bufferSize)
+ {
+ Char buffer[bufferSize + 1];
+ memcpy(buffer, token.start_, ulength);
+ buffer[length] = 0;
+ fixNumericLocaleInput(buffer, buffer + length);
+ count = sscanf(buffer, format, &value);
+ }
+ else
+ {
+ JSONCPP_STRING buffer(token.start_, token.end_);
+ count = sscanf(buffer.c_str(), format, &value);
+ }
+
+ if (count != 1)
+ return addError("'" + JSONCPP_STRING(token.start_, token.end_) + "' is not a number.", token);
+ decoded = value;
+ return true;
+}
+
+bool OurReader::decodeString(Token &token)
+{
+ JSONCPP_STRING decoded_string;
+ if (!decodeString(token, decoded_string))
+ return false;
+ Value decoded(decoded_string);
+ currentValue().swapPayload(decoded);
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool OurReader::decodeString(Token &token, JSONCPP_STRING &decoded)
+{
+ decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
+ Location current = token.start_ + 1; // skip '"'
+ Location end = token.end_ - 1; // do not include '"'
+ while (current != end)
+ {
+ Char c = *current++;
+ if (c == '"')
+ break;
+ else if (c == '\\')
+ {
+ if (current == end)
+ return addError("Empty escape sequence in string", token, current);
+ Char escape = *current++;
+ switch (escape)
+ {
+ case '"':
+ decoded += '"';
+ break;
+ case '/':
+ decoded += '/';
+ break;
+ case '\\':
+ decoded += '\\';
+ break;
+ case 'b':
+ decoded += '\b';
+ break;
+ case 'f':
+ decoded += '\f';
+ break;
+ case 'n':
+ decoded += '\n';
+ break;
+ case 'r':
+ decoded += '\r';
+ break;
+ case 't':
+ decoded += '\t';
+ break;
+ case 'u':
+ {
+ unsigned int unicode;
+ if (!decodeUnicodeCodePoint(token, current, end, unicode))
+ return false;
+ decoded += codePointToUTF8(unicode);
+ }
+ break;
+ default:
+ return addError("Bad escape sequence in string", token, current);
+ }
+ }
+ else
+ {
+ decoded += c;
+ }
+ }
+ return true;
+}
+
+bool OurReader::decodeUnicodeCodePoint(Token &token, Location &current, Location end,
+ unsigned int &unicode)
+{
+
+ if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+ return false;
+ if (unicode >= 0xD800 && unicode <= 0xDBFF)
+ {
+ // surrogate pairs
+ if (end - current < 6)
+ return addError("additional six characters expected to parse unicode surrogate pair.", token,
+ current);
+ unsigned int surrogatePair;
+ if (*(current++) == '\\' && *(current++) == 'u')
+ {
+ if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair))
+ {
+ unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+ }
+ else
+ return false;
+ }
+ else
+ return addError("expecting another \\u token to begin the second half of "
+ "a unicode surrogate pair",
+ token, current);
+ }
+ return true;
+}
+
+bool OurReader::decodeUnicodeEscapeSequence(Token &token, Location &current, Location end,
+ unsigned int &ret_unicode)
+{
+ if (end - current < 4)
+ return addError("Bad unicode escape sequence in string: four digits expected.", token, current);
+ int unicode = 0;
+ for (int index = 0; index < 4; ++index)
+ {
+ Char c = *current++;
+ unicode *= 16;
+ if (c >= '0' && c <= '9')
+ unicode += c - '0';
+ else if (c >= 'a' && c <= 'f')
+ unicode += c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ unicode += c - 'A' + 10;
+ else
+ return addError("Bad unicode escape sequence in string: hexadecimal digit expected.", token,
+ current);
+ }
+ ret_unicode = static_cast<unsigned int>(unicode);
+ return true;
+}
+
+bool OurReader::addError(const JSONCPP_STRING &message, Token &token, Location extra)
+{
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = extra;
+ errors_.push_back(info);
+ return false;
+}
+
+bool OurReader::recoverFromError(TokenType skipUntilToken)
+{
+ size_t errorCount = errors_.size();
+ Token skip;
+ for (;;)
+ {
+ if (!readToken(skip))
+ errors_.resize(errorCount); // discard errors caused by recovery
+ if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+ break;
+ }
+ errors_.resize(errorCount);
+ return false;
+}
+
+bool OurReader::addErrorAndRecover(const JSONCPP_STRING &message, Token &token,
+ TokenType skipUntilToken)
+{
+ addError(message, token);
+ return recoverFromError(skipUntilToken);
+}
+
+Value &OurReader::currentValue() { return *(nodes_.top()); }
+
+OurReader::Char OurReader::getNextChar()
+{
+ if (current_ == end_)
+ return 0;
+ return *current_++;
+}
+
+void OurReader::getLocationLineAndColumn(Location location, int &line, int &column) const
+{
+ Location current = begin_;
+ Location lastLineStart = current;
+ line = 0;
+ while (current < location && current != end_)
+ {
+ Char c = *current++;
+ if (c == '\r')
+ {
+ if (*current == '\n')
+ ++current;
+ lastLineStart = current;
+ ++line;
+ }
+ else if (c == '\n')
+ {
+ lastLineStart = current;
+ ++line;
+ }
+ }
+ // column & line start at 1
+ column = int(location - lastLineStart) + 1;
+ ++line;
+}
+
+JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const
+{
+ int line, column;
+ getLocationLineAndColumn(location, line, column);
+ char buffer[18 + 16 + 16 + 1];
+ snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+ return buffer;
+}
+
+JSONCPP_STRING OurReader::getFormattedErrorMessages() const
+{
+ JSONCPP_STRING formattedMessage;
+ for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError)
+ {
+ const ErrorInfo &error = *itError;
+ formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+ formattedMessage += " " + error.message_ + "\n";
+ if (error.extra_)
+ formattedMessage += "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+ }
+ return formattedMessage;
+}
+
+std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const
+{
+ std::vector<OurReader::StructuredError> allErrors;
+ for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError)
+ {
+ const ErrorInfo &error = *itError;
+ OurReader::StructuredError structured;
+ structured.offset_start = error.token_.start_ - begin_;
+ structured.offset_limit = error.token_.end_ - begin_;
+ structured.message = error.message_;
+ allErrors.push_back(structured);
+ }
+ return allErrors;
+}
+
+bool OurReader::pushError(const Value &value, const JSONCPP_STRING &message)
+{
+ ptrdiff_t length = end_ - begin_;
+ if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
+ return false;
+ Token token;
+ token.type_ = tokenError;
+ token.start_ = begin_ + value.getOffsetStart();
+ token.end_ = end_ + value.getOffsetLimit();
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = 0;
+ errors_.push_back(info);
+ return true;
+}
+
+bool OurReader::pushError(const Value &value, const JSONCPP_STRING &message, const Value &extra)
+{
+ ptrdiff_t length = end_ - begin_;
+ if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
+ extra.getOffsetLimit() > length)
+ return false;
+ Token token;
+ token.type_ = tokenError;
+ token.start_ = begin_ + value.getOffsetStart();
+ token.end_ = begin_ + value.getOffsetLimit();
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = begin_ + extra.getOffsetStart();
+ errors_.push_back(info);
+ return true;
+}
+
+bool OurReader::good() const { return !errors_.size(); }
+
+class OurCharReader : public CharReader
+{
+ bool const collectComments_;
+ OurReader reader_;
+
+public:
+ OurCharReader(bool collectComments, OurFeatures const &features)
+ : collectComments_(collectComments), reader_(features)
+ {
+ }
+ bool parse(char const *beginDoc, char const *endDoc, Value *root,
+ JSONCPP_STRING *errs) JSONCPP_OVERRIDE
+ {
+ bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
+ if (errs)
+ {
+ *errs = reader_.getFormattedErrorMessages();
+ }
+ return ok;
+ }
+};
+
+CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
+CharReaderBuilder::~CharReaderBuilder() {}
+CharReader *CharReaderBuilder::newCharReader() const
+{
+ bool collectComments = settings_["collectComments"].asBool();
+ OurFeatures features = OurFeatures::all();
+ features.allowComments_ = settings_["allowComments"].asBool();
+ features.strictRoot_ = settings_["strictRoot"].asBool();
+ features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
+ features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
+ features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
+ features.stackLimit_ = settings_["stackLimit"].asInt();
+ features.failIfExtra_ = settings_["failIfExtra"].asBool();
+ features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
+ features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
+ return new OurCharReader(collectComments, features);
+}
+static void getValidReaderKeys(std::set<JSONCPP_STRING> *valid_keys)
+{
+ valid_keys->clear();
+ valid_keys->insert("collectComments");
+ valid_keys->insert("allowComments");
+ valid_keys->insert("strictRoot");
+ valid_keys->insert("allowDroppedNullPlaceholders");
+ valid_keys->insert("allowNumericKeys");
+ valid_keys->insert("allowSingleQuotes");
+ valid_keys->insert("stackLimit");
+ valid_keys->insert("failIfExtra");
+ valid_keys->insert("rejectDupKeys");
+ valid_keys->insert("allowSpecialFloats");
+}
+bool CharReaderBuilder::validate(Json::Value *invalid) const
+{
+ Json::Value my_invalid;
+ if (!invalid)
+ invalid = &my_invalid; // so we do not need to test for NULL
+ Json::Value &inv = *invalid;
+ std::set<JSONCPP_STRING> valid_keys;
+ getValidReaderKeys(&valid_keys);
+ Value::Members keys = settings_.getMemberNames();
+ size_t n = keys.size();
+ for (size_t i = 0; i < n; ++i)
+ {
+ JSONCPP_STRING const &key = keys[i];
+ if (valid_keys.find(key) == valid_keys.end())
+ {
+ inv[key] = settings_[key];
+ }
+ }
+ return 0u == inv.size();
+}
+Value &CharReaderBuilder::operator[](JSONCPP_STRING key) { return settings_[key]; }
+// static
+void CharReaderBuilder::strictMode(Json::Value *settings)
+{
+ //! [CharReaderBuilderStrictMode]
+ (*settings)["allowComments"] = false;
+ (*settings)["strictRoot"] = true;
+ (*settings)["allowDroppedNullPlaceholders"] = false;
+ (*settings)["allowNumericKeys"] = false;
+ (*settings)["allowSingleQuotes"] = false;
+ (*settings)["stackLimit"] = 1000;
+ (*settings)["failIfExtra"] = true;
+ (*settings)["rejectDupKeys"] = true;
+ (*settings)["allowSpecialFloats"] = false;
+ //! [CharReaderBuilderStrictMode]
+}
+// static
+void CharReaderBuilder::setDefaults(Json::Value *settings)
+{
+ //! [CharReaderBuilderDefaults]
+ (*settings)["collectComments"] = true;
+ (*settings)["allowComments"] = true;
+ (*settings)["strictRoot"] = false;
+ (*settings)["allowDroppedNullPlaceholders"] = false;
+ (*settings)["allowNumericKeys"] = false;
+ (*settings)["allowSingleQuotes"] = false;
+ (*settings)["stackLimit"] = 1000;
+ (*settings)["failIfExtra"] = false;
+ (*settings)["rejectDupKeys"] = false;
+ (*settings)["allowSpecialFloats"] = false;
+ //! [CharReaderBuilderDefaults]
+}
+
+//////////////////////////////////
+// global functions
+
+bool parseFromStream(CharReader::Factory const &fact, JSONCPP_ISTREAM &sin, Value *root,
+ JSONCPP_STRING *errs)
+{
+ JSONCPP_OSTRINGSTREAM ssin;
+ ssin << sin.rdbuf();
+ JSONCPP_STRING doc = ssin.str();
+ char const *begin = doc.data();
+ char const *end = begin + doc.size();
+ // Note that we do not actually need a null-terminator.
+ CharReaderPtr const reader(fact.newCharReader());
+ return reader->parse(begin, end, root, errs);
+}
+
+JSONCPP_ISTREAM &operator>>(JSONCPP_ISTREAM &sin, Value &root)
+{
+ CharReaderBuilder b;
+ JSONCPP_STRING errs;
+ bool ok = parseFromStream(b, sin, &root, &errs);
+ if (!ok)
+ {
+ fprintf(stderr, "Error from reader: %s", errs.c_str());
+
+ throwRuntimeError(errs);
+ }
+ return sin;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_reader.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_valueiterator.inl
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json
+{
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true) {}
+
+ValueIteratorBase::ValueIteratorBase(const Value::ObjectValues::iterator &current)
+ : current_(current), isNull_(false)
+{
+}
+
+Value &ValueIteratorBase::deref() const { return current_->second; }
+
+void ValueIteratorBase::increment() { ++current_; }
+
+void ValueIteratorBase::decrement() { --current_; }
+
+ValueIteratorBase::difference_type ValueIteratorBase::computeDistance(const SelfType &other) const
+{
+#ifdef JSON_USE_CPPTL_SMALLMAP
+ return other.current_ - current_;
+#else
+ // Iterator for null value are initialized using the default
+ // constructor, which initialize current_ to the default
+ // std::map::iterator. As begin() and end() are two instance
+ // of the default std::map::iterator, they can not be compared.
+ // To allow this, we handle this comparison specifically.
+ if (isNull_ && other.isNull_)
+ {
+ return 0;
+ }
+
+ // Usage of std::distance is not portable (does not compile with Sun Studio 12
+ // RogueWave STL,
+ // which is the one used by default).
+ // Using a portable hand-made version for non random iterator instead:
+ // return difference_type( std::distance( current_, other.current_ ) );
+ difference_type myDistance = 0;
+ for (Value::ObjectValues::iterator it = current_; it != other.current_; ++it)
+ {
+ ++myDistance;
+ }
+ return myDistance;
+#endif
+}
+
+bool ValueIteratorBase::isEqual(const SelfType &other) const
+{
+ if (isNull_)
+ {
+ return other.isNull_;
+ }
+ return current_ == other.current_;
+}
+
+void ValueIteratorBase::copy(const SelfType &other)
+{
+ current_ = other.current_;
+ isNull_ = other.isNull_;
+}
+
+Value ValueIteratorBase::key() const
+{
+ const Value::CZString czstring = (*current_).first;
+ if (czstring.data())
+ {
+ if (czstring.isStaticString())
+ return Value(StaticString(czstring.data()));
+ return Value(czstring.data(), czstring.data() + czstring.length());
+ }
+ return Value(czstring.index());
+}
+
+UInt ValueIteratorBase::index() const
+{
+ const Value::CZString czstring = (*current_).first;
+ if (!czstring.data())
+ return czstring.index();
+ return Value::UInt(-1);
+}
+
+JSONCPP_STRING ValueIteratorBase::name() const
+{
+ char const *keey;
+ char const *end;
+ keey = memberName(&end);
+ if (!keey)
+ return JSONCPP_STRING();
+ return JSONCPP_STRING(keey, end);
+}
+
+char const *ValueIteratorBase::memberName() const
+{
+ const char *cname = (*current_).first.data();
+ return cname ? cname : "";
+}
+
+char const *ValueIteratorBase::memberName(char const **end) const
+{
+ const char *cname = (*current_).first.data();
+ if (!cname)
+ {
+ *end = NULL;
+ return NULL;
+ }
+ *end = cname + (*current_).first.length();
+ return cname;
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueConstIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueConstIterator::ValueConstIterator() {}
+
+ValueConstIterator::ValueConstIterator(const Value::ObjectValues::iterator &current)
+ : ValueIteratorBase(current)
+{
+}
+
+ValueConstIterator::ValueConstIterator(ValueIterator const &other) : ValueIteratorBase(other) {}
+
+ValueConstIterator &ValueConstIterator::operator=(const ValueIteratorBase &other)
+{
+ copy(other);
+ return *this;
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIterator::ValueIterator() {}
+
+ValueIterator::ValueIterator(const Value::ObjectValues::iterator &current)
+ : ValueIteratorBase(current)
+{
+}
+
+ValueIterator::ValueIterator(const ValueConstIterator &other) : ValueIteratorBase(other)
+{
+ throwRuntimeError("ConstIterator to Iterator should never be allowed.");
+}
+
+ValueIterator::ValueIterator(const ValueIterator &other) : ValueIteratorBase(other) {}
+
+ValueIterator &ValueIterator::operator=(const SelfType &other)
+{
+ copy(other);
+ return *this;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_valueiterator.inl
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_value.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/value.h>
+#include <json/writer.h>
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <math.h>
+#include <sstream>
+#include <utility>
+#include <cstring>
+#include <cassert>
+#ifdef JSON_USE_CPPTL
+#include <cpptl/conststring.h>
+#endif
+#include <cstddef> // size_t
+#include <algorithm> // min()
+
+#define JSON_ASSERT_UNREACHABLE assert(false)
+
+namespace Json
+{
+
+// This is a walkaround to avoid the static initialization of Value::null.
+// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
+// 8 (instead of 4) as a bit of future-proofing.
+#if defined(__ARMEL__)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#else
+#define ALIGNAS(byte_alignment)
+#endif
+// static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
+// const unsigned char& kNullRef = kNull[0];
+// const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
+// const Value& Value::nullRef = null;
+
+// static
+Value const &Value::nullSingleton()
+{
+ static Value const nullStatic;
+ return nullStatic;
+}
+
+// for backwards compatibility, we'll leave these global references around, but DO NOT
+// use them in JSONCPP library code any more!
+Value const &Value::null = Value::nullSingleton();
+Value const &Value::nullRef = Value::nullSingleton();
+
+const Int Value::minInt = Int(~(UInt(-1) / 2));
+const Int Value::maxInt = Int(UInt(-1) / 2);
+const UInt Value::maxUInt = UInt(-1);
+#if defined(JSON_HAS_INT64)
+const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
+const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
+const UInt64 Value::maxUInt64 = UInt64(-1);
+// The constant is hard-coded because some compiler have trouble
+// converting Value::maxUInt64 to a double correctly (AIX/xlC).
+// Assumes that UInt64 is a 64 bits integer.
+static const double maxUInt64AsDouble = 18446744073709551615.0;
+#endif // defined(JSON_HAS_INT64)
+const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
+const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
+const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
+
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+template <typename T, typename U> static inline bool InRange(double d, T min, U max)
+{
+ // The casts can lose precision, but we are looking only for
+ // an approximate range. Might fail on edge cases though. ~cdunn
+ // return d >= static_cast<double>(min) && d <= static_cast<double>(max);
+ return d >= min && d <= max;
+}
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+static inline double integerToDouble(Json::UInt64 value)
+{
+ return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1));
+}
+
+template <typename T> static inline double integerToDouble(T value)
+{
+ return static_cast<double>(value);
+}
+
+template <typename T, typename U> static inline bool InRange(double d, T min, U max)
+{
+ return d >= integerToDouble(min) && d <= integerToDouble(max);
+}
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+
+/** Duplicates the specified string value.
+ * @param value Pointer to the string to duplicate. Must be zero-terminated if
+ * length is "unknown".
+ * @param length Length of the value. if equals to unknown, then it will be
+ * computed using strlen(value).
+ * @return Pointer on the duplicate instance of string.
+ */
+static inline char *duplicateStringValue(const char *value, size_t length)
+{
+ // Avoid an integer overflow in the call to malloc below by limiting length
+ // to a sane value.
+ if (length >= static_cast<size_t>(Value::maxInt))
+ length = Value::maxInt - 1;
+
+ char *newString = static_cast<char *>(malloc(length + 1));
+ if (newString == NULL)
+ {
+ throwRuntimeError("in Json::Value::duplicateStringValue(): "
+ "Failed to allocate string value buffer");
+ }
+ memcpy(newString, value, length);
+ newString[length] = 0;
+ return newString;
+}
+
+/* Record the length as a prefix.
+ */
+static inline char *duplicateAndPrefixStringValue(const char *value, unsigned int length)
+{
+ // Avoid an integer overflow in the call to malloc below by limiting length
+ // to a sane value.
+ JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U,
+ "in Json::Value::duplicateAndPrefixStringValue(): "
+ "length too big for prefixing");
+ unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
+ char *newString = static_cast<char *>(malloc(actualLength));
+ if (newString == 0)
+ {
+ throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
+ "Failed to allocate string value buffer");
+ }
+ *reinterpret_cast<unsigned *>(newString) = length;
+ memcpy(newString + sizeof(unsigned), value, length);
+ newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
+ return newString;
+}
+inline static void decodePrefixedString(bool isPrefixed, char const *prefixed, unsigned *length,
+ char const **value)
+{
+ if (!isPrefixed)
+ {
+ *length = static_cast<unsigned>(strlen(prefixed));
+ *value = prefixed;
+ }
+ else
+ {
+ *length = *reinterpret_cast<unsigned const *>(prefixed);
+ *value = prefixed + sizeof(unsigned);
+ }
+}
+/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
+ */
+#if JSONCPP_USING_SECURE_MEMORY
+static inline void releasePrefixedStringValue(char *value)
+{
+ unsigned length = 0;
+ char const *valueDecoded;
+ decodePrefixedString(true, value, &length, &valueDecoded);
+ size_t const size = sizeof(unsigned) + length + 1U;
+ memset(value, 0, size);
+ free(value);
+}
+static inline void releaseStringValue(char *value, unsigned length)
+{
+ // length==0 => we allocated the strings memory
+ size_t size = (length == 0) ? strlen(value) : length;
+ memset(value, 0, size);
+ free(value);
+}
+#else // !JSONCPP_USING_SECURE_MEMORY
+static inline void releasePrefixedStringValue(char *value) { free(value); }
+static inline void releaseStringValue(char *value, unsigned) { free(value); }
+#endif // JSONCPP_USING_SECURE_MEMORY
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "json_valueiterator.inl"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json
+{
+
+Exception::Exception(JSONCPP_STRING const &msg) : msg_(msg) {}
+Exception::~Exception() throw() {}
+char const *Exception::what() const throw() { return msg_.c_str(); }
+RuntimeError::RuntimeError(JSONCPP_STRING const &msg) : Exception(msg) {}
+LogicError::LogicError(JSONCPP_STRING const &msg) : Exception(msg) {}
+JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const &msg) { throw RuntimeError(msg); }
+JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const &msg) { throw LogicError(msg); }
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+Value::CommentInfo::CommentInfo() : comment_(0) {}
+
+Value::CommentInfo::~CommentInfo()
+{
+ if (comment_)
+ releaseStringValue(comment_, 0u);
+}
+
+void Value::CommentInfo::setComment(const char *text, size_t len)
+{
+ if (comment_)
+ {
+ releaseStringValue(comment_, 0u);
+ comment_ = 0;
+ }
+ JSON_ASSERT(text != 0);
+ JSON_ASSERT_MESSAGE(text[0] == '\0' || text[0] == '/',
+ "in Json::Value::setComment(): Comments must start with /");
+ // It seems that /**/ style comments are acceptable as well.
+ comment_ = duplicateStringValue(text, len);
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+// Notes: policy_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
+
+Value::CZString::CZString(char const *str, unsigned ulength, DuplicationPolicy allocate)
+ : cstr_(str)
+{
+ // allocate != duplicate
+ storage_.policy_ = allocate & 0x3;
+ storage_.length_ = ulength & 0x3FFFFFFF;
+}
+
+Value::CZString::CZString(const CZString &other)
+{
+ cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0
+ ? duplicateStringValue(other.cstr_, other.storage_.length_)
+ : other.cstr_);
+ storage_.policy_ =
+ static_cast<unsigned>(
+ other.cstr_ ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
+ ? noDuplication
+ : duplicate)
+ : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
+ 3U;
+ storage_.length_ = other.storage_.length_;
+}
+
+#if JSON_HAS_RVALUE_REFERENCES
+Value::CZString::CZString(CZString &&other) : cstr_(other.cstr_), index_(other.index_)
+{
+ other.cstr_ = nullptr;
+}
+#endif
+
+Value::CZString::~CZString()
+{
+ if (cstr_ && storage_.policy_ == duplicate)
+ {
+ releaseStringValue(const_cast<char *>(cstr_), storage_.length_ + 1u); //+1 for null terminating
+ // character for sake of
+ // completeness but not
+ // actually necessary
+ }
+}
+
+void Value::CZString::swap(CZString &other)
+{
+ std::swap(cstr_, other.cstr_);
+ std::swap(index_, other.index_);
+}
+
+Value::CZString &Value::CZString::operator=(CZString other)
+{
+ swap(other);
+ return *this;
+}
+
+bool Value::CZString::operator<(const CZString &other) const
+{
+ if (!cstr_)
+ return index_ < other.index_;
+ // return strcmp(cstr_, other.cstr_) < 0;
+ // Assume both are strings.
+ unsigned this_len = this->storage_.length_;
+ unsigned other_len = other.storage_.length_;
+ unsigned min_len = std::min(this_len, other_len);
+ JSON_ASSERT(this->cstr_ && other.cstr_);
+ int comp = memcmp(this->cstr_, other.cstr_, min_len);
+ if (comp < 0)
+ return true;
+ if (comp > 0)
+ return false;
+ return (this_len < other_len);
+}
+
+bool Value::CZString::operator==(const CZString &other) const
+{
+ if (!cstr_)
+ return index_ == other.index_;
+ // return strcmp(cstr_, other.cstr_) == 0;
+ // Assume both are strings.
+ unsigned this_len = this->storage_.length_;
+ unsigned other_len = other.storage_.length_;
+ if (this_len != other_len)
+ return false;
+ JSON_ASSERT(this->cstr_ && other.cstr_);
+ int comp = memcmp(this->cstr_, other.cstr_, this_len);
+ return comp == 0;
+}
+
+ArrayIndex Value::CZString::index() const { return index_; }
+
+// const char* Value::CZString::c_str() const { return cstr_; }
+const char *Value::CZString::data() const { return cstr_; }
+unsigned Value::CZString::length() const { return storage_.length_; }
+bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value(ValueType vtype)
+{
+ static char const empty[] = "";
+ initBasic(vtype);
+ switch (vtype)
+ {
+ case nullValue:
+ break;
+ case intValue:
+ case uintValue:
+ value_.int_ = 0;
+ break;
+ case realValue:
+ value_.real_ = 0.0;
+ break;
+ case stringValue:
+ // allocated_ == false, so this is safe.
+ value_.string_ = const_cast<char *>(static_cast<char const *>(empty));
+ break;
+ case arrayValue:
+ case objectValue:
+ value_.map_ = new ObjectValues();
+ break;
+ case booleanValue:
+ value_.bool_ = false;
+ break;
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+}
+
+Value::Value(Int value)
+{
+ initBasic(intValue);
+ value_.int_ = value;
+}
+
+Value::Value(UInt value)
+{
+ initBasic(uintValue);
+ value_.uint_ = value;
+}
+#if defined(JSON_HAS_INT64)
+Value::Value(Int64 value)
+{
+ initBasic(intValue);
+ value_.int_ = value;
+}
+Value::Value(UInt64 value)
+{
+ initBasic(uintValue);
+ value_.uint_ = value;
+}
+#endif // defined(JSON_HAS_INT64)
+
+Value::Value(double value)
+{
+ initBasic(realValue);
+ value_.real_ = value;
+}
+
+Value::Value(const char *value)
+{
+ initBasic(stringValue, true);
+ value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
+}
+
+Value::Value(const char *beginValue, const char *endValue)
+{
+ initBasic(stringValue, true);
+ value_.string_ =
+ duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
+}
+
+Value::Value(const JSONCPP_STRING &value)
+{
+ initBasic(stringValue, true);
+ value_.string_ =
+ duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
+}
+
+Value::Value(const StaticString &value)
+{
+ initBasic(stringValue);
+ value_.string_ = const_cast<char *>(value.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value::Value(const CppTL::ConstString &value)
+{
+ initBasic(stringValue, true);
+ value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
+}
+#endif
+
+Value::Value(bool value)
+{
+ initBasic(booleanValue);
+ value_.bool_ = value;
+}
+
+Value::Value(Value const &other)
+ : type_(other.type_), allocated_(false), comments_(0), start_(other.start_),
+ limit_(other.limit_)
+{
+ switch (type_)
+ {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ value_ = other.value_;
+ break;
+ case stringValue:
+ if (other.value_.string_ && other.allocated_)
+ {
+ unsigned len;
+ char const *str;
+ decodePrefixedString(other.allocated_, other.value_.string_, &len, &str);
+ value_.string_ = duplicateAndPrefixStringValue(str, len);
+ allocated_ = true;
+ }
+ else
+ {
+ value_.string_ = other.value_.string_;
+ allocated_ = false;
+ }
+ break;
+ case arrayValue:
+ case objectValue:
+ value_.map_ = new ObjectValues(*other.value_.map_);
+ break;
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ if (other.comments_)
+ {
+ comments_ = new CommentInfo[numberOfCommentPlacement];
+ for (int comment = 0; comment < numberOfCommentPlacement; ++comment)
+ {
+ const CommentInfo &otherComment = other.comments_[comment];
+ if (otherComment.comment_)
+ comments_[comment].setComment(otherComment.comment_, strlen(otherComment.comment_));
+ }
+ }
+}
+
+#if JSON_HAS_RVALUE_REFERENCES
+// Move constructor
+Value::Value(Value &&other)
+{
+ initBasic(nullValue);
+ swap(other);
+}
+#endif
+
+Value::~Value()
+{
+ switch (type_)
+ {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ break;
+ case stringValue:
+ if (allocated_)
+ releasePrefixedStringValue(value_.string_);
+ break;
+ case arrayValue:
+ case objectValue:
+ delete value_.map_;
+ break;
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+
+ delete[] comments_;
+
+ value_.uint_ = 0;
+}
+
+Value &Value::operator=(Value other)
+{
+ swap(other);
+ return *this;
+}
+
+void Value::swapPayload(Value &other)
+{
+ ValueType temp = type_;
+ type_ = other.type_;
+ other.type_ = temp;
+ std::swap(value_, other.value_);
+ int temp2 = allocated_;
+ allocated_ = other.allocated_;
+ other.allocated_ = temp2 & 0x1;
+}
+
+void Value::swap(Value &other)
+{
+ swapPayload(other);
+ std::swap(comments_, other.comments_);
+ std::swap(start_, other.start_);
+ std::swap(limit_, other.limit_);
+}
+
+ValueType Value::type() const { return type_; }
+
+int Value::compare(const Value &other) const
+{
+ if (*this < other)
+ return -1;
+ if (*this > other)
+ return 1;
+ return 0;
+}
+
+bool Value::operator<(const Value &other) const
+{
+ int typeDelta = type_ - other.type_;
+ if (typeDelta)
+ return typeDelta < 0 ? true : false;
+ switch (type_)
+ {
+ case nullValue:
+ return false;
+ case intValue:
+ return value_.int_ < other.value_.int_;
+ case uintValue:
+ return value_.uint_ < other.value_.uint_;
+ case realValue:
+ return value_.real_ < other.value_.real_;
+ case booleanValue:
+ return value_.bool_ < other.value_.bool_;
+ case stringValue:
+ {
+ if ((value_.string_ == 0) || (other.value_.string_ == 0))
+ {
+ if (other.value_.string_)
+ return true;
+ else
+ return false;
+ }
+ unsigned this_len;
+ unsigned other_len;
+ char const *this_str;
+ char const *other_str;
+ decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+ decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
+ unsigned min_len = std::min(this_len, other_len);
+ JSON_ASSERT(this_str && other_str);
+ int comp = memcmp(this_str, other_str, min_len);
+ if (comp < 0)
+ return true;
+ if (comp > 0)
+ return false;
+ return (this_len < other_len);
+ }
+ case arrayValue:
+ case objectValue:
+ {
+ int delta = int(value_.map_->size() - other.value_.map_->size());
+ if (delta)
+ return delta < 0;
+ return (*value_.map_) < (*other.value_.map_);
+ }
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return false; // unreachable
+}
+
+bool Value::operator<=(const Value &other) const { return !(other < *this); }
+
+bool Value::operator>=(const Value &other) const { return !(*this < other); }
+
+bool Value::operator>(const Value &other) const { return other < *this; }
+
+bool Value::operator==(const Value &other) const
+{
+ // if ( type_ != other.type_ )
+ // GCC 2.95.3 says:
+ // attempt to take address of bit-field structure member `Json::Value::type_'
+ // Beats me, but a temp solves the problem.
+ int temp = other.type_;
+ if (type_ != temp)
+ return false;
+ switch (type_)
+ {
+ case nullValue:
+ return true;
+ case intValue:
+ return value_.int_ == other.value_.int_;
+ case uintValue:
+ return value_.uint_ == other.value_.uint_;
+ case realValue:
+ return value_.real_ == other.value_.real_;
+ case booleanValue:
+ return value_.bool_ == other.value_.bool_;
+ case stringValue:
+ {
+ if ((value_.string_ == 0) || (other.value_.string_ == 0))
+ {
+ return (value_.string_ == other.value_.string_);
+ }
+ unsigned this_len;
+ unsigned other_len;
+ char const *this_str;
+ char const *other_str;
+ decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+ decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
+ if (this_len != other_len)
+ return false;
+ JSON_ASSERT(this_str && other_str);
+ int comp = memcmp(this_str, other_str, this_len);
+ return comp == 0;
+ }
+ case arrayValue:
+ case objectValue:
+ return value_.map_->size() == other.value_.map_->size() &&
+ (*value_.map_) == (*other.value_.map_);
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return false; // unreachable
+}
+
+bool Value::operator!=(const Value &other) const { return !(*this == other); }
+
+const char *Value::asCString() const
+{
+ JSON_ASSERT_MESSAGE(type_ == stringValue, "in Json::Value::asCString(): requires stringValue");
+ if (value_.string_ == 0)
+ return 0;
+ unsigned this_len;
+ char const *this_str;
+ decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+ return this_str;
+}
+
+#if JSONCPP_USING_SECURE_MEMORY
+unsigned Value::getCStringLength() const
+{
+ JSON_ASSERT_MESSAGE(type_ == stringValue, "in Json::Value::asCString(): requires stringValue");
+ if (value_.string_ == 0)
+ return 0;
+ unsigned this_len;
+ char const *this_str;
+ decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+ return this_len;
+}
+#endif
+
+bool Value::getString(char const **str, char const **cend) const
+{
+ if (type_ != stringValue)
+ return false;
+ if (value_.string_ == 0)
+ return false;
+ unsigned length;
+ decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
+ *cend = *str + length;
+ return true;
+}
+
+JSONCPP_STRING Value::asString() const
+{
+ switch (type_)
+ {
+ case nullValue:
+ return "";
+ case stringValue:
+ {
+ if (value_.string_ == 0)
+ return "";
+ unsigned this_len;
+ char const *this_str;
+ decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+ return JSONCPP_STRING(this_str, this_len);
+ }
+ case booleanValue:
+ return value_.bool_ ? "true" : "false";
+ case intValue:
+ return valueToString(value_.int_);
+ case uintValue:
+ return valueToString(value_.uint_);
+ case realValue:
+ return valueToString(value_.real_);
+ default:
+ JSON_FAIL_MESSAGE("Type is not convertible to string");
+ }
+}
+
+#ifdef JSON_USE_CPPTL
+CppTL::ConstString Value::asConstString() const
+{
+ unsigned len;
+ char const *str;
+ decodePrefixedString(allocated_, value_.string_, &len, &str);
+ return CppTL::ConstString(str, len);
+}
+#endif
+
+Value::Int Value::asInt() const
+{
+ switch (type_)
+ {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
+ return Int(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
+ return Int(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), "double out of Int range");
+ return Int(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to Int.");
+}
+
+Value::UInt Value::asUInt() const
+{
+ switch (type_)
+ {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
+ return UInt(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
+ return UInt(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), "double out of UInt range");
+ return UInt(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
+}
+
+#if defined(JSON_HAS_INT64)
+
+Value::Int64 Value::asInt64() const
+{
+ switch (type_)
+ {
+ case intValue:
+ return Int64(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
+ return Int64(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), "double out of Int64 range");
+ return Int64(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
+}
+
+Value::UInt64 Value::asUInt64() const
+{
+ switch (type_)
+ {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
+ return UInt64(value_.int_);
+ case uintValue:
+ return UInt64(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), "double out of UInt64 range");
+ return UInt64(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
+}
+#endif // if defined(JSON_HAS_INT64)
+
+LargestInt Value::asLargestInt() const
+{
+#if defined(JSON_NO_INT64)
+ return asInt();
+#else
+ return asInt64();
+#endif
+}
+
+LargestUInt Value::asLargestUInt() const
+{
+#if defined(JSON_NO_INT64)
+ return asUInt();
+#else
+ return asUInt64();
+#endif
+}
+
+double Value::asDouble() const
+{
+ switch (type_)
+ {
+ case intValue:
+ return static_cast<double>(value_.int_);
+ case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return static_cast<double>(value_.uint_);
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ case realValue:
+ return value_.real_;
+ case nullValue:
+ return 0.0;
+ case booleanValue:
+ return value_.bool_ ? 1.0 : 0.0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to double.");
+}
+
+float Value::asFloat() const
+{
+ switch (type_)
+ {
+ case intValue:
+ return static_cast<float>(value_.int_);
+ case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return static_cast<float>(value_.uint_);
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ // This can fail (silently?) if the value is bigger than MAX_FLOAT.
+ return static_cast<float>(integerToDouble(value_.uint_));
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ case realValue:
+ return static_cast<float>(value_.real_);
+ case nullValue:
+ return 0.0;
+ case booleanValue:
+ return value_.bool_ ? 1.0f : 0.0f;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to float.");
+}
+
+bool Value::asBool() const
+{
+ switch (type_)
+ {
+ case booleanValue:
+ return value_.bool_;
+ case nullValue:
+ return false;
+ case intValue:
+ return value_.int_ ? true : false;
+ case uintValue:
+ return value_.uint_ ? true : false;
+ case realValue:
+ // This is kind of strange. Not recommended.
+ return (value_.real_ != 0.0) ? true : false;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to bool.");
+}
+
+bool Value::isConvertibleTo(ValueType other) const
+{
+ switch (other)
+ {
+ case nullValue:
+ return (isNumeric() && asDouble() == 0.0) ||
+ (type_ == booleanValue && value_.bool_ == false) ||
+ (type_ == stringValue && asString() == "") ||
+ (type_ == arrayValue && value_.map_->size() == 0) ||
+ (type_ == objectValue && value_.map_->size() == 0) || type_ == nullValue;
+ case intValue:
+ return isInt() || (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
+ type_ == booleanValue || type_ == nullValue;
+ case uintValue:
+ return isUInt() || (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
+ type_ == booleanValue || type_ == nullValue;
+ case realValue:
+ return isNumeric() || type_ == booleanValue || type_ == nullValue;
+ case booleanValue:
+ return isNumeric() || type_ == booleanValue || type_ == nullValue;
+ case stringValue:
+ return isNumeric() || type_ == booleanValue || type_ == stringValue || type_ == nullValue;
+ case arrayValue:
+ return type_ == arrayValue || type_ == nullValue;
+ case objectValue:
+ return type_ == objectValue || type_ == nullValue;
+ }
+ JSON_ASSERT_UNREACHABLE;
+ return false;
+}
+
+/// Number of values in array or object
+ArrayIndex Value::size() const
+{
+ switch (type_)
+ {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ case stringValue:
+ return 0;
+ case arrayValue: // size of the array is highest index + 1
+ if (!value_.map_->empty())
+ {
+ ObjectValues::const_iterator itLast = value_.map_->end();
+ --itLast;
+ return (*itLast).first.index() + 1;
+ }
+ return 0;
+ case objectValue:
+ return ArrayIndex(value_.map_->size());
+ }
+ JSON_ASSERT_UNREACHABLE;
+ return 0; // unreachable;
+}
+
+bool Value::empty() const
+{
+ if (isNull() || isArray() || isObject())
+ return size() == 0u;
+ else
+ return false;
+}
+
+bool Value::operator!() const { return isNull(); }
+
+void Value::clear()
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || type_ == objectValue,
+ "in Json::Value::clear(): requires complex value");
+ start_ = 0;
+ limit_ = 0;
+ switch (type_)
+ {
+ case arrayValue:
+ case objectValue:
+ value_.map_->clear();
+ break;
+ default:
+ break;
+ }
+}
+
+void Value::resize(ArrayIndex newSize)
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::resize(): requires arrayValue");
+ if (type_ == nullValue)
+ *this = Value(arrayValue);
+ ArrayIndex oldSize = size();
+ if (newSize == 0)
+ clear();
+ else if (newSize > oldSize)
+ (*this)[newSize - 1];
+ else
+ {
+ for (ArrayIndex index = newSize; index < oldSize; ++index)
+ {
+ value_.map_->erase(index);
+ }
+ JSON_ASSERT(size() == newSize);
+ }
+}
+
+Value &Value::operator[](ArrayIndex index)
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::operator[](ArrayIndex): requires arrayValue");
+ if (type_ == nullValue)
+ *this = Value(arrayValue);
+ CZString key(index);
+ ObjectValues::iterator it = value_.map_->lower_bound(key);
+ if (it != value_.map_->end() && (*it).first == key)
+ return (*it).second;
+
+ ObjectValues::value_type defaultValue(key, nullSingleton());
+ it = value_.map_->insert(it, defaultValue);
+ return (*it).second;
+}
+
+Value &Value::operator[](int index)
+{
+ JSON_ASSERT_MESSAGE(index >= 0,
+ "in Json::Value::operator[](int index): index cannot be negative");
+ return (*this)[ArrayIndex(index)];
+}
+
+const Value &Value::operator[](ArrayIndex index) const
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
+ if (type_ == nullValue)
+ return nullSingleton();
+ CZString key(index);
+ ObjectValues::const_iterator it = value_.map_->find(key);
+ if (it == value_.map_->end())
+ return nullSingleton();
+ return (*it).second;
+}
+
+const Value &Value::operator[](int index) const
+{
+ JSON_ASSERT_MESSAGE(index >= 0,
+ "in Json::Value::operator[](int index) const: index cannot be negative");
+ return (*this)[ArrayIndex(index)];
+}
+
+void Value::initBasic(ValueType vtype, bool allocated)
+{
+ type_ = vtype;
+ allocated_ = allocated;
+ comments_ = 0;
+ start_ = 0;
+ limit_ = 0;
+}
+
+// Access an object value by name, create a null member if it does not exist.
+// @pre Type of '*this' is object or null.
+// @param key is null-terminated.
+Value &Value::resolveReference(const char *key)
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+ "in Json::Value::resolveReference(): requires objectValue");
+ if (type_ == nullValue)
+ *this = Value(objectValue);
+ CZString actualKey(key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
+ ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+ if (it != value_.map_->end() && (*it).first == actualKey)
+ return (*it).second;
+
+ ObjectValues::value_type defaultValue(actualKey, nullSingleton());
+ it = value_.map_->insert(it, defaultValue);
+ Value &value = (*it).second;
+ return value;
+}
+
+// @param key is not null-terminated.
+Value &Value::resolveReference(char const *key, char const *cend)
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+ "in Json::Value::resolveReference(key, end): requires objectValue");
+ if (type_ == nullValue)
+ *this = Value(objectValue);
+ CZString actualKey(key, static_cast<unsigned>(cend - key), CZString::duplicateOnCopy);
+ ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+ if (it != value_.map_->end() && (*it).first == actualKey)
+ return (*it).second;
+
+ ObjectValues::value_type defaultValue(actualKey, nullSingleton());
+ it = value_.map_->insert(it, defaultValue);
+ Value &value = (*it).second;
+ return value;
+}
+
+Value Value::get(ArrayIndex index, const Value &defaultValue) const
+{
+ const Value *value = &((*this)[index]);
+ return value == &nullSingleton() ? defaultValue : *value;
+}
+
+bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
+
+Value const *Value::find(char const *key, char const *cend) const
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+ "in Json::Value::find(key, end, found): requires objectValue or nullValue");
+ if (type_ == nullValue)
+ return NULL;
+ CZString actualKey(key, static_cast<unsigned>(cend - key), CZString::noDuplication);
+ ObjectValues::const_iterator it = value_.map_->find(actualKey);
+ if (it == value_.map_->end())
+ return NULL;
+ return &(*it).second;
+}
+const Value &Value::operator[](const char *key) const
+{
+ Value const *found = find(key, key + strlen(key));
+ if (!found)
+ return nullSingleton();
+ return *found;
+}
+Value const &Value::operator[](JSONCPP_STRING const &key) const
+{
+ Value const *found = find(key.data(), key.data() + key.length());
+ if (!found)
+ return nullSingleton();
+ return *found;
+}
+
+Value &Value::operator[](const char *key) { return resolveReference(key, key + strlen(key)); }
+
+Value &Value::operator[](const JSONCPP_STRING &key)
+{
+ return resolveReference(key.data(), key.data() + key.length());
+}
+
+Value &Value::operator[](const StaticString &key) { return resolveReference(key.c_str()); }
+
+#ifdef JSON_USE_CPPTL
+Value &Value::operator[](const CppTL::ConstString &key)
+{
+ return resolveReference(key.c_str(), key.end_c_str());
+}
+Value const &Value::operator[](CppTL::ConstString const &key) const
+{
+ Value const *found = find(key.c_str(), key.end_c_str());
+ if (!found)
+ return nullSingleton();
+ return *found;
+}
+#endif
+
+Value &Value::append(const Value &value) { return (*this)[size()] = value; }
+
+Value Value::get(char const *key, char const *cend, Value const &defaultValue) const
+{
+ Value const *found = find(key, cend);
+ return !found ? defaultValue : *found;
+}
+Value Value::get(char const *key, Value const &defaultValue) const
+{
+ return get(key, key + strlen(key), defaultValue);
+}
+Value Value::get(JSONCPP_STRING const &key, Value const &defaultValue) const
+{
+ return get(key.data(), key.data() + key.length(), defaultValue);
+}
+
+bool Value::removeMember(const char *key, const char *cend, Value *removed)
+{
+ if (type_ != objectValue)
+ {
+ return false;
+ }
+ CZString actualKey(key, static_cast<unsigned>(cend - key), CZString::noDuplication);
+ ObjectValues::iterator it = value_.map_->find(actualKey);
+ if (it == value_.map_->end())
+ return false;
+ *removed = it->second;
+ value_.map_->erase(it);
+ return true;
+}
+bool Value::removeMember(const char *key, Value *removed)
+{
+ return removeMember(key, key + strlen(key), removed);
+}
+bool Value::removeMember(JSONCPP_STRING const &key, Value *removed)
+{
+ return removeMember(key.data(), key.data() + key.length(), removed);
+}
+Value Value::removeMember(const char *key)
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+ "in Json::Value::removeMember(): requires objectValue");
+ if (type_ == nullValue)
+ return nullSingleton();
+
+ Value removed; // null
+ removeMember(key, key + strlen(key), &removed);
+ return removed; // still null if removeMember() did nothing
+}
+Value Value::removeMember(const JSONCPP_STRING &key) { return removeMember(key.c_str()); }
+
+bool Value::removeIndex(ArrayIndex index, Value *removed)
+{
+ if (type_ != arrayValue)
+ {
+ return false;
+ }
+ CZString key(index);
+ ObjectValues::iterator it = value_.map_->find(key);
+ if (it == value_.map_->end())
+ {
+ return false;
+ }
+ *removed = it->second;
+ ArrayIndex oldSize = size();
+ // shift left all items left, into the place of the "removed"
+ for (ArrayIndex i = index; i < (oldSize - 1); ++i)
+ {
+ CZString keey(i);
+ (*value_.map_)[keey] = (*this)[i + 1];
+ }
+ // erase the last one ("leftover")
+ CZString keyLast(oldSize - 1);
+ ObjectValues::iterator itLast = value_.map_->find(keyLast);
+ value_.map_->erase(itLast);
+ return true;
+}
+
+#ifdef JSON_USE_CPPTL
+Value Value::get(const CppTL::ConstString &key, const Value &defaultValue) const
+{
+ return get(key.c_str(), key.end_c_str(), defaultValue);
+}
+#endif
+
+bool Value::isMember(char const *key, char const *cend) const
+{
+ Value const *value = find(key, cend);
+ return NULL != value;
+}
+bool Value::isMember(char const *key) const { return isMember(key, key + strlen(key)); }
+bool Value::isMember(JSONCPP_STRING const &key) const
+{
+ return isMember(key.data(), key.data() + key.length());
+}
+
+#ifdef JSON_USE_CPPTL
+bool Value::isMember(const CppTL::ConstString &key) const
+{
+ return isMember(key.c_str(), key.end_c_str());
+}
+#endif
+
+Value::Members Value::getMemberNames() const
+{
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+ "in Json::Value::getMemberNames(), value must be objectValue");
+ if (type_ == nullValue)
+ return Value::Members();
+ Members members;
+ members.reserve(value_.map_->size());
+ ObjectValues::const_iterator it = value_.map_->begin();
+ ObjectValues::const_iterator itEnd = value_.map_->end();
+ for (; it != itEnd; ++it)
+ {
+ members.push_back(JSONCPP_STRING((*it).first.data(), (*it).first.length()));
+ }
+ return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+// EnumMemberNames
+// Value::enumMemberNames() const
+//{
+// if ( type_ == objectValue )
+// {
+// return CppTL::Enum::any( CppTL::Enum::transform(
+// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
+// MemberNamesTransform() ) );
+// }
+// return EnumMemberNames();
+//}
+//
+//
+// EnumValues
+// Value::enumValues() const
+//{
+// if ( type_ == objectValue || type_ == arrayValue )
+// return CppTL::Enum::anyValues( *(value_.map_),
+// CppTL::Type<const Value &>() );
+// return EnumValues();
+//}
+//
+//# endif
+
+static bool IsIntegral(double d)
+{
+ double integral_part;
+ return modf(d, &integral_part) == 0.0;
+}
+
+bool Value::isNull() const { return type_ == nullValue; }
+
+bool Value::isBool() const { return type_ == booleanValue; }
+
+bool Value::isInt() const
+{
+ switch (type_)
+ {
+ case intValue:
+ return value_.int_ >= minInt && value_.int_ <= maxInt;
+ case uintValue:
+ return value_.uint_ <= UInt(maxInt);
+ case realValue:
+ return value_.real_ >= minInt && value_.real_ <= maxInt && IsIntegral(value_.real_);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool Value::isUInt() const
+{
+ switch (type_)
+ {
+ case intValue:
+ return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
+ case uintValue:
+ return value_.uint_ <= maxUInt;
+ case realValue:
+ return value_.real_ >= 0 && value_.real_ <= maxUInt && IsIntegral(value_.real_);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool Value::isInt64() const
+{
+#if defined(JSON_HAS_INT64)
+ switch (type_)
+ {
+ case intValue:
+ return true;
+ case uintValue:
+ return value_.uint_ <= UInt64(maxInt64);
+ case realValue:
+ // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+ // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+ // require the value to be strictly less than the limit.
+ return value_.real_ >= double(minInt64) && value_.real_ < double(maxInt64) &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+#endif // JSON_HAS_INT64
+ return false;
+}
+
+bool Value::isUInt64() const
+{
+#if defined(JSON_HAS_INT64)
+ switch (type_)
+ {
+ case intValue:
+ return value_.int_ >= 0;
+ case uintValue:
+ return true;
+ case realValue:
+ // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+ // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+ // require the value to be strictly less than the limit.
+ return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
+ default:
+ break;
+ }
+#endif // JSON_HAS_INT64
+ return false;
+}
+
+bool Value::isIntegral() const
+{
+#if defined(JSON_HAS_INT64)
+ return isInt64() || isUInt64();
+#else
+ return isInt() || isUInt();
+#endif
+}
+
+bool Value::isDouble() const { return type_ == realValue || isIntegral(); }
+
+bool Value::isNumeric() const { return isIntegral() || isDouble(); }
+
+bool Value::isString() const { return type_ == stringValue; }
+
+bool Value::isArray() const { return type_ == arrayValue; }
+
+bool Value::isObject() const { return type_ == objectValue; }
+
+void Value::setComment(const char *comment, size_t len, CommentPlacement placement)
+{
+ if (!comments_)
+ comments_ = new CommentInfo[numberOfCommentPlacement];
+ if ((len > 0) && (comment[len - 1] == '\n'))
+ {
+ // Always discard trailing newline, to aid indentation.
+ len -= 1;
+ }
+ comments_[placement].setComment(comment, len);
+}
+
+void Value::setComment(const char *comment, CommentPlacement placement)
+{
+ setComment(comment, strlen(comment), placement);
+}
+
+void Value::setComment(const JSONCPP_STRING &comment, CommentPlacement placement)
+{
+ setComment(comment.c_str(), comment.length(), placement);
+}
+
+bool Value::hasComment(CommentPlacement placement) const
+{
+ return comments_ != 0 && comments_[placement].comment_ != 0;
+}
+
+JSONCPP_STRING Value::getComment(CommentPlacement placement) const
+{
+ if (hasComment(placement))
+ return comments_[placement].comment_;
+ return "";
+}
+
+void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
+
+void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
+
+ptrdiff_t Value::getOffsetStart() const { return start_; }
+
+ptrdiff_t Value::getOffsetLimit() const { return limit_; }
+
+JSONCPP_STRING Value::toStyledString() const
+{
+ StyledWriter writer;
+ return writer.write(*this);
+}
+
+Value::const_iterator Value::begin() const
+{
+ switch (type_)
+ {
+ case arrayValue:
+ case objectValue:
+ if (value_.map_)
+ return const_iterator(value_.map_->begin());
+ break;
+ default:
+ break;
+ }
+ return const_iterator();
+}
+
+Value::const_iterator Value::end() const
+{
+ switch (type_)
+ {
+ case arrayValue:
+ case objectValue:
+ if (value_.map_)
+ return const_iterator(value_.map_->end());
+ break;
+ default:
+ break;
+ }
+ return const_iterator();
+}
+
+Value::iterator Value::begin()
+{
+ switch (type_)
+ {
+ case arrayValue:
+ case objectValue:
+ if (value_.map_)
+ return iterator(value_.map_->begin());
+ break;
+ default:
+ break;
+ }
+ return iterator();
+}
+
+Value::iterator Value::end()
+{
+ switch (type_)
+ {
+ case arrayValue:
+ case objectValue:
+ if (value_.map_)
+ return iterator(value_.map_->end());
+ break;
+ default:
+ break;
+ }
+ return iterator();
+}
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
+
+PathArgument::PathArgument(ArrayIndex index) : key_(), index_(index), kind_(kindIndex) {}
+
+PathArgument::PathArgument(const char *key) : key_(key), index_(), kind_(kindKey) {}
+
+PathArgument::PathArgument(const JSONCPP_STRING &key) : key_(key.c_str()), index_(), kind_(kindKey)
+{
+}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path(const JSONCPP_STRING &path, const PathArgument &a1, const PathArgument &a2,
+ const PathArgument &a3, const PathArgument &a4, const PathArgument &a5)
+{
+ InArgs in;
+ in.push_back(&a1);
+ in.push_back(&a2);
+ in.push_back(&a3);
+ in.push_back(&a4);
+ in.push_back(&a5);
+ makePath(path, in);
+}
+
+void Path::makePath(const JSONCPP_STRING &path, const InArgs &in)
+{
+ const char *current = path.c_str();
+ const char *end = current + path.length();
+ InArgs::const_iterator itInArg = in.begin();
+ while (current != end)
+ {
+ if (*current == '[')
+ {
+ ++current;
+ if (*current == '%')
+ addPathInArg(path, in, itInArg, PathArgument::kindIndex);
+ else
+ {
+ ArrayIndex index = 0;
+ for (; current != end && *current >= '0' && *current <= '9'; ++current)
+ index = index * 10 + ArrayIndex(*current - '0');
+ args_.push_back(index);
+ }
+ if (current == end || *++current != ']')
+ invalidPath(path, int(current - path.c_str()));
+ }
+ else if (*current == '%')
+ {
+ addPathInArg(path, in, itInArg, PathArgument::kindKey);
+ ++current;
+ }
+ else if (*current == '.' || *current == ']')
+ {
+ ++current;
+ }
+ else
+ {
+ const char *beginName = current;
+ while (current != end && !strchr("[.", *current))
+ ++current;
+ args_.push_back(JSONCPP_STRING(beginName, current));
+ }
+ }
+}
+
+void Path::addPathInArg(const JSONCPP_STRING & /*path*/, const InArgs &in,
+ InArgs::const_iterator &itInArg, PathArgument::Kind kind)
+{
+ if (itInArg == in.end())
+ {
+ // Error: missing argument %d
+ }
+ else if ((*itInArg)->kind_ != kind)
+ {
+ // Error: bad argument type
+ }
+ else
+ {
+ args_.push_back(**itInArg++);
+ }
+}
+
+void Path::invalidPath(const JSONCPP_STRING & /*path*/, int /*location*/)
+{
+ // Error: invalid path.
+}
+
+const Value &Path::resolve(const Value &root) const
+{
+ const Value *node = &root;
+ for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it)
+ {
+ const PathArgument &arg = *it;
+ if (arg.kind_ == PathArgument::kindIndex)
+ {
+ if (!node->isArray() || !node->isValidIndex(arg.index_))
+ {
+ // Error: unable to resolve path (array value expected at position...
+ return Value::null;
+ }
+ node = &((*node)[arg.index_]);
+ }
+ else if (arg.kind_ == PathArgument::kindKey)
+ {
+ if (!node->isObject())
+ {
+ // Error: unable to resolve path (object value expected at position...)
+ return Value::null;
+ }
+ node = &((*node)[arg.key_]);
+ if (node == &Value::nullSingleton())
+ {
+ // Error: unable to resolve path (object has no member named '' at
+ // position...)
+ return Value::null;
+ }
+ }
+ }
+ return *node;
+}
+
+Value Path::resolve(const Value &root, const Value &defaultValue) const
+{
+ const Value *node = &root;
+ for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it)
+ {
+ const PathArgument &arg = *it;
+ if (arg.kind_ == PathArgument::kindIndex)
+ {
+ if (!node->isArray() || !node->isValidIndex(arg.index_))
+ return defaultValue;
+ node = &((*node)[arg.index_]);
+ }
+ else if (arg.kind_ == PathArgument::kindKey)
+ {
+ if (!node->isObject())
+ return defaultValue;
+ node = &((*node)[arg.key_]);
+ if (node == &Value::nullSingleton())
+ return defaultValue;
+ }
+ }
+ return *node;
+}
+
+Value &Path::make(Value &root) const
+{
+ Value *node = &root;
+ for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it)
+ {
+ const PathArgument &arg = *it;
+ if (arg.kind_ == PathArgument::kindIndex)
+ {
+ if (!node->isArray())
+ {
+ // Error: node is not an array at position ...
+ }
+ node = &((*node)[arg.index_]);
+ }
+ else if (arg.kind_ == PathArgument::kindKey)
+ {
+ if (!node->isObject())
+ {
+ // Error: node is not an object at position...
+ }
+ node = &((*node)[arg.key_]);
+ }
+ }
+ return *node;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_value.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_writer.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/writer.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <iomanip>
+#include <memory>
+#include <sstream>
+#include <utility>
+#include <set>
+#include <cassert>
+#include <cstring>
+#include <cstdio>
+
+#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
+#include <float.h>
+#define isfinite _finite
+#elif defined(__sun) && defined(__SVR4) // Solaris
+#if !defined(isfinite)
+#include <ieeefp.h>
+#define isfinite finite
+#endif
+#elif defined(_AIX)
+#if !defined(isfinite)
+#include <math.h>
+#define isfinite finite
+#endif
+#elif defined(__hpux)
+#if !defined(isfinite)
+#if defined(__ia64) && !defined(finite)
+#define isfinite(x) ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
+#else
+#include <math.h>
+#define isfinite finite
+#endif
+#endif
+#else
+#include <cmath>
+#if !(defined(__QNXNTO__)) // QNX already defines isfinite
+#define isfinite std::isfinite
+#endif
+#endif
+
+#if defined(_MSC_VER)
+#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
+#define snprintf sprintf_s
+#elif _MSC_VER >= 1900 // VC++ 14.0 and above
+#define snprintf std::snprintf
+#else
+#define snprintf _snprintf
+#endif
+#elif defined(__ANDROID__) || defined(__QNXNTO__)
+#define snprintf snprintf
+#elif __cplusplus >= 201103L
+#if !defined(__MINGW32__) && !defined(__CYGWIN__)
+#define snprintf std::snprintf
+#endif
+#endif
+
+#if defined(__BORLANDC__)
+#include <float.h>
+#define isfinite _finite
+#define snprintf _snprintf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+namespace Json
+{
+
+#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
+typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
+#else
+typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
+#endif
+
+static bool containsControlCharacter(const char *str)
+{
+ while (*str)
+ {
+ if (isControlCharacter(*(str++)))
+ return true;
+ }
+ return false;
+}
+
+static bool containsControlCharacter0(const char *str, unsigned len)
+{
+ char const *end = str + len;
+ while (end != str)
+ {
+ if (isControlCharacter(*str) || 0 == *str)
+ return true;
+ ++str;
+ }
+ return false;
+}
+
+JSONCPP_STRING valueToString(LargestInt value)
+{
+ UIntToStringBuffer buffer;
+ char *current = buffer + sizeof(buffer);
+ if (value == Value::minLargestInt)
+ {
+ uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
+ *--current = '-';
+ }
+ else if (value < 0)
+ {
+ uintToString(LargestUInt(-value), current);
+ *--current = '-';
+ }
+ else
+ {
+ uintToString(LargestUInt(value), current);
+ }
+ assert(current >= buffer);
+ return current;
+}
+
+JSONCPP_STRING valueToString(LargestUInt value)
+{
+ UIntToStringBuffer buffer;
+ char *current = buffer + sizeof(buffer);
+ uintToString(value, current);
+ assert(current >= buffer);
+ return current;
+}
+
+#if defined(JSON_HAS_INT64)
+
+JSONCPP_STRING valueToString(Int value) { return valueToString(LargestInt(value)); }
+
+JSONCPP_STRING valueToString(UInt value) { return valueToString(LargestUInt(value)); }
+
+#endif // # if defined(JSON_HAS_INT64)
+
+namespace
+{
+JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision)
+{
+ // Allocate a buffer that is more than large enough to store the 16 digits of
+ // precision requested below.
+ char buffer[32];
+ int len = -1;
+
+ char formatString[6];
+ sprintf(formatString, "%%.%dg", precision);
+
+ // Print into the buffer. We need not request the alternative representation
+ // that always has a decimal point because JSON doesn't distingish the
+ // concepts of reals and integers.
+ if (isfinite(value))
+ {
+ len = snprintf(buffer, sizeof(buffer), formatString, value);
+ }
+ else
+ {
+ // IEEE standard states that NaN values will not compare to themselves
+ if (value != value)
+ {
+ len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
+ }
+ else if (value < 0)
+ {
+ len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
+ }
+ else
+ {
+ len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
+ }
+ // For those, we do not need to call fixNumLoc, but it is fast.
+ }
+ assert(len >= 0);
+ fixNumericLocale(buffer, buffer + len);
+ return buffer;
+}
+}
+
+JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
+
+JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
+
+JSONCPP_STRING valueToQuotedString(const char *value)
+{
+ if (value == NULL)
+ return "";
+ // Not sure how to handle unicode...
+ if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter(value))
+ return JSONCPP_STRING("\"") + value + "\"";
+ // We have to walk value and escape any special characters.
+ // Appending to JSONCPP_STRING is not efficient, but this should be rare.
+ // (Note: forward slashes are *not* rare, but I am not escaping them.)
+ JSONCPP_STRING::size_type maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL
+ JSONCPP_STRING result;
+ result.reserve(maxsize); // to avoid lots of mallocs
+ result += "\"";
+ for (const char *c = value; *c != 0; ++c)
+ {
+ switch (*c)
+ {
+ case '\"':
+ result += "\\\"";
+ break;
+ case '\\':
+ result += "\\\\";
+ break;
+ case '\b':
+ result += "\\b";
+ break;
+ case '\f':
+ result += "\\f";
+ break;
+ case '\n':
+ result += "\\n";
+ break;
+ case '\r':
+ result += "\\r";
+ break;
+ case '\t':
+ result += "\\t";
+ break;
+ // case '/':
+ // Even though \/ is considered a legal escape in JSON, a bare
+ // slash is also legal, so I see no reason to escape it.
+ // (I hope I am not misunderstanding something.
+ // blep notes: actually escaping \/ may be useful in javascript to avoid </
+ // sequence.
+ // Should add a flag to allow this compatibility mode and prevent this
+ // sequence from occurring.
+ default:
+ if (isControlCharacter(*c))
+ {
+ JSONCPP_OSTRINGSTREAM oss;
+ oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4)
+ << static_cast<int>(*c);
+ result += oss.str();
+ }
+ else
+ {
+ result += *c;
+ }
+ break;
+ }
+ }
+ result += "\"";
+ return result;
+}
+
+// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
+static char const *strnpbrk(char const *s, char const *accept, size_t n)
+{
+ assert((s || !n) && accept);
+
+ char const *const end = s + n;
+ for (char const *cur = s; cur < end; ++cur)
+ {
+ int const c = *cur;
+ for (char const *a = accept; *a; ++a)
+ {
+ if (*a == c)
+ {
+ return cur;
+ }
+ }
+ }
+ return NULL;
+}
+static JSONCPP_STRING valueToQuotedStringN(const char *value, unsigned length)
+{
+ if (value == NULL)
+ return "";
+ // Not sure how to handle unicode...
+ if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
+ !containsControlCharacter0(value, length))
+ return JSONCPP_STRING("\"") + value + "\"";
+ // We have to walk value and escape any special characters.
+ // Appending to JSONCPP_STRING is not efficient, but this should be rare.
+ // (Note: forward slashes are *not* rare, but I am not escaping them.)
+ JSONCPP_STRING::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL
+ JSONCPP_STRING result;
+ result.reserve(maxsize); // to avoid lots of mallocs
+ result += "\"";
+ char const *end = value + length;
+ for (const char *c = value; c != end; ++c)
+ {
+ switch (*c)
+ {
+ case '\"':
+ result += "\\\"";
+ break;
+ case '\\':
+ result += "\\\\";
+ break;
+ case '\b':
+ result += "\\b";
+ break;
+ case '\f':
+ result += "\\f";
+ break;
+ case '\n':
+ result += "\\n";
+ break;
+ case '\r':
+ result += "\\r";
+ break;
+ case '\t':
+ result += "\\t";
+ break;
+ // case '/':
+ // Even though \/ is considered a legal escape in JSON, a bare
+ // slash is also legal, so I see no reason to escape it.
+ // (I hope I am not misunderstanding something.)
+ // blep notes: actually escaping \/ may be useful in javascript to avoid </
+ // sequence.
+ // Should add a flag to allow this compatibility mode and prevent this
+ // sequence from occurring.
+ default:
+ if ((isControlCharacter(*c)) || (*c == 0))
+ {
+ JSONCPP_OSTRINGSTREAM oss;
+ oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4)
+ << static_cast<int>(*c);
+ result += oss.str();
+ }
+ else
+ {
+ result += *c;
+ }
+ break;
+ }
+ }
+ result += "\"";
+ return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer() {}
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+ : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), omitEndingLineFeed_(false)
+{
+}
+
+void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
+
+void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
+
+void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
+
+JSONCPP_STRING FastWriter::write(const Value &root)
+{
+ document_ = "";
+ writeValue(root);
+ if (!omitEndingLineFeed_)
+ document_ += "\n";
+ return document_;
+}
+
+void FastWriter::writeValue(const Value &value)
+{
+ switch (value.type())
+ {
+ case nullValue:
+ if (!dropNullPlaceholders_)
+ document_ += "null";
+ break;
+ case intValue:
+ document_ += valueToString(value.asLargestInt());
+ break;
+ case uintValue:
+ document_ += valueToString(value.asLargestUInt());
+ break;
+ case realValue:
+ document_ += valueToString(value.asDouble());
+ break;
+ case stringValue:
+ {
+ // Is NULL possible for value.string_? No.
+ char const *str;
+ char const *end;
+ bool ok = value.getString(&str, &end);
+ if (ok)
+ document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
+ break;
+ }
+ case booleanValue:
+ document_ += valueToString(value.asBool());
+ break;
+ case arrayValue:
+ {
+ document_ += '[';
+ ArrayIndex size = value.size();
+ for (ArrayIndex index = 0; index < size; ++index)
+ {
+ if (index > 0)
+ document_ += ',';
+ writeValue(value[index]);
+ }
+ document_ += ']';
+ }
+ break;
+ case objectValue:
+ {
+ Value::Members members(value.getMemberNames());
+ document_ += '{';
+ for (Value::Members::iterator it = members.begin(); it != members.end(); ++it)
+ {
+ const JSONCPP_STRING &name = *it;
+ if (it != members.begin())
+ document_ += ',';
+ document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
+ document_ += yamlCompatiblityEnabled_ ? ": " : ":";
+ writeValue(value[name]);
+ }
+ document_ += '}';
+ }
+ break;
+ }
+}
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3), addChildValues_() {}
+
+JSONCPP_STRING StyledWriter::write(const Value &root)
+{
+ document_ = "";
+ addChildValues_ = false;
+ indentString_ = "";
+ writeCommentBeforeValue(root);
+ writeValue(root);
+ writeCommentAfterValueOnSameLine(root);
+ document_ += "\n";
+ return document_;
+}
+
+void StyledWriter::writeValue(const Value &value)
+{
+ switch (value.type())
+ {
+ case nullValue:
+ pushValue("null");
+ break;
+ case intValue:
+ pushValue(valueToString(value.asLargestInt()));
+ break;
+ case uintValue:
+ pushValue(valueToString(value.asLargestUInt()));
+ break;
+ case realValue:
+ pushValue(valueToString(value.asDouble()));
+ break;
+ case stringValue:
+ {
+ // Is NULL possible for value.string_? No.
+ char const *str;
+ char const *end;
+ bool ok = value.getString(&str, &end);
+ if (ok)
+ pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+ else
+ pushValue("");
+ break;
+ }
+ case booleanValue:
+ pushValue(valueToString(value.asBool()));
+ break;
+ case arrayValue:
+ writeArrayValue(value);
+ break;
+ case objectValue:
+ {
+ Value::Members members(value.getMemberNames());
+ if (members.empty())
+ pushValue("{}");
+ else
+ {
+ writeWithIndent("{");
+ indent();
+ Value::Members::iterator it = members.begin();
+ for (;;)
+ {
+ const JSONCPP_STRING &name = *it;
+ const Value &childValue = value[name];
+ writeCommentBeforeValue(childValue);
+ writeWithIndent(valueToQuotedString(name.c_str()));
+ document_ += " : ";
+ writeValue(childValue);
+ if (++it == members.end())
+ {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ document_ += ',';
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("}");
+ }
+ }
+ break;
+ }
+}
+
+void StyledWriter::writeArrayValue(const Value &value)
+{
+ unsigned size = value.size();
+ if (size == 0)
+ pushValue("[]");
+ else
+ {
+ bool isArrayMultiLine = isMultineArray(value);
+ if (isArrayMultiLine)
+ {
+ writeWithIndent("[");
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index = 0;
+ for (;;)
+ {
+ const Value &childValue = value[index];
+ writeCommentBeforeValue(childValue);
+ if (hasChildValue)
+ writeWithIndent(childValues_[index]);
+ else
+ {
+ writeIndent();
+ writeValue(childValue);
+ }
+ if (++index == size)
+ {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ document_ += ',';
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("]");
+ }
+ else // output on a single line
+ {
+ assert(childValues_.size() == size);
+ document_ += "[ ";
+ for (unsigned index = 0; index < size; ++index)
+ {
+ if (index > 0)
+ document_ += ", ";
+ document_ += childValues_[index];
+ }
+ document_ += " ]";
+ }
+ }
+}
+
+bool StyledWriter::isMultineArray(const Value &value)
+{
+ ArrayIndex const size = value.size();
+ bool isMultiLine = size * 3 >= rightMargin_;
+ childValues_.clear();
+ for (ArrayIndex index = 0; index < size && !isMultiLine; ++index)
+ {
+ const Value &childValue = value[index];
+ isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0);
+ }
+ if (!isMultiLine) // check if line length > max line length
+ {
+ childValues_.reserve(size);
+ addChildValues_ = true;
+ ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+ for (ArrayIndex index = 0; index < size; ++index)
+ {
+ if (hasCommentForValue(value[index]))
+ {
+ isMultiLine = true;
+ }
+ writeValue(value[index]);
+ lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+ }
+ addChildValues_ = false;
+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
+ }
+ return isMultiLine;
+}
+
+void StyledWriter::pushValue(const JSONCPP_STRING &value)
+{
+ if (addChildValues_)
+ childValues_.push_back(value);
+ else
+ document_ += value;
+}
+
+void StyledWriter::writeIndent()
+{
+ if (!document_.empty())
+ {
+ char last = document_[document_.length() - 1];
+ if (last == ' ') // already indented
+ return;
+ if (last != '\n') // Comments may add new-line
+ document_ += '\n';
+ }
+ document_ += indentString_;
+}
+
+void StyledWriter::writeWithIndent(const JSONCPP_STRING &value)
+{
+ writeIndent();
+ document_ += value;
+}
+
+void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }
+
+void StyledWriter::unindent()
+{
+ assert(indentString_.size() >= indentSize_);
+ indentString_.resize(indentString_.size() - indentSize_);
+}
+
+void StyledWriter::writeCommentBeforeValue(const Value &root)
+{
+ if (!root.hasComment(commentBefore))
+ return;
+
+ document_ += "\n";
+ writeIndent();
+ const JSONCPP_STRING &comment = root.getComment(commentBefore);
+ JSONCPP_STRING::const_iterator iter = comment.begin();
+ while (iter != comment.end())
+ {
+ document_ += *iter;
+ if (*iter == '\n' && (iter != comment.end() && *(iter + 1) == '/'))
+ writeIndent();
+ ++iter;
+ }
+
+ // Comments are stripped of trailing newlines, so add one here
+ document_ += "\n";
+}
+
+void StyledWriter::writeCommentAfterValueOnSameLine(const Value &root)
+{
+ if (root.hasComment(commentAfterOnSameLine))
+ document_ += " " + root.getComment(commentAfterOnSameLine);
+
+ if (root.hasComment(commentAfter))
+ {
+ document_ += "\n";
+ document_ += root.getComment(commentAfter);
+ document_ += "\n";
+ }
+}
+
+bool StyledWriter::hasCommentForValue(const Value &value)
+{
+ return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) ||
+ value.hasComment(commentAfter);
+}
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)
+ : document_(NULL), rightMargin_(74), indentation_(indentation), addChildValues_()
+{
+}
+
+void StyledStreamWriter::write(JSONCPP_OSTREAM &out, const Value &root)
+{
+ document_ = &out;
+ addChildValues_ = false;
+ indentString_ = "";
+ indented_ = true;
+ writeCommentBeforeValue(root);
+ if (!indented_)
+ writeIndent();
+ indented_ = true;
+ writeValue(root);
+ writeCommentAfterValueOnSameLine(root);
+ *document_ << "\n";
+ document_ = NULL; // Forget the stream, for safety.
+}
+
+void StyledStreamWriter::writeValue(const Value &value)
+{
+ switch (value.type())
+ {
+ case nullValue:
+ pushValue("null");
+ break;
+ case intValue:
+ pushValue(valueToString(value.asLargestInt()));
+ break;
+ case uintValue:
+ pushValue(valueToString(value.asLargestUInt()));
+ break;
+ case realValue:
+ pushValue(valueToString(value.asDouble()));
+ break;
+ case stringValue:
+ {
+ // Is NULL possible for value.string_? No.
+ char const *str;
+ char const *end;
+ bool ok = value.getString(&str, &end);
+ if (ok)
+ pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+ else
+ pushValue("");
+ break;
+ }
+ case booleanValue:
+ pushValue(valueToString(value.asBool()));
+ break;
+ case arrayValue:
+ writeArrayValue(value);
+ break;
+ case objectValue:
+ {
+ Value::Members members(value.getMemberNames());
+ if (members.empty())
+ pushValue("{}");
+ else
+ {
+ writeWithIndent("{");
+ indent();
+ Value::Members::iterator it = members.begin();
+ for (;;)
+ {
+ const JSONCPP_STRING &name = *it;
+ const Value &childValue = value[name];
+ writeCommentBeforeValue(childValue);
+ writeWithIndent(valueToQuotedString(name.c_str()));
+ *document_ << " : ";
+ writeValue(childValue);
+ if (++it == members.end())
+ {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ *document_ << ",";
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("}");
+ }
+ }
+ break;
+ }
+}
+
+void StyledStreamWriter::writeArrayValue(const Value &value)
+{
+ unsigned size = value.size();
+ if (size == 0)
+ pushValue("[]");
+ else
+ {
+ bool isArrayMultiLine = isMultineArray(value);
+ if (isArrayMultiLine)
+ {
+ writeWithIndent("[");
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index = 0;
+ for (;;)
+ {
+ const Value &childValue = value[index];
+ writeCommentBeforeValue(childValue);
+ if (hasChildValue)
+ writeWithIndent(childValues_[index]);
+ else
+ {
+ if (!indented_)
+ writeIndent();
+ indented_ = true;
+ writeValue(childValue);
+ indented_ = false;
+ }
+ if (++index == size)
+ {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ *document_ << ",";
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("]");
+ }
+ else // output on a single line
+ {
+ assert(childValues_.size() == size);
+ *document_ << "[ ";
+ for (unsigned index = 0; index < size; ++index)
+ {
+ if (index > 0)
+ *document_ << ", ";
+ *document_ << childValues_[index];
+ }
+ *document_ << " ]";
+ }
+ }
+}
+
+bool StyledStreamWriter::isMultineArray(const Value &value)
+{
+ ArrayIndex const size = value.size();
+ bool isMultiLine = size * 3 >= rightMargin_;
+ childValues_.clear();
+ for (ArrayIndex index = 0; index < size && !isMultiLine; ++index)
+ {
+ const Value &childValue = value[index];
+ isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0);
+ }
+ if (!isMultiLine) // check if line length > max line length
+ {
+ childValues_.reserve(size);
+ addChildValues_ = true;
+ ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+ for (ArrayIndex index = 0; index < size; ++index)
+ {
+ if (hasCommentForValue(value[index]))
+ {
+ isMultiLine = true;
+ }
+ writeValue(value[index]);
+ lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+ }
+ addChildValues_ = false;
+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
+ }
+ return isMultiLine;
+}
+
+void StyledStreamWriter::pushValue(const JSONCPP_STRING &value)
+{
+ if (addChildValues_)
+ childValues_.push_back(value);
+ else
+ *document_ << value;
+}
+
+void StyledStreamWriter::writeIndent()
+{
+ // blep intended this to look at the so-far-written string
+ // to determine whether we are already indented, but
+ // with a stream we cannot do that. So we rely on some saved state.
+ // The caller checks indented_.
+ *document_ << '\n' << indentString_;
+}
+
+void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING &value)
+{
+ if (!indented_)
+ writeIndent();
+ *document_ << value;
+ indented_ = false;
+}
+
+void StyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void StyledStreamWriter::unindent()
+{
+ assert(indentString_.size() >= indentation_.size());
+ indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void StyledStreamWriter::writeCommentBeforeValue(const Value &root)
+{
+ if (!root.hasComment(commentBefore))
+ return;
+
+ if (!indented_)
+ writeIndent();
+ const JSONCPP_STRING &comment = root.getComment(commentBefore);
+ JSONCPP_STRING::const_iterator iter = comment.begin();
+ while (iter != comment.end())
+ {
+ *document_ << *iter;
+ if (*iter == '\n' && (iter != comment.end() && *(iter + 1) == '/'))
+ // writeIndent(); // would include newline
+ *document_ << indentString_;
+ ++iter;
+ }
+ indented_ = false;
+}
+
+void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value &root)
+{
+ if (root.hasComment(commentAfterOnSameLine))
+ *document_ << ' ' << root.getComment(commentAfterOnSameLine);
+
+ if (root.hasComment(commentAfter))
+ {
+ writeIndent();
+ *document_ << root.getComment(commentAfter);
+ }
+ indented_ = false;
+}
+
+bool StyledStreamWriter::hasCommentForValue(const Value &value)
+{
+ return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) ||
+ value.hasComment(commentAfter);
+}
+
+//////////////////////////
+// BuiltStyledStreamWriter
+
+/// Scoped enums are not available until C++11.
+struct CommentStyle
+{
+ /// Decide whether to write comments.
+ enum Enum
+ {
+ None, ///< Drop all comments.
+ Most, ///< Recover odd behavior of previous versions (not implemented yet).
+ All ///< Keep all comments.
+ };
+};
+
+struct BuiltStyledStreamWriter : public StreamWriter
+{
+ BuiltStyledStreamWriter(JSONCPP_STRING const &indentation, CommentStyle::Enum cs,
+ JSONCPP_STRING const &colonSymbol, JSONCPP_STRING const &nullSymbol,
+ JSONCPP_STRING const &endingLineFeedSymbol, bool useSpecialFloats,
+ unsigned int precision);
+ int write(Value const &root, JSONCPP_OSTREAM *sout) JSONCPP_OVERRIDE;
+
+private:
+ void writeValue(Value const &value);
+ void writeArrayValue(Value const &value);
+ bool isMultineArray(Value const &value);
+ void pushValue(JSONCPP_STRING const &value);
+ void writeIndent();
+ void writeWithIndent(JSONCPP_STRING const &value);
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue(Value const &root);
+ void writeCommentAfterValueOnSameLine(Value const &root);
+ static bool hasCommentForValue(const Value &value);
+
+ typedef std::vector<JSONCPP_STRING> ChildValues;
+
+ ChildValues childValues_;
+ JSONCPP_STRING indentString_;
+ unsigned int rightMargin_;
+ JSONCPP_STRING indentation_;
+ CommentStyle::Enum cs_;
+ JSONCPP_STRING colonSymbol_;
+ JSONCPP_STRING nullSymbol_;
+ JSONCPP_STRING endingLineFeedSymbol_;
+ bool addChildValues_ : 1;
+ bool indented_ : 1;
+ bool useSpecialFloats_ : 1;
+ unsigned int precision_;
+};
+BuiltStyledStreamWriter::BuiltStyledStreamWriter(JSONCPP_STRING const &indentation,
+ CommentStyle::Enum cs,
+ JSONCPP_STRING const &colonSymbol,
+ JSONCPP_STRING const &nullSymbol,
+ JSONCPP_STRING const &endingLineFeedSymbol,
+ bool useSpecialFloats, unsigned int precision)
+ : rightMargin_(74), indentation_(indentation), cs_(cs), colonSymbol_(colonSymbol),
+ nullSymbol_(nullSymbol), endingLineFeedSymbol_(endingLineFeedSymbol), addChildValues_(false),
+ indented_(false), useSpecialFloats_(useSpecialFloats), precision_(precision)
+{
+}
+int BuiltStyledStreamWriter::write(Value const &root, JSONCPP_OSTREAM *sout)
+{
+ sout_ = sout;
+ addChildValues_ = false;
+ indented_ = true;
+ indentString_ = "";
+ writeCommentBeforeValue(root);
+ if (!indented_)
+ writeIndent();
+ indented_ = true;
+ writeValue(root);
+ writeCommentAfterValueOnSameLine(root);
+ *sout_ << endingLineFeedSymbol_;
+ sout_ = NULL;
+ return 0;
+}
+void BuiltStyledStreamWriter::writeValue(Value const &value)
+{
+ switch (value.type())
+ {
+ case nullValue:
+ pushValue(nullSymbol_);
+ break;
+ case intValue:
+ pushValue(valueToString(value.asLargestInt()));
+ break;
+ case uintValue:
+ pushValue(valueToString(value.asLargestUInt()));
+ break;
+ case realValue:
+ pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
+ break;
+ case stringValue:
+ {
+ // Is NULL is possible for value.string_? No.
+ char const *str;
+ char const *end;
+ bool ok = value.getString(&str, &end);
+ if (ok)
+ pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+ else
+ pushValue("");
+ break;
+ }
+ case booleanValue:
+ pushValue(valueToString(value.asBool()));
+ break;
+ case arrayValue:
+ writeArrayValue(value);
+ break;
+ case objectValue:
+ {
+ Value::Members members(value.getMemberNames());
+ if (members.empty())
+ pushValue("{}");
+ else
+ {
+ writeWithIndent("{");
+ indent();
+ Value::Members::iterator it = members.begin();
+ for (;;)
+ {
+ JSONCPP_STRING const &name = *it;
+ Value const &childValue = value[name];
+ writeCommentBeforeValue(childValue);
+ writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
+ *sout_ << colonSymbol_;
+ writeValue(childValue);
+ if (++it == members.end())
+ {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ *sout_ << ",";
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("}");
+ }
+ }
+ break;
+ }
+}
+
+void BuiltStyledStreamWriter::writeArrayValue(Value const &value)
+{
+ unsigned size = value.size();
+ if (size == 0)
+ pushValue("[]");
+ else
+ {
+ bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
+ if (isMultiLine)
+ {
+ writeWithIndent("[");
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index = 0;
+ for (;;)
+ {
+ Value const &childValue = value[index];
+ writeCommentBeforeValue(childValue);
+ if (hasChildValue)
+ writeWithIndent(childValues_[index]);
+ else
+ {
+ if (!indented_)
+ writeIndent();
+ indented_ = true;
+ writeValue(childValue);
+ indented_ = false;
+ }
+ if (++index == size)
+ {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ *sout_ << ",";
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("]");
+ }
+ else // output on a single line
+ {
+ assert(childValues_.size() == size);
+ *sout_ << "[";
+ if (!indentation_.empty())
+ *sout_ << " ";
+ for (unsigned index = 0; index < size; ++index)
+ {
+ if (index > 0)
+ *sout_ << ((!indentation_.empty()) ? ", " : ",");
+ *sout_ << childValues_[index];
+ }
+ if (!indentation_.empty())
+ *sout_ << " ";
+ *sout_ << "]";
+ }
+ }
+}
+
+bool BuiltStyledStreamWriter::isMultineArray(Value const &value)
+{
+ ArrayIndex const size = value.size();
+ bool isMultiLine = size * 3 >= rightMargin_;
+ childValues_.clear();
+ for (ArrayIndex index = 0; index < size && !isMultiLine; ++index)
+ {
+ Value const &childValue = value[index];
+ isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0);
+ }
+ if (!isMultiLine) // check if line length > max line length
+ {
+ childValues_.reserve(size);
+ addChildValues_ = true;
+ ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+ for (ArrayIndex index = 0; index < size; ++index)
+ {
+ if (hasCommentForValue(value[index]))
+ {
+ isMultiLine = true;
+ }
+ writeValue(value[index]);
+ lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+ }
+ addChildValues_ = false;
+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
+ }
+ return isMultiLine;
+}
+
+void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const &value)
+{
+ if (addChildValues_)
+ childValues_.push_back(value);
+ else
+ *sout_ << value;
+}
+
+void BuiltStyledStreamWriter::writeIndent()
+{
+ // blep intended this to look at the so-far-written string
+ // to determine whether we are already indented, but
+ // with a stream we cannot do that. So we rely on some saved state.
+ // The caller checks indented_.
+
+ if (!indentation_.empty())
+ {
+ // In this case, drop newlines too.
+ *sout_ << '\n' << indentString_;
+ }
+}
+
+void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const &value)
+{
+ if (!indented_)
+ writeIndent();
+ *sout_ << value;
+ indented_ = false;
+}
+
+void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void BuiltStyledStreamWriter::unindent()
+{
+ assert(indentString_.size() >= indentation_.size());
+ indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const &root)
+{
+ if (cs_ == CommentStyle::None)
+ return;
+ if (!root.hasComment(commentBefore))
+ return;
+
+ if (!indented_)
+ writeIndent();
+ const JSONCPP_STRING &comment = root.getComment(commentBefore);
+ JSONCPP_STRING::const_iterator iter = comment.begin();
+ while (iter != comment.end())
+ {
+ *sout_ << *iter;
+ if (*iter == '\n' && (iter != comment.end() && *(iter + 1) == '/'))
+ // writeIndent(); // would write extra newline
+ *sout_ << indentString_;
+ ++iter;
+ }
+ indented_ = false;
+}
+
+void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const &root)
+{
+ if (cs_ == CommentStyle::None)
+ return;
+ if (root.hasComment(commentAfterOnSameLine))
+ *sout_ << " " + root.getComment(commentAfterOnSameLine);
+
+ if (root.hasComment(commentAfter))
+ {
+ writeIndent();
+ *sout_ << root.getComment(commentAfter);
+ }
+}
+
+// static
+bool BuiltStyledStreamWriter::hasCommentForValue(const Value &value)
+{
+ return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) ||
+ value.hasComment(commentAfter);
+}
+
+///////////////
+// StreamWriter
+
+StreamWriter::StreamWriter() : sout_(NULL) {}
+StreamWriter::~StreamWriter() {}
+StreamWriter::Factory::~Factory() {}
+StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
+StreamWriterBuilder::~StreamWriterBuilder() {}
+StreamWriter *StreamWriterBuilder::newStreamWriter() const
+{
+ JSONCPP_STRING indentation = settings_["indentation"].asString();
+ JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
+ bool eyc = settings_["enableYAMLCompatibility"].asBool();
+ bool dnp = settings_["dropNullPlaceholders"].asBool();
+ bool usf = settings_["useSpecialFloats"].asBool();
+ unsigned int pre = settings_["precision"].asUInt();
+ CommentStyle::Enum cs = CommentStyle::All;
+ if (cs_str == "All")
+ {
+ cs = CommentStyle::All;
+ }
+ else if (cs_str == "None")
+ {
+ cs = CommentStyle::None;
+ }
+ else
+ {
+ throwRuntimeError("commentStyle must be 'All' or 'None'");
+ }
+ JSONCPP_STRING colonSymbol = " : ";
+ if (eyc)
+ {
+ colonSymbol = ": ";
+ }
+ else if (indentation.empty())
+ {
+ colonSymbol = ":";
+ }
+ JSONCPP_STRING nullSymbol = "null";
+ if (dnp)
+ {
+ nullSymbol = "";
+ }
+ if (pre > 17)
+ pre = 17;
+ JSONCPP_STRING endingLineFeedSymbol = "";
+ return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, endingLineFeedSymbol,
+ usf, pre);
+}
+static void getValidWriterKeys(std::set<JSONCPP_STRING> *valid_keys)
+{
+ valid_keys->clear();
+ valid_keys->insert("indentation");
+ valid_keys->insert("commentStyle");
+ valid_keys->insert("enableYAMLCompatibility");
+ valid_keys->insert("dropNullPlaceholders");
+ valid_keys->insert("useSpecialFloats");
+ valid_keys->insert("precision");
+}
+bool StreamWriterBuilder::validate(Json::Value *invalid) const
+{
+ Json::Value my_invalid;
+ if (!invalid)
+ invalid = &my_invalid; // so we do not need to test for NULL
+ Json::Value &inv = *invalid;
+ std::set<JSONCPP_STRING> valid_keys;
+ getValidWriterKeys(&valid_keys);
+ Value::Members keys = settings_.getMemberNames();
+ size_t n = keys.size();
+ for (size_t i = 0; i < n; ++i)
+ {
+ JSONCPP_STRING const &key = keys[i];
+ if (valid_keys.find(key) == valid_keys.end())
+ {
+ inv[key] = settings_[key];
+ }
+ }
+ return 0u == inv.size();
+}
+Value &StreamWriterBuilder::operator[](JSONCPP_STRING key) { return settings_[key]; }
+// static
+void StreamWriterBuilder::setDefaults(Json::Value *settings)
+{
+ //! [StreamWriterBuilderDefaults]
+ (*settings)["commentStyle"] = "All";
+ (*settings)["indentation"] = "\t";
+ (*settings)["enableYAMLCompatibility"] = false;
+ (*settings)["dropNullPlaceholders"] = false;
+ (*settings)["useSpecialFloats"] = false;
+ (*settings)["precision"] = 17;
+ //! [StreamWriterBuilderDefaults]
+}
+
+JSONCPP_STRING writeString(StreamWriter::Factory const &builder, Value const &root)
+{
+ JSONCPP_OSTRINGSTREAM sout;
+ StreamWriterPtr const writer(builder.newStreamWriter());
+ writer->write(root, &sout);
+ return sout.str();
+}
+
+JSONCPP_OSTREAM &operator<<(JSONCPP_OSTREAM &sout, Value const &root)
+{
+ StreamWriterBuilder builder;
+ StreamWriterPtr const writer(builder.newStreamWriter());
+ writer->write(root, &sout);
+ return sout;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_writer.cpp
+// //////////////////////////////////////////////////////////////////////
diff --git a/runtime/3rdparty/lcov-to-cobertura-xml/README.md b/runtime/3rdparty/lcov-to-cobertura-xml/README.md
new file mode 100644
index 000000000..2fc4cff42
--- /dev/null
+++ b/runtime/3rdparty/lcov-to-cobertura-xml/README.md
@@ -0,0 +1,5 @@
+# lcov to cobertura XML converter
+
+lcov to cobertura XML converter is imported from
+
+https://github.com/eriwen/lcov-to-cobertura-xml
diff --git a/runtime/3rdparty/lcov-to-cobertura-xml/lcov_cobertura.py b/runtime/3rdparty/lcov-to-cobertura-xml/lcov_cobertura.py
new file mode 100755
index 000000000..7aae6d115
--- /dev/null
+++ b/runtime/3rdparty/lcov-to-cobertura-xml/lcov_cobertura.py
@@ -0,0 +1,414 @@
+#!/usr/bin/env python
+
+# Copyright 2011-2012 Eric Wendelin
+#
+# This is free software, licensed under the Apache License, Version 2.0,
+# available in the accompanying LICENSE.txt file.
+
+"""
+Converts lcov line coverage output to Cobertura-compatible XML for CI
+"""
+
+import re
+import sys
+import os
+import time
+import subprocess
+from xml.dom import minidom
+from optparse import OptionParser
+
+from distutils.spawn import find_executable
+
+CPPFILT = "c++filt"
+HAVE_CPPFILT = False
+
+if find_executable(CPPFILT) is not None:
+ HAVE_CPPFILT = True
+
+VERSION = '1.6'
+__all__ = ['LcovCobertura']
+
+
+class Demangler(object):
+ def __init__(self):
+ self.pipe = subprocess.Popen(
+ CPPFILT, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+ def demangle(self, name):
+ self.pipe.stdin.write(name + "\n")
+ return self.pipe.stdout.readline().rstrip()
+
+
+class LcovCobertura(object):
+ """
+ Converts code coverage report files in lcov format to Cobertura's XML
+ report format so that CI servers like Jenkins can aggregate results and
+ determine build stability etc.
+
+ >>> from lcov_cobertura import LcovCobertura
+ >>> LCOV_INPUT = 'your lcov input'
+ >>> converter = LcovCobertura(LCOV_INPUT)
+ >>> cobertura_xml = converter.convert()
+ >>> print(cobertura_xml)
+ """
+
+ def __init__(self, lcov_data, base_dir='.', excludes=None, demangle=False):
+ """
+ Create a new :class:`LcovCobertura` object using the given `lcov_data`
+ and `options`.
+
+ :param lcov_data: Path to LCOV data file
+ :type lcov_data: string
+ :param base_dir: Path upon which to base all sources
+ :type base_dir: string
+ :param excludes: list of regexes to packages as excluded
+ :type excludes: [string]
+ :param demangle: whether to demangle function names using c++filt
+ :type demangle: bool
+ """
+
+ if not excludes:
+ excludes = []
+ self.lcov_data = lcov_data
+ self.base_dir = base_dir
+ self.excludes = excludes
+ if demangle:
+ demangler = Demangler()
+ self.format = demangler.demangle
+ else:
+ self.format = lambda x: x
+
+ def convert(self):
+ """
+ Convert lcov file to cobertura XML using options from this instance.
+ """
+ coverage_data = self.parse()
+ return self.generate_cobertura_xml(coverage_data)
+
+ def parse(self):
+ """
+ Generate a data structure representing it that can be serialized in any
+ logical format.
+ """
+
+ coverage_data = {
+ 'packages': {},
+ 'summary': {'lines-total': 0, 'lines-covered': 0,
+ 'branches-total': 0, 'branches-covered': 0},
+ 'timestamp': str(int(time.time()))
+ }
+ package = None
+ current_file = None
+ file_lines_total = 0
+ file_lines_covered = 0
+ file_lines = {}
+ file_methods = {}
+ file_branches_total = 0
+ file_branches_covered = 0
+
+ for line in self.lcov_data.split('\n'):
+ if line.strip() == 'end_of_record':
+ if current_file is not None:
+ package_dict = coverage_data['packages'][package]
+ package_dict['lines-total'] += file_lines_total
+ package_dict['lines-covered'] += file_lines_covered
+ package_dict['branches-total'] += file_branches_total
+ package_dict['branches-covered'] += file_branches_covered
+ file_dict = package_dict['classes'][current_file]
+ file_dict['lines-total'] = file_lines_total
+ file_dict['lines-covered'] = file_lines_covered
+ file_dict['lines'] = dict(file_lines)
+ file_dict['methods'] = dict(file_methods)
+ file_dict['branches-total'] = file_branches_total
+ file_dict['branches-covered'] = file_branches_covered
+ coverage_data['summary']['lines-total'] += file_lines_total
+ coverage_data['summary']['lines-covered'] += file_lines_covered
+ coverage_data['summary']['branches-total'] += file_branches_total
+ coverage_data['summary']['branches-covered'] += file_branches_covered
+
+ line_parts = line.split(':', 1)
+ input_type = line_parts[0]
+
+ if input_type == 'SF':
+ # Get file name
+ file_name = line_parts[-1].strip()
+ relative_file_name = os.path.relpath(file_name, self.base_dir)
+ package = '.'.join(relative_file_name.split(os.path.sep)[0:-1])
+ class_name = '.'.join(relative_file_name.split(os.path.sep))
+ if package not in coverage_data['packages']:
+ coverage_data['packages'][package] = {
+ 'classes': {}, 'lines-total': 0, 'lines-covered': 0,
+ 'branches-total': 0, 'branches-covered': 0
+ }
+ coverage_data['packages'][package]['classes'][
+ relative_file_name] = {
+ 'name': class_name, 'lines': {}, 'lines-total': 0,
+ 'lines-covered': 0, 'branches-total': 0,
+ 'branches-covered': 0
+ }
+ package = package
+ current_file = relative_file_name
+ file_lines_total = 0
+ file_lines_covered = 0
+ file_lines.clear()
+ file_methods.clear()
+ file_branches_total = 0
+ file_branches_covered = 0
+ elif input_type == 'DA':
+ # DA:2,0
+ (line_number, line_hits) = line_parts[-1].strip().split(',')
+ line_number = int(line_number)
+ if line_number not in file_lines:
+ file_lines[line_number] = {
+ 'branch': 'false', 'branches-total': 0,
+ 'branches-covered': 0
+ }
+ file_lines[line_number]['hits'] = line_hits
+ # Increment lines total/covered for class and package
+ try:
+ if int(line_hits) > 0:
+ file_lines_covered += 1
+ except:
+ pass
+ file_lines_total += 1
+ elif input_type == 'BRDA':
+ # BRDA:1,1,2,0
+ (line_number, block_number, branch_number, branch_hits) = line_parts[-1].strip().split(',')
+ line_number = int(line_number)
+ if line_number not in file_lines:
+ file_lines[line_number] = {
+ 'branch': 'true', 'branches-total': 0,
+ 'branches-covered': 0, 'hits': 0
+ }
+ file_lines[line_number]['branch'] = 'true'
+ file_lines[line_number]['branches-total'] += 1
+ file_branches_total += 1
+ if branch_hits != '-' and int(branch_hits) > 0:
+ file_lines[line_number]['branches-covered'] += 1
+ file_branches_covered += 1
+ elif input_type == 'BRF':
+ file_branches_total = int(line_parts[1])
+ elif input_type == 'BRH':
+ file_branches_covered = int(line_parts[1])
+ elif input_type == 'FN':
+ # FN:5,(anonymous_1)
+ function_line, function_name = line_parts[-1].strip().split(',')
+ file_methods[function_name] = [function_line, '0']
+ elif input_type == 'FNDA':
+ # FNDA:0,(anonymous_1)
+ (function_hits, function_name) = line_parts[-1].strip().split(',')
+ if function_name not in file_methods:
+ file_methods[function_name] = ['0', '0']
+ file_methods[function_name][-1] = function_hits
+
+ # Exclude packages
+ excluded = [x for x in coverage_data['packages'] for e in self.excludes
+ if re.match(e, x)]
+ for package in excluded:
+ del coverage_data['packages'][package]
+
+ # Compute line coverage rates
+ for package_data in list(coverage_data['packages'].values()):
+ package_data['line-rate'] = self._percent(
+ package_data['lines-total'],
+ package_data['lines-covered'])
+ package_data['branch-rate'] = self._percent(
+ package_data['branches-total'],
+ package_data['branches-covered'])
+
+ return coverage_data
+
+ def generate_cobertura_xml(self, coverage_data):
+ """
+ Given parsed coverage data, return a String cobertura XML representation.
+
+ :param coverage_data: Nested dict representing coverage information.
+ :type coverage_data: dict
+ """
+
+ dom_impl = minidom.getDOMImplementation()
+ doctype = dom_impl.createDocumentType("coverage", None,
+ "http://cobertura.sourceforge.net/xml/coverage-04.dtd")
+ document = dom_impl.createDocument(None, "coverage", doctype)
+ root = document.documentElement
+ summary = coverage_data['summary']
+ self._attrs(root, {
+ 'branch-rate': self._percent(summary['branches-total'],
+ summary['branches-covered']),
+ 'branches-covered': str(summary['branches-covered']),
+ 'branches-valid': str(summary['branches-total']),
+ 'complexity': '0',
+ 'line-rate': self._percent(summary['lines-total'],
+ summary['lines-covered']),
+ 'lines-covered': str(summary['lines-covered']),
+ 'lines-valid': str(summary['lines-total']),
+ 'timestamp': coverage_data['timestamp'],
+ 'version': '2.0.3'
+ })
+
+ sources = self._el(document, 'sources', {})
+ source = self._el(document, 'source', {})
+ source.appendChild(document.createTextNode(self.base_dir))
+ sources.appendChild(source)
+
+ root.appendChild(sources)
+
+ packages_el = self._el(document, 'packages', {})
+
+ packages = coverage_data['packages']
+ for package_name, package_data in list(packages.items()):
+ package_el = self._el(document, 'package', {
+ 'line-rate': package_data['line-rate'],
+ 'branch-rate': package_data['branch-rate'],
+ 'name': package_name,
+ 'complexity': '0',
+ })
+ classes_el = self._el(document, 'classes', {})
+ for class_name, class_data in list(package_data['classes'].items()):
+ class_el = self._el(document, 'class', {
+ 'branch-rate': self._percent(class_data['branches-total'],
+ class_data['branches-covered']),
+ 'complexity': '0',
+ 'filename': class_name,
+ 'line-rate': self._percent(class_data['lines-total'],
+ class_data['lines-covered']),
+ 'name': class_data['name']
+ })
+
+ # Process methods
+ methods_el = self._el(document, 'methods', {})
+ for method_name, (line, hits) in list(class_data['methods'].items()):
+ method_el = self._el(document, 'method', {
+ 'name': self.format(method_name),
+ 'signature': '',
+ 'line-rate': '1.0' if int(hits) > 0 else '0.0',
+ 'branch-rate': '1.0' if int(hits) > 0 else '0.0',
+ })
+ method_lines_el = self._el(document, 'lines', {})
+ method_line_el = self._el(document, 'line', {
+ 'hits': hits,
+ 'number': line,
+ 'branch': 'false',
+ })
+ method_lines_el.appendChild(method_line_el)
+ method_el.appendChild(method_lines_el)
+ methods_el.appendChild(method_el)
+
+ # Process lines
+ lines_el = self._el(document, 'lines', {})
+ lines = list(class_data['lines'].keys())
+ lines.sort()
+ for line_number in lines:
+ line_el = self._el(document, 'line', {
+ 'branch': class_data['lines'][line_number]['branch'],
+ 'hits': str(class_data['lines'][line_number]['hits']),
+ 'number': str(line_number)
+ })
+ if class_data['lines'][line_number]['branch'] == 'true':
+ total = int(class_data['lines'][line_number]['branches-total'])
+ covered = int(class_data['lines'][line_number]['branches-covered'])
+ percentage = int((covered * 100.0) / total)
+ line_el.setAttribute('condition-coverage',
+ '{0}% ({1}/{2})'.format(
+ percentage, covered, total))
+ lines_el.appendChild(line_el)
+
+ class_el.appendChild(methods_el)
+ class_el.appendChild(lines_el)
+ classes_el.appendChild(class_el)
+ package_el.appendChild(classes_el)
+ packages_el.appendChild(package_el)
+ root.appendChild(packages_el)
+
+ return document.toprettyxml()
+
+ def _el(self, document, name, attrs):
+ """
+ Create an element within document with given name and attributes.
+
+ :param document: Document element
+ :type document: Document
+ :param name: Element name
+ :type name: string
+ :param attrs: Attributes for element
+ :type attrs: dict
+ """
+ return self._attrs(document.createElement(name), attrs)
+
+ def _attrs(self, element, attrs):
+ """
+ Set attributes on given element.
+
+ :param element: DOM Element
+ :type element: Element
+ :param attrs: Attributes for element
+ :type attrs: dict
+ """
+ for attr, val in list(attrs.items()):
+ element.setAttribute(attr, val)
+ return element
+
+ def _percent(self, lines_total, lines_covered):
+ """
+ Get the percentage of lines covered in the total, with formatting.
+
+ :param lines_total: Total number of lines in given module
+ :type lines_total: number
+ :param lines_covered: Number of lines covered by tests in module
+ :type lines_covered: number
+ """
+
+ if lines_total == 0:
+ return '0.0'
+ return str(float(float(lines_covered) / float(lines_total)))
+
+
+def main(argv=None):
+ """
+ Converts LCOV coverage data to Cobertura-compatible XML for reporting.
+
+ Usage:
+ lcov_cobertura.py lcov-file.dat
+ lcov_cobertura.py lcov-file.dat -b src/dir -e test.lib -o path/out.xml
+
+ By default, XML output will be written to ./coverage.xml
+ """
+ if argv is None:
+ argv = sys.argv
+ parser = OptionParser()
+ parser.usage = ('lcov_cobertura.py lcov-file.dat [-b source/dir] '
+ '[-e <exclude packages regex>] [-o output.xml] [-d]')
+ parser.description = 'Converts lcov output to cobertura-compatible XML'
+ parser.add_option('-b', '--base-dir', action='store',
+ help='Directory where source files are located',
+ dest='base_dir', default='.')
+ parser.add_option('-e', '--excludes',
+ help='Comma-separated list of regexes of packages to exclude',
+ action='append', dest='excludes', default=[])
+ parser.add_option('-o', '--output',
+ help='Path to store cobertura xml file',
+ action='store', dest='output', default='coverage.xml')
+ parser.add_option('-d', '--demangle',
+ help='Demangle C++ function names using %s' % CPPFILT,
+ action='store_true', dest='demangle', default=False)
+ (options, args) = parser.parse_args(args=argv)
+
+ if options.demangle and not HAVE_CPPFILT:
+ raise RuntimeError("C++ filter executable (%s) not found!" % CPPFILT)
+
+ if len(args) != 2:
+ print(main.__doc__)
+ sys.exit(1)
+
+ try:
+ with open(args[1], 'r') as lcov_file:
+ lcov_data = lcov_file.read()
+ lcov_cobertura = LcovCobertura(lcov_data, options.base_dir, options.excludes, options.demangle)
+ cobertura_xml = lcov_cobertura.convert()
+ with open(options.output, mode='wt') as output_file:
+ output_file.write(cobertura_xml)
+ except IOError:
+ sys.stderr.write("Unable to convert %s to Cobertura XML" % args[1])
+
+if __name__ == '__main__':
+ main()
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
new file mode 100644
index 000000000..5ea6cdadd
--- /dev/null
+++ b/runtime/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectories()
diff --git a/runtime/contrib/CMakeLists.txt b/runtime/contrib/CMakeLists.txt
new file mode 100644
index 000000000..5ea6cdadd
--- /dev/null
+++ b/runtime/contrib/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectories()
diff --git a/runtime/contrib/TFLiteSharp/README.md b/runtime/contrib/TFLiteSharp/README.md
new file mode 100644
index 000000000..8e43be618
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/README.md
@@ -0,0 +1,92 @@
+# C-Sharp TFLite API Directory structure
+```
+.
+├── packaging
+│   ├── TFLiteSharp.manifest
+│   └── TFLiteSharp.spec
+├── README.md
+├── TFLiteNative
+│   ├── CMakeLists.txt
+│   ├── include
+│   │   ├── tflite_log.h
+│   │   └── tflite_nativewrapper.h
+│   ├── src
+│   │   └── tflite_nativewrapper.cpp
+│   └── tflite-native.pc.in
+├── TFLiteSharp
+│   ├── TFLiteSharp
+│   │   ├── src
+│   │   │   └── Interpreter.cs
+│   │   └── TFLiteSharp.csproj
+│   └── TFLiteSharp.sln
+└── TFLiteSharpTest
+ ├── TFLiteSharpTest
+ │   ├── Program.cs
+ │   └── TFLiteSharpTest.csproj
+ └── TFLiteSharpTest.sln
+```
+
+# Build C-Sharp TFLite
+gbs should be used to build TFLiteSharp package. nnfw is also built by gbs. As in most cases when building nnfw we won't intend to build TFLiteSharp hence we have separated its build process, so in order to build TFLiteSharp below command is needed:
+```
+nnfw$ gbs build --packaging-dir=contrib/TFLiteSharp/packaging/ --spec=TFLiteSharp.spec -A armv7l
+```
+This will first build the TFLiteNative package containing native c++ bindings between c# api and tflite api
+and then it will build TFLiteSharp(c# api package).
+
+Please use gbs.conf file corresponding to tizen image version. In most cases gbs.conf file should be same as the one which is used to build nnfw.
+# C-Sharp TFLite API list
+
+## Interpreter Class
+
+### Constructor
+
+The `Interpreter.cs` class drives model inference with TensorFlow Lite.
+
+#### Initializing an `Interpreter` With a Model File
+
+The `Interpreter` can be initialized with a model file using the constructor:
+
+```c#
+public Interpreter(string modelFile);
+```
+
+Number of threads available to the interpereter can be set by using the following function:
+```c#
+public void SetNumThreads(int num_threads)
+```
+
+### Running a model
+
+If a model takes only one input and returns only one output, the following will trigger an inference run:
+
+```c#
+interpreter.Run(input, output);
+```
+
+For models with multiple inputs, or multiple outputs, use:
+
+```c#
+interpreter.RunForMultipleInputsOutputs(inputs, map_of_indices_to_outputs);
+```
+
+The C# api also provides functions for getting the model's input and output indices given the name of tensors as input:
+
+```c#
+public int GetInputIndex(String tensorName)
+public int GetOutputIndex(String tensorName)
+```
+
+Developer can also enable or disable the use of NN API based on hardware capabilites:
+```c#
+public void SetUseNNAPI(boolean useNNAPI)
+```
+
+### Releasing Resources After Use
+
+An `Interpreter` owns resources. To avoid memory leak, the resources must be
+released after use by:
+
+```c#
+interpreter.Dispose();
+```
diff --git a/runtime/contrib/TFLiteSharp/TFLiteNative/CMakeLists.txt b/runtime/contrib/TFLiteSharp/TFLiteNative/CMakeLists.txt
new file mode 100644
index 000000000..8b58aac9c
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteNative/CMakeLists.txt
@@ -0,0 +1,67 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(fw_name "tflite-native")
+
+PROJECT(${fw_name})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(LIB ${LIB_PATH})
+SET(LIBDIR ${PREFIX}/${LIB_PATH})
+
+SET(INC_DIR include)
+INCLUDE_DIRECTORIES(${INC_DIR})
+
+INCLUDE(FindPkgConfig)
+
+SET(COMMON_DEPS "tensorflow-lite")
+SET(PC_DEPS "capi-base-common")
+
+IF (TIZEN)
+ MESSAGE("Building for Tizen")
+ SET(TIZEN_DEPS "dlog")
+ PKG_CHECK_MODULES(${fw_name} REQUIRED ${COMMON_DEPS} ${TIZEN_DEPS})
+ ADD_DEFINITIONS("-D__TIZEN__")
+ELSE ()
+ MESSAGE("Building for Linux")
+ PKG_CHECK_MODULES(${fw_name} REQUIRED ${COMMON_DEPS})
+ENDIF ()
+
+FOREACH(flag ${${fw_name}_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -fPIC -Wall -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIBDIR}")
+
+aux_source_directory(src SOURCES)
+ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
+
+TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS})
+
+SET_TARGET_PROPERTIES(${fw_name}
+ PROPERTIES
+ VERSION ${FULLVER}
+ SOVERSION ${MAJORVER}
+ CLEAN_DIRECT_OUTPUT 1
+)
+
+INSTALL(TARGETS ${fw_name} DESTINATION ${LIB})
+INSTALL(
+ DIRECTORY ${INC_DIR}/ DESTINATION include/
+ FILES_MATCHING
+ PATTERN "${INC_DIR}/*.h"
+ )
+
+SET(PC_NAME ${fw_name})
+SET(PC_REQUIRED ${pc_dependents})
+SET(PC_LDFLAGS -l${fw_name})
+
+CONFIGURE_FILE(
+ ${fw_name}.pc.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc
+ @ONLY
+)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB}/pkgconfig)
diff --git a/runtime/contrib/TFLiteSharp/TFLiteNative/include/tflite_log.h b/runtime/contrib/TFLiteSharp/TFLiteNative/include/tflite_log.h
new file mode 100644
index 000000000..69dfcc7b2
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteNative/include/tflite_log.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _TFLITE_LOG_H_
+#define _TFLITE_LOG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*__cplusplus*/
+
+#define ERROR 1
+#define WARNING 2
+#define INFO 3
+#define DEBUG 4
+
+#ifdef __TIZEN__
+#include <dlog/dlog.h>
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif // LOG_TAG
+#define LOG_TAG "TFLITE_NATIVE"
+
+#define TFLITE_NATIVE_LOG(log_level, format, args...) \
+ do \
+ { \
+ switch (log_level) \
+ { \
+ case ERROR: \
+ LOGE(format, ##args); \
+ case WARNING: \
+ LOGE(format, ##args); \
+ default: \
+ LOGI(format, ##args); \
+ } \
+ } while (0)
+#else // __TIZEN__
+#define LEVEL_TO_STR(level) \
+ (((level) == ERROR) \
+ ? "ERROR" \
+ : ((level) == WARNING) \
+ ? "WARNING" \
+ : ((level) == INFO) ? "INFO" : ((level) == DEBUG) ? "DEBUG" : "DEFAULT")
+#define TFLITE_NATIVE_LOG(log_level, format, args...) \
+ do \
+ { \
+ printf("%s: %s: ", LEVEL_TO_STR(log_level), __FILE__); \
+ printf(format, ##args); \
+ printf("\n"); \
+ } while (0)
+#endif // __TIZEN__
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus*/
+
+#endif /*_TFLITE_LOG_H*/
diff --git a/runtime/contrib/TFLiteSharp/TFLiteNative/include/tflite_nativewrapper.h b/runtime/contrib/TFLiteSharp/TFLiteNative/include/tflite_nativewrapper.h
new file mode 100644
index 000000000..b099ba9ba
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteNative/include/tflite_nativewrapper.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _TFLITE_NATIVEWRAPPER_H_
+#define _TFLITE_NATIVEWRAPPER_H_
+
+#include "tensorflow/lite/kernels/register.h"
+#include "tensorflow/lite/model.h"
+#include "tensorflow/lite/string_util.h"
+#include "tensorflow/lite/tools/mutable_op_resolver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*__cplusplus*/
+
+typedef enum {
+ /** 32-bit signed integer. */
+ INT32 = 1,
+
+ /** 32-bit single precision floating point. */
+ FLOAT32 = 2,
+
+ /** 8-bit unsigned integer. */
+ UINT8 = 3,
+
+ /** 64-bit signed integer. */
+ INT64 = 4
+} TFLiteNativeType;
+
+void tflite_interpreter_setNumThreads(long *interpreterHandle, int numThreads);
+
+long long tflite_flatbuffermodel_BuildFromFile(char *modelPath);
+
+long long tflite_builder_interpreterBuilder(long *modelHandle);
+
+void *tflite_interpreter_run(long *interpreterHandle, void *values, int inputLength, int dataType);
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus*/
+
+#endif /*_TFLITE_NATIVEWRAPPER_H_*/
diff --git a/runtime/contrib/TFLiteSharp/TFLiteNative/src/tflite_nativewrapper.cpp b/runtime/contrib/TFLiteSharp/TFLiteNative/src/tflite_nativewrapper.cpp
new file mode 100644
index 000000000..576a659ac
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteNative/src/tflite_nativewrapper.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include "tflite_nativewrapper.h"
+#include "tflite_log.h"
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+
+int getNumBytes(TFLiteNativeType dataType)
+{
+ switch (dataType)
+ {
+ case INT32:
+ return 4;
+ case FLOAT32:
+ return 4;
+ case UINT8:
+ return 1;
+ case INT64:
+ return 8;
+ default:
+ return 1;
+ }
+}
+
+/// <summary>
+/// Set the number of threads available to the interpreter.
+/// </summary>
+/// <param name="interpreterHandle">Handle of the interpreter instance.</param>
+/// <param name="numThreads">Number of threads.</param>
+void tflite_interpreter_setNumThreads(long *interpreterHandle, int numThreads)
+{
+ assert(interpreterHandle != nullptr);
+ tflite::Interpreter *interpreter = reinterpret_cast<tflite::Interpreter *>(*interpreterHandle);
+
+ interpreter->SetNumThreads(numThreads);
+
+ TFLITE_NATIVE_LOG(DEBUG, "Number of threads: %d", numThreads);
+ return;
+}
+
+/// <summary>
+/// Creates a Flat Buffer Model from the given .tflite model.
+/// </summary>
+/// <param name="modelPath">Path of the model.</param>
+long long tflite_flatbuffermodel_BuildFromFile(char *modelPath)
+{
+ if (modelPath == nullptr)
+ {
+ TFLITE_NATIVE_LOG(ERROR, "Invalid parameter");
+ return 0;
+ }
+ TFLITE_NATIVE_LOG(ERROR, "Model Path: %s", modelPath);
+
+ if (access(modelPath, F_OK) == -1)
+ {
+ TFLITE_NATIVE_LOG(ERROR, "Failed to access model [%s]", strerror(errno));
+ return 0;
+ }
+
+ auto model = tflite::FlatBufferModel::BuildFromFile(modelPath);
+
+ TFLITE_NATIVE_LOG(DEBUG, "Successfully loaded model");
+ return reinterpret_cast<long>(model.release());
+}
+
+/// <summary>
+/// Creates an interpreter instance taking the flatbuffer model as input.
+/// </summary>
+/// <param name="modelHandle">Address of the flatbuffer model.</param>
+long long tflite_builder_interpreterBuilder(long *modelHandle)
+{
+ assert(modelHandle != nullptr);
+ tflite::FlatBufferModel *model = reinterpret_cast<tflite::FlatBufferModel *>(*modelHandle);
+
+ tflite::ops::builtin::BuiltinOpResolver resolver;
+ std::unique_ptr<tflite::Interpreter> interpreter;
+
+ TfLiteStatus status = tflite::InterpreterBuilder(*model, resolver)(&interpreter);
+
+ if (status != kTfLiteOk)
+ {
+ TFLITE_NATIVE_LOG(DEBUG, "Cannot create interpreter");
+ return 0;
+ }
+ TFLITE_NATIVE_LOG(DEBUG, "CheckPoint interpreter");
+ return reinterpret_cast<long>(interpreter.release());
+}
+
+/// <summary>
+/// Runs the inference given the inputs.
+/// </summary>
+/// <param name="interpreterHandle">Address of the interpreter instance.</param>
+/// <param name="values">Input values for the model.</param>
+/// <param name="inpLength">Length of the input.</param>
+/// <param name="dataType">Data type key of the input.</param>
+void *tflite_interpreter_run(long *interpreterHandle, void *values, int inputLength, int dataType)
+{
+ assert(interpreterHandle != nullptr);
+ tflite::Interpreter *interpreter = reinterpret_cast<tflite::Interpreter *>(*interpreterHandle);
+
+ int inputTensorIndex = interpreter->inputs()[0];
+
+ // TODO:: input tensor size will be passed as a parameter. It is hardcoded for now.
+ interpreter->ResizeInputTensor(inputTensorIndex, {1, 224, 224, 3});
+
+ if (interpreter->AllocateTensors() != kTfLiteOk)
+ {
+ TFLITE_NATIVE_LOG(ERROR, "Failed to allocate tensors!");
+ return nullptr;
+ }
+
+ float *inputTensorPointer = interpreter->typed_tensor<float>(inputTensorIndex);
+
+ int numBytes = getNumBytes((TFLiteNativeType)dataType);
+
+ memcpy(inputTensorPointer, values, inputLength * numBytes);
+
+ if (interpreter->Invoke() != kTfLiteOk)
+ {
+ TFLITE_NATIVE_LOG(ERROR, "Failed to invoke");
+ }
+
+ float *output = interpreter->typed_output_tensor<float>(0);
+ return output;
+}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteNative/tflite-native.pc.in b/runtime/contrib/TFLiteSharp/TFLiteNative/tflite-native.pc.in
new file mode 100644
index 000000000..eec103acc
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteNative/tflite-native.pc.in
@@ -0,0 +1,13 @@
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@/
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@ tensorflow-lite
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp.sln b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp.sln
new file mode 100644
index 000000000..985466cef
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.16
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TFLiteSharp", "TFLiteSharp\TFLiteSharp.csproj", "{22D47176-D5AD-4AD4-8867-8788139DF71C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {22D47176-D5AD-4AD4-8867-8788139DF71C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {22D47176-D5AD-4AD4-8867-8788139DF71C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {22D47176-D5AD-4AD4-8867-8788139DF71C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {22D47176-D5AD-4AD4-8867-8788139DF71C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {1B276F69-8E79-4501-AF04-6D340690762B}
+ EndGlobalSection
+EndGlobal
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/Interop/Interop.Libraries.cs b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/Interop/Interop.Libraries.cs
new file mode 100644
index 000000000..db8d9f612
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/Interop/Interop.Libraries.cs
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+internal static partial class Interop
+{
+ internal static partial class Libraries
+ {
+ public const string TFLite = "libtflite-native.so";
+ }
+}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/Interop/Interop.TFLite.cs b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/Interop/Interop.TFLite.cs
new file mode 100644
index 000000000..c7c7b24aa
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/Interop/Interop.TFLite.cs
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class TFLite
+ {
+ [DllImport(Libraries.TFLite, EntryPoint = "tflite_flatbuffermodel_BuildFromFile")]
+ internal static extern IntPtr TFLiteFlatBufferModelBuildFromFile(string path);
+
+ [DllImport(Libraries.TFLite, EntryPoint = "tflite_builder_interpreterBuilder")]
+ internal static extern IntPtr TFLiteBuilderInterpreterBuilder(ref IntPtr modelHandle);
+
+ [DllImport(Libraries.TFLite, EntryPoint = "tflite_interpreter_setNumThreads")]
+ internal static extern void TFLiteInterpreterSetNumThreads(int numThreads);
+
+ [DllImport(Libraries.TFLite, EntryPoint = "tflite_interpreter_run")]
+ internal static extern IntPtr TFLiteInterpreterRun(ref IntPtr interpreterHandle, IntPtr values, int inpLen, int dataType);
+
+ }
+}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/TFLiteSharp.csproj b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/TFLiteSharp.csproj
new file mode 100644
index 000000000..e0490bfb8
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/TFLiteSharp.csproj
@@ -0,0 +1,52 @@
+<Project>
+ <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
+
+ <PropertyGroup Label="Globals">
+ <TizenProjectExtensionsPath>$(MSBuildExtensionsPath)\Tizen\VisualStudio\</TizenProjectExtensionsPath>
+ </PropertyGroup>
+
+ <Import Project="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props" Condition="Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props')" />
+
+ <PropertyGroup>
+ <OutputType>Library</OutputType>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ </PropertyGroup>
+
+ <!--
+ This Property Group for msbuild command line.
+ If project build on Visual Studio, it would be set automatically through the certificate manager.
+ <PropertyGroup>
+ <AuthorPath>author_test.p12</AuthorPath>
+ <AuthorPass>author_test</AuthorPass>
+ <DistributorPath>tizen-distributor-signer.p12</DistributorPath>
+ <DistributorPass>tizenpkcs12passfordsigner</DistributorPass>
+ </PropertyGroup>
+ -->
+
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugType>portable</DebugType>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>None</DebugType>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Remove="res\**" />
+ <EmbeddedResource Remove="res\**" />
+ <None Remove="res\**" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Folder Include="Interop\" />
+ <Folder Include="lib\" />
+ </ItemGroup>
+
+ <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
+ <Import Project="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets" Condition="Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets')" />
+
+ <!-- Install Check 'Visual Studio for Tizen' for developing on Visual Studio -->
+ <Target Name="TizenVsixInstallCheck" BeforeTargets="CompileDesignTime">
+ <Warning Condition="!Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props')" Text="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props is not exist.&#xA; you need to check if 'Visual Studio for Tizen' is installed" />
+ <Warning Condition="!Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets')" Text="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets is not exist.\&#xA; you need to check if 'Visual Studio for Tizen' is installed" />
+ </Target>
+</Project>
+
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/src/Datatype.cs b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/src/Datatype.cs
new file mode 100644
index 000000000..404d1663e
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/src/Datatype.cs
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Type of elements in a {@link TfLiteTensor}. */
+enum DataType
+{
+ /** 32-bit signed integer. */
+ INT32 = 1,
+
+ /** 32-bit single precision floating point. */
+ FLOAT32 = 2,
+
+ /** 8-bit unsigned integer. */
+ UINT8 = 3,
+
+ /** 64-bit signed integer. */
+ INT64 = 4
+}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/src/Interpreter.cs b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/src/Interpreter.cs
new file mode 100644
index 000000000..f1b4a8e07
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharp/TFLiteSharp/src/Interpreter.cs
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace TFLite
+{
+
+ /// <summary>
+ /// Driver class to drive model inference with TensorFlow Lite. Interpreter
+ /// encapsulates a pre-trained model file in whihc the operations are performed
+ /// @class Interpreter
+ /// </summary>
+ public class Interpreter : IDisposable
+ {
+ // Handle to hold the model instance
+ private IntPtr m_modelHandle;
+ // Handle to hold the interpreter instance
+ private IntPtr m_interpreterHandle;
+
+ /// <summary>
+ /// Interpreter Constructor. Inititalizes an interpreter.
+ /// </summary>
+ ///<param name="modelPath">a File of a pre-trained TF Lite model. </param>
+ public Interpreter(string modelPath)
+ {
+ //Constructor to initialize the interpreter with a model file
+ m_modelHandle = Interop.TFLite.TFLiteFlatBufferModelBuildFromFile(modelPath);
+ if(m_modelHandle == IntPtr.Zero)
+ {
+ //TODO: routine for handling null pointer.
+ }
+ m_interpreterHandle = Interop.TFLite.TFLiteBuilderInterpreterBuilder(ref m_modelHandle);
+ if (m_interpreterHandle == IntPtr.Zero)
+ {
+ //TODO: routine for handling null pointer.
+ }
+ }
+
+ /// <summary>
+ /// Set the number of threads available to the interpreter.
+ /// </summary>
+ /// <param name="numThreads">Number of threads.</param>
+ public void SetNumThreads(int numThreads)
+ {
+ Interop.TFLite.TFLiteInterpreterSetNumThreads(numThreads);
+ return;
+ }
+
+ /// <summary>
+ /// Runs model inference if the model takes only one input, and provides only
+ /// one output.
+ /// </summary>
+ /// <param name="input">input an array or multidimensional array.</param>
+ /// <param name="output">outputs a multidimensional array of output data.</param>
+ public void Run(Array input, ref Array output)
+ {
+ Array[] inputs = { input };
+ Dictionary<int, Array> outputs = new Dictionary<int, Array>();
+
+ RunForMultipleInputsOutputs(inputs, ref outputs);
+ output = outputs[0];
+
+ return;
+ }
+
+ /// <summary>
+ /// Runs model inference if the model takes multiple inputs, or returns multiple
+ /// outputs.
+ /// </summary>
+ /// <param name="inputs">input an array of input data.</param>
+ /// <param name="outputs">outputs a map mapping output indices to multidimensional
+ /// arrays of output data.</param>
+ public void RunForMultipleInputsOutputs(Array[] inputs, ref Dictionary<int, Array> outputs)
+ {
+ if(m_interpreterHandle == IntPtr.Zero)
+ {
+ //TODO:: exception handling
+ }
+
+ if (inputs == null || inputs.Length == 0)
+ {
+ //TODO::throw new IllegalArgumentException("Input error: Inputs should not be null or empty.");
+ }
+
+ DataType[] dataTypes = new DataType[inputs.Length];//To be used in multi-dimensional case
+
+ for (int i = 0; i < inputs.Length; ++i)
+ {
+ dataTypes[i] = DataTypeOf(inputs[i]);
+ }
+
+ //TODO:: Support for multi dimesional array to be added.
+ IntPtr pnt = Marshal.AllocHGlobal(inputs[0].Length);
+
+ switch (dataTypes[0])
+ {
+ case DataType.INT32:
+ Marshal.Copy((int[])inputs[0], 0, pnt, inputs[0].Length);
+ break;
+ case DataType.FLOAT32:
+ Marshal.Copy((float[])inputs[0], 0, pnt, inputs[0].Length);
+ break;
+ case DataType.UINT8:
+ Marshal.Copy((byte[])inputs[0], 0, pnt, inputs[0].Length);
+ break;
+ case DataType.INT64:
+ Marshal.Copy((long[])inputs[0], 0, pnt, inputs[0].Length);
+ break;
+ default:
+ Marshal.Copy((byte[])inputs[0], 0, pnt, inputs[0].Length);
+ break;
+ }
+
+ //Currently this handles only single input with single dimension.
+ IntPtr outputsHandles = Interop.TFLite.TFLiteInterpreterRun(ref m_interpreterHandle, pnt, inputs[0].Length, (int)dataTypes[0]);
+
+ if (outputsHandles == null)
+ {
+ //throw new IllegalStateException("Internal error: Interpreter has no outputs.");
+ }
+
+ switch (dataTypes[0])
+ {
+ case DataType.INT32:
+ int[] managedArrayInt = new int[inputs[0].Length];
+ Marshal.Copy(outputsHandles, managedArrayInt, 0, inputs[0].Length);
+ outputs.Add(0, managedArrayInt);
+ break;
+ case DataType.FLOAT32:
+ float[] managedArrayFloat = new float[inputs[0].Length];
+ Marshal.Copy(outputsHandles, managedArrayFloat, 0, inputs[0].Length);
+ outputs.Add(0, managedArrayFloat);
+ break;
+ case DataType.UINT8:
+ byte[] managedArrayByte = new byte[inputs[0].Length];
+ Marshal.Copy(outputsHandles, managedArrayByte, 0, inputs[0].Length);
+ outputs.Add(0, managedArrayByte);
+ break;
+ case DataType.INT64:
+ long[] managedArrayLong = new long[inputs[0].Length];
+ Marshal.Copy(outputsHandles, managedArrayLong, 0, inputs[0].Length);
+ outputs.Add(0, managedArrayLong);
+ break;
+ default:
+ byte[] managedArrayDefault = new byte[inputs[0].Length];
+ Marshal.Copy(outputsHandles, managedArrayDefault, 0, inputs[0].Length);
+ outputs.Add(0, managedArrayDefault);
+ break;
+ }
+ return;
+ }
+
+ static DataType DataTypeOf(Array a)
+ {
+ if (a.GetValue(0).GetType()==typeof(int))
+ {
+ return DataType.INT32;
+ }
+ else if (a.GetValue(0).GetType() == typeof(float))
+ {
+ return DataType.FLOAT32;
+ }
+ else if (a.GetValue(0).GetType() == typeof(byte))
+ {
+ return DataType.UINT8;
+ }
+ else if(a.GetValue(0).GetType() == typeof(long))
+ {
+ return DataType.INT64;
+ }
+ else
+ {
+ return DataType.UINT8;
+ //TODO: throw exception
+ }
+
+ }
+
+ /// <summary>
+ /// Resizes idx-th input of the native model to the given dims.
+ /// </summary>
+ /// <param name="idx">index of the input.</param>
+ /// <param name="dims">Dimensions to which input needs to be resized.</param>
+ public void ResizeInput(int idx, int[] dims)
+ {
+ return;
+ }
+
+ /// <summary>
+ /// Gets index of an input given the tensor name of the input.
+ /// </summary>
+ /// <param name="tensorName">Name of the tensor.</param>
+ public int GetInputIndex(string tensorName)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Gets index of output given the tensor name of the input.
+ /// </summary>
+ /// <param name="tensorName">Name of the tensor.</param>
+ public int GetOutputIndex(string tensorName)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Turns on/off Android NNAPI for hardware acceleration when it is available.
+ /// </summary>
+ /// <param name="useNNAPI">set the boolean value to turn on/off nnapi.</param>
+ public void SetUseNNAPI(bool useNNAPI)
+ {
+ return;
+ }
+
+ /// <summary>
+ /// Release resources associated with the Interpreter.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool bDisposing)
+ {
+ if (m_interpreterHandle != IntPtr.Zero)
+ {
+ // Call the function to dispose this class
+ m_interpreterHandle = IntPtr.Zero;
+ }
+
+ if (bDisposing)
+ {
+ // No need to call the finalizer since we've now cleaned
+ // up the unmanaged memory
+ GC.SuppressFinalize(this);
+ }
+ }
+
+ // This finalizer is called when Garbage collection occurs, but only if
+ // the IDisposable.Dispose method wasn't already called.
+ ~Interpreter()
+ {
+ Dispose(false);
+ }
+ }
+}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest.sln b/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest.sln
new file mode 100644
index 000000000..e260a72c7
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.16
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TFLiteSharpTest", "TFLiteSharpTest\TFLiteSharpTest.csproj", "{D35A178F-9EF3-4B07-9E53-A91AA7A030B3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TFLiteSharp", "..\TFLiteSharp\TFLiteSharp\TFLiteSharp.csproj", "{C06BC425-9BC3-43C7-A9D3-E12849E0C129}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D35A178F-9EF3-4B07-9E53-A91AA7A030B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D35A178F-9EF3-4B07-9E53-A91AA7A030B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D35A178F-9EF3-4B07-9E53-A91AA7A030B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D35A178F-9EF3-4B07-9E53-A91AA7A030B3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C06BC425-9BC3-43C7-A9D3-E12849E0C129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C06BC425-9BC3-43C7-A9D3-E12849E0C129}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C06BC425-9BC3-43C7-A9D3-E12849E0C129}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C06BC425-9BC3-43C7-A9D3-E12849E0C129}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8F946511-2BE4-40A5-A48C-A5684C62755D}
+ EndGlobalSection
+EndGlobal
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest/Program.cs b/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest/Program.cs
new file mode 100644
index 000000000..e559bec36
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest/Program.cs
@@ -0,0 +1,38 @@
+using System;
+
+namespace TFLiteSharpTest
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ //Constructing a new interpreter instance from the modelfile
+ TFLite.Interpreter interpreter = new TFLite.Interpreter("modelpath/modelfile.tflite");
+ Console.WriteLine("Interpreter Built Successfully");
+
+ //Setting the number of threads of the interpreter
+ interpreter.SetNumThreads(1);
+
+ //Declaring input and output variables;
+ Array input = new int[5] { 1, 2, 3, 4, 5 };
+ Array output = new int[5];
+
+ //Call to invoke the interpreter and run the inference to populate output
+ interpreter.Run(input, out output);
+ Console.WriteLine("Output generated Successfully");
+
+ //get input, output indices
+ Console.WriteLine("Input index for tensorname: " + interpreter.GetInputIndex("tensorname"));
+ Console.WriteLine("Output index for tensorname: " + interpreter.GetOutputIndex("tensorname"));
+
+ //Resizing the dimensions
+ int[] dims = new int[3] { 1, 2, 3 };
+ interpreter.ResizeInput(1, dims);
+
+ //Disposing the interpreter to free resources at the end
+ interpreter.Dispose();
+
+ Console.WriteLine("Run Complete");
+ }
+ }
+}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest/TFLiteSharpTest.csproj b/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest/TFLiteSharpTest.csproj
new file mode 100644
index 000000000..b143ee598
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteSharpTest/TFLiteSharpTest/TFLiteSharpTest.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>netcoreapp2.0</TargetFramework>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\..\TFLiteSharp\TFLiteSharp\TFLiteSharp.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp.csproj b/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp.csproj
new file mode 100644
index 000000000..1c9ed6037
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp.csproj
@@ -0,0 +1,54 @@
+<Project>
+ <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
+
+ <!-- Setting Tizen Extension Path -->
+ <PropertyGroup Label="Globals">
+ <TizenProjectExtensionsPath>$(MSBuildExtensionsPath)\Tizen\VisualStudio\</TizenProjectExtensionsPath>
+ </PropertyGroup>
+
+ <!-- Import Tizen property in Tizen.NET SDK -->
+ <Import Project="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props" Condition="Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props')" />
+
+ <!-- Property Group for .NET Core Project -->
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ </PropertyGroup>
+
+ <!-- Property Group for Tizen Project -->
+ <PropertyGroup>
+ <TizenCreateTpkOnBuild>true</TizenCreateTpkOnBuild>
+ <PackageTargetFallback>$(PackageTargetFallback);portable-net45+wp80+win81+wpa81</PackageTargetFallback>
+ </PropertyGroup>
+
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugType>portable</DebugType>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>None</DebugType>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Folder Include="lib\" />
+ <Folder Include="res\" />
+ </ItemGroup>
+
+ <!-- Include Nuget Package for Tizen Project building -->
+ <ItemGroup>
+ <PackageReference Include="Tizen.NET" Version="3.0.0" />
+ <PackageReference Include="Tizen.NET.Sdk" Version="1.0.1" />
+ <PackageReference Include="Xamarin.Forms.Platform.Tizen" Version="2.3.5-r256-001" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\TFLiteSharp\TFLiteSharp\TFLiteSharp.csproj" />
+ </ItemGroup>
+
+ <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
+ <Import Project="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets" Condition="Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets')" />
+
+ <!-- Install Check 'Visual Studio for Tizen' for developing on Visual Studio -->
+ <Target Name="TizenVsixInstallCheck" BeforeTargets="CompileDesignTime">
+ <Warning Condition="!Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props')" Text="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.props is not exist.&#xA; you need to check if 'Visual Studio for Tizen' is installed" />
+ <Warning Condition="!Exists('$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets')" Text="$(TizenProjectExtensionsPath)Tizen.NET.ProjectType.targets is not exist.\&#xA; you need to check if 'Visual Studio for Tizen' is installed" />
+ </Target>
+</Project>
diff --git a/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp_App.cs b/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp_App.cs
new file mode 100644
index 000000000..49a08604d
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp_App.cs
@@ -0,0 +1,65 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Xamarin.Forms;
+
+namespace TFLiteTestApp
+{
+ public class App : Application
+ {
+ public App()
+ {
+ TFLite.Interpreter interpreter = null;
+ try
+ {
+ interpreter = new TFLite.Interpreter(Tizen.Applications.Application.Current.DirectoryInfo.Resource + "mobilenet_v1_1.0_224.tflite");
+ }
+ catch(Exception e)
+ {
+ Tizen.Log.Debug("tflite", "Error: " + e);
+ }
+
+ Tizen.Log.Debug("tflite", "Interpreter Initialised");
+ Array Output = new byte[1000];
+
+ Array input = new byte[150582];
+ input = File.ReadAllBytes(Tizen.Applications.Application.Current.DirectoryInfo.Resource + "mouse_224.bmp");
+
+ interpreter.Run(input, ref Output);
+ //val variable to check if the Output array is being populated or not.
+ byte val = ((byte[])Output)[0];
+ // The root page of your application
+ MainPage = new ContentPage
+ {
+ Content = new StackLayout
+ {
+ VerticalOptions = LayoutOptions.Center,
+ Children = {
+ new Label {
+ HorizontalTextAlignment = TextAlignment.Center,
+ Text = "Welcome to Xamarin Forms!"
+ }
+ }
+ }
+ };
+ }
+
+ protected override void OnStart()
+ {
+ // Handle when your app starts
+ }
+
+ protected override void OnSleep()
+ {
+ // Handle when your app sleeps
+ }
+
+ protected override void OnResume()
+ {
+ // Handle when your app resumes
+ }
+ }
+}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp_Main.cs b/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp_Main.cs
new file mode 100644
index 000000000..2a8f747a4
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteTestApp/TFLiteTestApp_Main.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace TFLiteTestApp
+{
+ class Program : global::Xamarin.Forms.Platform.Tizen.FormsApplication
+ {
+ protected override void OnCreate()
+ {
+ base.OnCreate();
+ LoadApplication(new App());
+ }
+
+ static void Main(string[] args)
+ {
+ var app = new Program();
+ global::Xamarin.Forms.Platform.Tizen.Forms.Init(app);
+ app.Run(args);
+ }
+ }
+}
diff --git a/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mobilenet_v1_1.0_224.tflite b/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mobilenet_v1_1.0_224.tflite
new file mode 100644
index 000000000..d34691eb6
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mobilenet_v1_1.0_224.tflite
Binary files differ
diff --git a/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mouse1.bmp b/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mouse1.bmp
new file mode 100644
index 000000000..1734ca318
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mouse1.bmp
Binary files differ
diff --git a/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mouse_224.bmp b/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mouse_224.bmp
new file mode 100644
index 000000000..ccfed6ad3
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteTestApp/res/mouse_224.bmp
Binary files differ
diff --git a/runtime/contrib/TFLiteSharp/TFLiteTestApp/shared/res/TFLiteTestApp.png b/runtime/contrib/TFLiteSharp/TFLiteTestApp/shared/res/TFLiteTestApp.png
new file mode 100644
index 000000000..9f3cb9860
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteTestApp/shared/res/TFLiteTestApp.png
Binary files differ
diff --git a/runtime/contrib/TFLiteSharp/TFLiteTestApp/tizen-manifest.xml b/runtime/contrib/TFLiteSharp/TFLiteTestApp/tizen-manifest.xml
new file mode 100644
index 000000000..62a8d4c7c
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/TFLiteTestApp/tizen-manifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="4" package="org.tizen.example.TFLiteTestApp" version="1.0.0">
+ <profile name="common" />
+ <ui-application appid="org.tizen.example.TFLiteTestApp"
+ exec="TFLiteTestApp.dll"
+ type="dotnet"
+ multiple="false"
+ taskmanage="true"
+ nodisplay="false"
+ launch_mode="single">
+ <label>TFLiteTestApp</label>
+ <icon>TFLiteTestApp.png</icon>
+ </ui-application>
+</manifest>
diff --git a/runtime/contrib/TFLiteSharp/packaging/TFLiteSharp.manifest b/runtime/contrib/TFLiteSharp/packaging/TFLiteSharp.manifest
new file mode 100644
index 000000000..75b0fa5e3
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/packaging/TFLiteSharp.manifest
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
diff --git a/runtime/contrib/TFLiteSharp/packaging/TFLiteSharp.spec b/runtime/contrib/TFLiteSharp/packaging/TFLiteSharp.spec
new file mode 100644
index 000000000..dcb65a864
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/packaging/TFLiteSharp.spec
@@ -0,0 +1,103 @@
+Name: TFLiteSharp
+Summary: Tensorflow lite native cpp wrapper and C# API
+Version: 1.0.0
+Release: 1
+Group: Development/Libraries
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Source1: %{name}.manifest
+Source2: tflite-native.manifest
+
+%description
+%{summary}
+
+%package TFLiteNative
+Summary: Tensorflow lite native cpp wrapper
+Group: Development/Libraries
+BuildRequires: cmake
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(tensorflow-lite)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description TFLiteNative
+Native CPP Wrapper for Tensorflow lite
+
+%package TFLiteNative-devel
+Summary: Tensorflow lite native cpp wrapper (Development)
+Requires: %{name} = %{version}-%{release}
+
+%description TFLiteNative-devel
+Tensorflow lite native cpp wrapper (Development)
+
+%package TFLiteSharp
+Summary: Tensorflow lite API for C#
+Group: Development/Libraries
+AutoReqProv: no
+ExcludeArch: aarch64
+
+BuildRequires: dotnet-build-tools
+
+%define Assemblies TFLiteSharp
+
+%description TFLiteSharp
+Tensorflow lite API for C#
+
+%dotnet_import_sub_packages
+
+%prep
+%setup -q
+cp %{SOURCE1} .
+cp %{SOURCE2} .
+%if 0%{?tizen:1}
+%define TARGET_OS tizen
+%else
+%define TARGET_OS linux
+%endif
+
+%build
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+%if "%{TARGET_OS}" == "tizen"
+cmake VERBOSE=1 -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \
+ -DLIB_INSTALL_DIR=%{_libdir} -DINCLUDE_INSTALL_DIR=%{_includedir} \
+ -DLIB_PATH=%{_lib} -DTIZEN=1 contrib/TFLiteSharp/TFLiteNative
+%else
+cmake VERBOSE=1 -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \
+ -DLIB_INSTALL_DIR=%{_libdir} -DINCLUDE_INSTALL_DIR=%{_includedir} \
+ -DLIB_PATH=%{_lib} contrib/TFLiteSharp/TFLiteNative
+%endif
+
+make %{?_smp_mflags}
+
+cd contrib/TFLiteSharp/
+for ASM in %{Assemblies}; do
+%dotnet_build $ASM
+%dotnet_pack $ASM
+done
+
+%install
+%make_install
+cd contrib/TFLiteSharp/TFLiteSharp
+for ASM in %{Assemblies}; do
+%dotnet_install $ASM
+done
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%license LICENSE
+
+%files TFLiteNative
+%manifest tflite-native.manifest
+%{_libdir}/libtflite-native.so*
+
+%files TFLiteNative-devel
+%{_includedir}/*
+%{_libdir}/pkgconfig/tflite-native.pc
+%{_libdir}/libtflite-native.so*
+
+%files TFLiteSharp
+%attr(644,root,root) %{dotnet_assembly_files}
diff --git a/runtime/contrib/TFLiteSharp/packaging/tflite-native.manifest b/runtime/contrib/TFLiteSharp/packaging/tflite-native.manifest
new file mode 100644
index 000000000..75b0fa5e3
--- /dev/null
+++ b/runtime/contrib/TFLiteSharp/packaging/tflite-native.manifest
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
diff --git a/runtime/contrib/android/.gitignore b/runtime/contrib/android/.gitignore
new file mode 100644
index 000000000..012fc1eb2
--- /dev/null
+++ b/runtime/contrib/android/.gitignore
@@ -0,0 +1,6 @@
+/.gradle/*
+/build/*
+/api/build/*
+/api/.cxx/*
+.project
+.settings
diff --git a/runtime/contrib/android/README.md b/runtime/contrib/android/README.md
new file mode 100644
index 000000000..4e8167580
--- /dev/null
+++ b/runtime/contrib/android/README.md
@@ -0,0 +1,76 @@
+## How to setup env
+
+Install android studio
+- android studio: https://developer.android.com/studio
+
+Install `ndk 20.0.5594570`
+```
+dragon@loki:~/Android/Sdk$ ./tools/bin/sdkmanager --install "ndk;20.0.5594570"
+```
+
+```
+dragon@loki:~/Android/Sdk/ndk$ ls
+20.0.5594570
+```
+
+Set `ANDROID_SDK_ROOT` or `ANDROID_HOME` for SDK
+```
+$ cat ~/.bashrc
+...
+export ANDROID_SDK_ROOT=$HOME/Android/Sdk
+export ANDROID_HOME=$HOME/Android/Sdk
+```
+
+## How to build
+
+after building `onert`
+```
+ONE/runtime/contrib/android $ ./gradlew build
+...
+
+ONE/runtime/contrib/android$ find . -name "*.aar"
+./api/build/outputs/aar/com.samsung.onert-1.0-debug.aar
+./api/build/outputs/aar/com.samsung.onert-1.0-release.aar
+```
+
+## Example
+
+``` java
+import com.samsung.onert.Session;
+import com.samsung.onert.Tensor;
+
+// for now, the only cpu backend has been supported
+Session session = new Session("/sdcard/nnpkg/model/", "cpu");
+session.prepare();
+
+Tensor[] inputs, outputs;
+
+// allocate inputs and outputs like below
+// int size = session.getInputSize();
+// inputs = new Tensor[size];
+// for (int i = 0; i < size; ++i){
+// TensorInfo ti = session.getInputTensorInfo(i);
+// inputs[i] = new Tensor(ti);
+// }
+// session.setInputs(inputs);
+
+session.setInputs(inputs);
+session.setOutputs(outputs);
+
+// source inputs from outside
+// inputs[i].buffer().put(outside_buffer);
+
+session.run();
+
+// sink outputs to inside
+// outside_buffer.put(outputs[i].buffer());
+
+session.close();
+```
+
+## How to add jni api
+```
+ONE/runtime/contrib/android $ ./update_jni_header.sh
+```
+
+and then follow code of `onert-native-api.h` on `onert-native-api.cpp`
diff --git a/runtime/contrib/android/api/Android.mk b/runtime/contrib/android/api/Android.mk
new file mode 100644
index 000000000..3c768cca5
--- /dev/null
+++ b/runtime/contrib/android/api/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+API_ROOT_PATH := $(LOCAL_PATH)
+PREBUILT_LIB :=
+
+include $(API_ROOT_PATH)/Prebuilt.mk
+include $(API_ROOT_PATH)/src/main/native/Android.mk
diff --git a/runtime/contrib/android/api/Application.mk b/runtime/contrib/android/api/Application.mk
new file mode 100644
index 000000000..9acb26f4a
--- /dev/null
+++ b/runtime/contrib/android/api/Application.mk
@@ -0,0 +1,3 @@
+# Set target ABI in build.gradle (externalNativeBuild - abiFilters)
+APP_ABI := arm64-v8a
+APP_STL := c++_shared
diff --git a/runtime/contrib/android/api/Prebuilt.mk b/runtime/contrib/android/api/Prebuilt.mk
new file mode 100644
index 000000000..7d9f56582
--- /dev/null
+++ b/runtime/contrib/android/api/Prebuilt.mk
@@ -0,0 +1,70 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+ifndef ONERT_PREBUILT_LIB_DIR
+$(error ONERT_PREBUILT_LIB_DIR is not set)
+endif
+
+# libcircle_loader
+include $(CLEAR_VARS)
+LOCAL_MODULE := circle_loader
+PREBUILT_LIB += circle_loader
+LOCAL_SRC_FILES := \
+ $(ONERT_PREBUILT_LIB_DIR)/libcircle_loader.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# libtflite_loader
+include $(CLEAR_VARS)
+LOCAL_MODULE := tflite_loader
+PREBUILT_LIB += tflite_loader
+LOCAL_SRC_FILES := \
+ $(ONERT_PREBUILT_LIB_DIR)/libtflite_loader.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# libtensorflowlite_jni
+include $(CLEAR_VARS)
+LOCAL_MODULE := tensorflowlite_jni
+PREBUILT_LIB += tensorflowlite_jni
+LOCAL_SRC_FILES := \
+ $(ONERT_PREBUILT_LIB_DIR)/libtensorflowlite_jni.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# libnnfw
+include $(CLEAR_VARS)
+LOCAL_MODULE := nnfw-dev
+PREBUILT_LIB += nnfw-dev
+LOCAL_SRC_FILES := \
+ $(ONERT_PREBUILT_LIB_DIR)/libnnfw-dev.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# libonert_core
+include $(CLEAR_VARS)
+LOCAL_MODULE := onert_core
+PREBUILT_LIB += onert_core
+LOCAL_SRC_FILES := \
+ $(ONERT_PREBUILT_LIB_DIR)/libonert_core.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# backend_cpu
+include $(CLEAR_VARS)
+LOCAL_MODULE := backend_cpu
+PREBUILT_LIB += backend_cpu
+LOCAL_SRC_FILES := \
+ $(ONERT_PREBUILT_LIB_DIR)/libbackend_cpu.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# TODO Support backend acl
+# backend_acl
+ifeq ($(ONERT_CONTAINS_ACL), 1)
+ $(error containing acl backend doesn't supported yet)
+endif
+
+# backend_ext
+ifneq ($(ONERT_EXT_PREBUILT_LIB), )
+include $(CLEAR_VARS)
+LOCAL_MODULE := backend_ext
+PREBUILT_LIB += backend_ext
+LOCAL_SRC_FILES := \
+ $(ONERT_EXT_PREBUILT_LIB)
+include $(PREBUILT_SHARED_LIBRARY)
+endif
diff --git a/runtime/contrib/android/api/build.gradle b/runtime/contrib/android/api/build.gradle
new file mode 100644
index 000000000..5427878e1
--- /dev/null
+++ b/runtime/contrib/android/api/build.gradle
@@ -0,0 +1,69 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.3"
+
+ defaultConfig {
+ minSdkVersion 26
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.11.0"
+
+ externalNativeBuild {
+ ndkBuild {
+ def onert_header_dir
+ if (project.hasProperty('onertHeaderDir'))
+ onert_header_dir = project.onertHeaderDir
+ else
+ onert_header_dir = "${project.projectDir}/../../../onert/api/include"
+
+ def onert_lib_dir
+ if (project.hasProperty('onertLibDir'))
+ onert_lib_dir = project.onertLibDir
+ else
+ onert_lib_dir = "${project.projectDir}/../../../../Product/out/lib"
+
+ def onert_contains_acl
+ if (project.hasProperty('onertContainsAcl'))
+ onert_contains_acl = 1
+ else
+ onert_contains_acl = 0
+
+ def onert_ext_lib
+ if (project.hasProperty('onertExtLib'))
+ onert_ext_lib = project.onertExtLib
+ else
+ onert_ext_lib = ""
+
+ arguments "ONERT_API_INC_DIR=$onert_header_dir",
+ "ONERT_PREBUILT_LIB_DIR=$onert_lib_dir",
+ "ONERT_CONTAINS_ACL=$onert_contains_acl",
+ "ONERT_EXT_PREBUILT_LIB=$onert_ext_lib"
+
+ abiFilters 'arm64-v8a'
+ }
+ }
+
+ archivesBaseName = "com.samsung.onert-$versionName"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ externalNativeBuild {
+ ndkBuild {
+ path "${project.projectDir}/Android.mk"
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+
+ implementation 'com.android.support:support-annotations:28.0.0'
+}
diff --git a/runtime/contrib/android/api/proguard-rules.pro b/runtime/contrib/android/api/proguard-rules.pro
new file mode 100644
index 000000000..f1b424510
--- /dev/null
+++ b/runtime/contrib/android/api/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/runtime/contrib/android/api/src/main/AndroidManifest.xml b/runtime/contrib/android/api/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..6e1aabc3e
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.samsung.onert" />
diff --git a/runtime/contrib/android/api/src/main/java/com/samsung/onert/Helper.java b/runtime/contrib/android/api/src/main/java/com/samsung/onert/Helper.java
new file mode 100644
index 000000000..22b0efb76
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/java/com/samsung/onert/Helper.java
@@ -0,0 +1,128 @@
+package com.samsung.onert;
+
+// java
+import java.util.Arrays;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.FloatBuffer;
+import java.nio.ByteOrder;
+
+// android
+import android.util.Log;
+
+final class Helper {
+ static final String TAG = "ONERT_NATIVE";
+
+ static boolean isByteBuffer(Object o) {
+ return o instanceof ByteBuffer;
+ }
+
+ static ByteBuffer asByteBuffer(int[] int_arr) {
+ int size = int_arr.length * Integer.BYTES;
+ assert size > 0;
+
+ ByteBuffer bb = ByteBuffer.allocateDirect(size).
+ order(ByteOrder.nativeOrder());
+ bb.clear();
+
+ bb.asIntBuffer().put(int_arr);
+ return bb;
+ }
+
+ static int[] asIntArray(ByteBuffer bb) {
+ bb.rewind();
+ int size = (bb.limit()) / Integer.BYTES +
+ ((bb.limit() % Integer.BYTES == 0) ? 0 : 1);
+ assert size > 0;
+
+ int[] int_arr = new int[size];
+
+ IntBuffer ib = bb.asIntBuffer();
+ ib.get(int_arr);
+ return int_arr;
+ }
+
+ static int[] asIntArray(byte[] ba) {
+ ByteBuffer bb = ByteBuffer.wrap(ba).order(ByteOrder.nativeOrder());
+ return asIntArray(bb);
+ }
+
+ static void printByteBufferForDebug(ByteBuffer bb) {
+ Log.d(TAG,
+ String.format("ByteBuffer cap(%d) limit(%d) pos(%d) remaining(%d)",
+ bb.capacity(), bb.limit(), bb.position(), bb.remaining()));
+ }
+
+ static void printIntArrayForDebug(int[] ia) {
+ Log.d(TAG,
+ String.format("IntArray(%d) %s", ia.length, Arrays.toString(ia)));
+ }
+
+ static void printArray(int[] array) {
+ printIntArrayForDebug(array);
+ Log.d(TAG, "PRINT_DATA_size: " + array.length);
+ }
+
+ static void printFloatBuffer(ByteBuffer bb, int size) {
+ try {
+ printByteBufferForDebug(bb);
+ Log.d(TAG, "PRINT_DATA_size: " + size + ", capacity: " + bb.capacity());
+ bb.position(0);
+ FloatBuffer fb = bb.asFloatBuffer();
+
+ int print_size = Math.min(size, 30);
+ float[] data = new float[print_size];
+ fb.get(data, 0, print_size);
+ Log.d(TAG, "PRINT_DATA :" + Arrays.toString(data));
+ bb.position(0);
+ } catch (Exception e) {
+ Log.d(TAG, "PRINT_DATA_EXCEPTION : " + e.toString());
+ }
+ }
+
+ static int convertTensorType(TensorInfo.Type type) {
+ int ret = 0;
+ switch (type) {
+ case FLOAT32:
+ ret = 0; break;
+ case INT32:
+ ret = 1; break;
+ case QUANT8_ASYMM:
+ ret = 2; break;
+ case BOOL:
+ ret = 3; break;
+ case UINT8:
+ ret = 4; break;
+ default:
+ ret = -1; break;
+ }
+ return ret;
+ }
+
+ static TensorInfo.Type convertOneRTTensorType(int type) {
+ TensorInfo.Type ret;
+ switch (type) {
+ case 0:
+ ret = TensorInfo.Type.FLOAT32; break;
+ case 1:
+ ret = TensorInfo.Type.INT32; break;
+ case 2:
+ ret = TensorInfo.Type.QUANT8_ASYMM; break;
+ case 3:
+ ret = TensorInfo.Type.BOOL; break;
+ case 4:
+ ret = TensorInfo.Type.UINT8; break;
+ default:
+ ret = TensorInfo.Type.UNKNOWN; break;
+ }
+ return ret;
+ }
+
+ static TensorInfo newTensorInfo(NativeSessionWrapper.InternalTensorInfo info) {
+ TensorInfo.Type type = Helper.convertOneRTTensorType(info.type);
+ int rank = info.rank;
+ int[] shape = info.shape;
+ return new TensorInfo(type, rank, shape);
+ }
+
+}
diff --git a/runtime/contrib/android/api/src/main/java/com/samsung/onert/NativeSessionWrapper.java b/runtime/contrib/android/api/src/main/java/com/samsung/onert/NativeSessionWrapper.java
new file mode 100644
index 000000000..eaaf76737
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/java/com/samsung/onert/NativeSessionWrapper.java
@@ -0,0 +1,139 @@
+package com.samsung.onert;
+
+// java
+import java.nio.ByteBuffer;
+
+// android
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+final class NativeSessionWrapper implements AutoCloseable {
+
+ static final String TAG = "ONERT_NATIVE";
+
+ static final String LIB_NAME = "onert-native-api";
+
+ static
+ {
+ System.loadLibrary(LIB_NAME);
+ }
+
+ static final String DEFAULT_BACKENDS = "cpu";
+
+ NativeSessionWrapper(@NonNull String nnpkg_path) {
+ this(nnpkg_path, DEFAULT_BACKENDS);
+ }
+
+ NativeSessionWrapper(@NonNull String nnpkg_path, @NonNull String backends) {
+ _handle = nativeCreateSession();
+ nativeLoadModelFromFile(_handle, nnpkg_path);
+ _backends = backends;
+ }
+
+ boolean prepare() {
+ return (nativeSetAvailableBackends(_handle, _backends) &&
+ nativePrepare(_handle));
+ }
+
+ // TODO Layout
+ boolean setInputs(Tensor[] inputs) {
+ final int count = inputs.length;
+ for (int i = 0; i < count; ++i) {
+ Tensor t = inputs[i];
+ if (!nativeSetInput(_handle, i, Helper.convertTensorType(t.type()), t.buffer(),
+ t.getByteSize())) {
+ Log.e(TAG, String.format("%s] nativeSetInput failed", "setInputs"));
+ return false;
+ }
+ if (!nativeSetInputLayout(_handle, i, 1)) { // 1: CHANNELS_LAST
+ Log.e(TAG, String.format("%s] nativeSetInputLayout failed", "setInputs"));
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // TODO Layout
+ boolean setOutputs(Tensor[] outputs) {
+ final int count = outputs.length;
+ for (int i = 0; i < count; ++i) {
+ Tensor t = outputs[i];
+ if (!nativeSetOutput(_handle, i, Helper.convertTensorType(t.type()), t.buffer(),
+ t.getByteSize())) {
+ Log.e(TAG, String.format("%s] nativeSetOutput failed", "setOutputs"));
+ return false;
+ }
+ if (!nativeSetOutputLayout(_handle, i, 1)) { // 1: CHANNELS_LAST
+ Log.e(TAG, String.format("%s] nativeSetOutputLayout failed", "setOutputs"));
+ return false;
+ }
+ }
+ return true;
+ }
+
+ boolean run() {
+ return nativeRun(_handle);
+ }
+
+ int getInputSize() {
+ return nativeGetInputSize(_handle);
+ }
+
+ int getOutputSize() {
+ return nativeGetOutputSize(_handle);
+ }
+
+ TensorInfo getInputTensorInfo(int index) {
+ InternalTensorInfo info = new InternalTensorInfo();
+ nativeGetInputTensorInfo(_handle, index, info);
+ return Helper.newTensorInfo(info);
+ }
+
+ TensorInfo getOutputTensorInfo(int index) {
+ InternalTensorInfo info = new InternalTensorInfo();
+ nativeGetOutputTensorInfo(_handle, index, info);
+ return Helper.newTensorInfo(info);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public void close() {
+ nativeCloseSession(_handle);
+ _handle = 0;
+ }
+
+ private long _handle = 0;
+ private String _backends = null;
+
+ // TODO How to handle enum in jni properly
+ class InternalTensorInfo {
+ int type;
+ int rank;
+ int[] shape;
+ };
+
+ // onert-native-api
+ private native long nativeCreateSession();
+ private native void nativeCloseSession(long handle);
+ private native boolean nativeLoadModelFromFile(long handle, String nnpkg_path);
+ private native boolean nativePrepare(long handle);
+ private native boolean nativeRun(long handle);
+ private native boolean nativeSetInput(long handle, int index, int type, ByteBuffer buffer, int byteSize);
+ private native boolean nativeSetOutput(long handle, int index, int type, ByteBuffer buffer, int byteSize);
+ private native boolean nativeSetInputLayout(long handle, int index, int layout);
+ private native boolean nativeSetOutputLayout(long handle, int index, int layout);
+ private native int nativeGetInputSize(long handle);
+ private native int nativeGetOutputSize(long handle);
+ private native boolean nativeGetInputTensorInfo(long handle, int index, InternalTensorInfo info);
+ private native boolean nativeGetOutputTensorInfo(long handle, int index, InternalTensorInfo info);
+ private native boolean nativeSetAvailableBackends(long handle, String backends);
+}
diff --git a/runtime/contrib/android/api/src/main/java/com/samsung/onert/Session.java b/runtime/contrib/android/api/src/main/java/com/samsung/onert/Session.java
new file mode 100644
index 000000000..9833aaac6
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/java/com/samsung/onert/Session.java
@@ -0,0 +1,61 @@
+package com.samsung.onert;
+
+// android
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public final class Session implements AutoCloseable {
+
+ // TODO backends -> enum & bit
+ public Session(@NonNull String nnpkg_path, @Nullable String backends) {
+ _native_sess = new NativeSessionWrapper(nnpkg_path, backends);
+ }
+
+ public boolean prepare() {
+ return _native_sess.prepare();
+ }
+
+ public void setInputs(Tensor[] inputs) {
+ _native_sess.setInputs(inputs);
+ }
+
+ public void setOutputs(Tensor[] outputs) {
+ _native_sess.setOutputs(outputs);
+ }
+
+ public int getInputSize() {
+ return _native_sess.getInputSize();
+ }
+
+ public int getOutputSize() {
+ return _native_sess.getOutputSize();
+ }
+
+ public TensorInfo getInputTensorInfo(int index) {
+ return _native_sess.getInputTensorInfo(index);
+ }
+
+ public TensorInfo getOutputTensorInfo(int index) {
+ return _native_sess.getOutputTensorInfo(index);
+ }
+
+ public boolean run() {
+ return _native_sess.run();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public void close() {
+ _native_sess = null;
+ }
+
+ private NativeSessionWrapper _native_sess = null;
+}
diff --git a/runtime/contrib/android/api/src/main/java/com/samsung/onert/Tensor.java b/runtime/contrib/android/api/src/main/java/com/samsung/onert/Tensor.java
new file mode 100644
index 000000000..609870156
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/java/com/samsung/onert/Tensor.java
@@ -0,0 +1,73 @@
+package com.samsung.onert;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+// TODO LAYOUT
+public final class Tensor implements AutoCloseable {
+
+ static final String TAG = "ONERT_NATIVE";
+
+ public static boolean validateBuffer(ByteBuffer buffer) {
+ if (buffer == null)
+ return false;
+ if (!buffer.isDirect())
+ return false;
+ return true;
+ }
+
+ public Tensor(@NonNull TensorInfo info) {
+ _info = info;
+ _buffer = ByteBuffer.allocateDirect(getByteSize())
+ .order(ByteOrder.nativeOrder());
+ }
+
+ public Tensor(@NonNull int[] shape, @NonNull TensorInfo.Type type) {
+ this(new TensorInfo(type, shape.length, shape));
+ }
+
+ public int[] shape() {
+ return _info.shape;
+ }
+
+ public TensorInfo.Type type() {
+ return _info.type;
+ }
+
+ public void buffer(ByteBuffer buffer) {
+ _buffer = buffer;
+ }
+
+ public ByteBuffer buffer() {
+ return _buffer;
+ }
+
+ public int getByteSize() {
+ return TensorInfo.getByteSize(_info);
+ }
+
+ public int getSize() {
+ return TensorInfo.getSize(_info);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public void close() {
+ _buffer = null;
+ }
+
+ private TensorInfo _info = null;
+ private ByteBuffer _buffer = null;
+}
diff --git a/runtime/contrib/android/api/src/main/java/com/samsung/onert/TensorInfo.java b/runtime/contrib/android/api/src/main/java/com/samsung/onert/TensorInfo.java
new file mode 100644
index 000000000..f1cbfba2c
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/java/com/samsung/onert/TensorInfo.java
@@ -0,0 +1,75 @@
+package com.samsung.onert;
+
+public final class TensorInfo implements AutoCloseable {
+ public enum Type {
+ FLOAT32,
+ INT32,
+ QUANT8_ASYMM,
+ BOOL,
+ UINT8,
+ UNKNOWN
+ }
+
+ public static int getTypeSize(Type type) {
+ int size = 0;
+ switch (type) {
+ case FLOAT32:
+ case INT32:
+ size = 4;
+ break;
+ case QUANT8_ASYMM:
+ case BOOL: // Note. different from java's one
+ case UINT8:
+ size = 1;
+ break;
+ default:
+ size = -1;
+ break;
+ }
+ return size;
+ }
+
+ public static int getByteSize(TensorInfo info) {
+ int size = TensorInfo.getTypeSize(info.type);
+ int[] shape = info.shape;
+ for (int i = 0; i < shape.length; ++i) {
+ size *= shape[i];
+ }
+ return size;
+ }
+
+ public static int getSize(TensorInfo info) {
+ int size = 1;
+ int[] shape = info.shape;
+ for (int i = 0; i < shape.length; ++i) {
+ size *= shape[i];
+ }
+ return size;
+ }
+
+ public TensorInfo() {}
+
+ public TensorInfo(Type t, int r, int[] s) {
+ type = t;
+ rank = r;
+ shape = s;
+ }
+ public Type type;
+ public int rank;
+ public int[] shape;
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public void close() {
+ shape = null;
+ }
+}
+
diff --git a/runtime/contrib/android/api/src/main/native/Android.mk b/runtime/contrib/android/api/src/main/native/Android.mk
new file mode 100644
index 000000000..76c80a7eb
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/native/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+ifndef ONERT_API_INC_DIR
+$(error ONERT_API_INC_DIR is not set)
+endif
+
+LOCAL_MODULE := onert-native-api
+LOCAL_SRC_FILES := \
+ onert-native-internal.cpp \
+ onert-native-helper.cpp \
+ onert-native-api.cpp
+LOCAL_C_INCLUDES := $(ONERT_API_INC_DIR)
+LOCAL_CXXFLAGS := -std=c++14 -O3 -fPIC -frtti -fexceptions
+LOCAL_SHARED_LIBRARIES := $(PREBUILT_LIB)
+LOCAL_LDLIBS := -llog -landroid
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/runtime/contrib/android/api/src/main/native/onert-native-api.cpp b/runtime/contrib/android/api/src/main/native/onert-native-api.cpp
new file mode 100644
index 000000000..209264d31
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/native/onert-native-api.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "onert-native-api.h"
+
+#include <android/log.h>
+
+#include "onert-native-internal.h"
+#include "onert-native-helper.h"
+
+namespace
+{
+
+// android log tag
+const char *JTAG = "ONERT_NATIVE";
+
+} // namespace
+
+JNIEXPORT jlong JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeCreateSession(JNIEnv *,
+ jobject)
+{
+ Handle sess = jni::createSession();
+ if (sess == 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] nnfw_create_session is failed",
+ __PRETTY_FUNCTION__);
+ }
+ return sess;
+}
+
+JNIEXPORT void JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeCloseSession(JNIEnv *,
+ jobject,
+ jlong handle)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return;
+
+ jni::closeSession(handle);
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeLoadModelFromFile(
+ JNIEnv *env, jobject, jlong handle, jstring jnnpkg_path)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ const char *nnpkg_path = env->GetStringUTFChars(jnnpkg_path, 0);
+ __android_log_print(ANDROID_LOG_DEBUG, JTAG, "%s] nnpkg_path: %s", __PRETTY_FUNCTION__,
+ nnpkg_path);
+
+ bool result = jni::loadModel(handle, nnpkg_path);
+
+ env->ReleaseStringUTFChars(jnnpkg_path, nnpkg_path);
+
+ if (result == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativePrepare(JNIEnv *,
+ jobject,
+ jlong handle)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ if (jni::prepare(handle) == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeRun(JNIEnv *, jobject,
+ jlong handle)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ if (jni::run(handle) == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetInput(
+ JNIEnv *env, jobject, jlong handle, jint jindex, jint jtype, jobject jbuf, jint jbufsize)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ jni::TensorParams params;
+ if (jni_helper::getTensorParams(env, jindex, jtype, jbuf, jbufsize, params) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed getTensorParams", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] index(%d), type(%d), buf(%p), buf_sz(%lu)",
+ __PRETTY_FUNCTION__, params.index, params.type, params.buffer,
+ params.buffer_size);
+
+ if (jni::setInput(handle, params) == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed native setInput", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetOutput(
+ JNIEnv *env, jobject, jlong handle, jint jindex, jint jtype, jobject jbuf, jint jbufsize)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ jni::TensorParams params;
+ if (jni_helper::getTensorParams(env, jindex, jtype, jbuf, jbufsize, params) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed getTensorParams", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] index(%d), type(%d), buf(%p), buf_sz(%lu)",
+ __PRETTY_FUNCTION__, params.index, params.type, params.buffer,
+ params.buffer_size);
+
+ if (jni::setOutput(handle, params) == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed native setOutput",
+ __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetInputLayout(
+ JNIEnv *, jobject, jlong handle, jint jindex, jint jlayout)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ jni::LayoutParams params;
+ if (jni_helper::getLayoutParams(jindex, jlayout, params) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (jni::setInputLayout(handle, params) == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetOutputLayout(
+ JNIEnv *, jobject, jlong handle, jint jindex, jint jlayout)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ jni::LayoutParams params;
+ if (jni_helper::getLayoutParams(jindex, jlayout, params) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (jni::setOutputLayout(handle, params) == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jint JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeGetInputSize(JNIEnv *,
+ jobject,
+ jlong handle)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return -1;
+
+ int size = 0;
+ if ((size = jni::getInputSize(handle)) < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return -1;
+ }
+
+ return static_cast<jint>(size);
+}
+
+JNIEXPORT jint JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeGetOutputSize(JNIEnv *,
+ jobject,
+ jlong handle)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return -1;
+
+ int size = 0;
+ if ((size = jni::getOutputSize(handle)) < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return -1;
+ }
+
+ return static_cast<jint>(size);
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetAvailableBackends(
+ JNIEnv *env, jobject, jlong handle, jstring jbackends)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ const char *backends = env->GetStringUTFChars(jbackends, 0);
+ __android_log_print(ANDROID_LOG_DEBUG, JTAG, "%s] backends: %s", __PRETTY_FUNCTION__, backends);
+
+ auto result = jni::setAvailableBackends(handle, backends);
+
+ env->ReleaseStringUTFChars(jbackends, backends);
+
+ if (result == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeGetInputTensorInfo(
+ JNIEnv *env, jobject, jlong handle, jint jindex, jobject jinfo)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ jni::TensorInfo tensor_info;
+ if (jni_helper::getInputTensorInfo(handle, jindex, tensor_info) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (jni_helper::setTensorInfoToJava(env, tensor_info, jinfo) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeGetOutputTensorInfo(
+ JNIEnv *env, jobject, jlong handle, jint jindex, jobject jinfo)
+{
+ if (jni_helper::verifyHandle(handle) == JNI_FALSE)
+ return JNI_FALSE;
+
+ jni::TensorInfo tensor_info;
+ if (jni_helper::getOutputTensorInfo(handle, jindex, tensor_info) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (jni_helper::setTensorInfoToJava(env, tensor_info, jinfo) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, JTAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
diff --git a/runtime/contrib/android/api/src/main/native/onert-native-api.h b/runtime/contrib/android/api/src/main/native/onert-native-api.h
new file mode 100644
index 000000000..13768d470
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/native/onert-native-api.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_samsung_onert_NativeSessionWrapper */
+
+#ifndef _Included_com_samsung_onert_NativeSessionWrapper
+#define _Included_com_samsung_onert_NativeSessionWrapper
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeCreateSession
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeCreateSession(JNIEnv *,
+ jobject);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeCloseSession
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeCloseSession(JNIEnv *,
+ jobject,
+ jlong);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeLoadModelFromFile
+ * Signature: (JLjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeLoadModelFromFile(
+ JNIEnv *, jobject, jlong, jstring);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativePrepare
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativePrepare(JNIEnv *,
+ jobject,
+ jlong);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeRun
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeRun(JNIEnv *, jobject,
+ jlong);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeSetInput
+ * Signature: (JIILjava/nio/ByteBuffer;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetInput(
+ JNIEnv *, jobject, jlong, jint, jint, jobject, jint);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeSetOutput
+ * Signature: (JIILjava/nio/ByteBuffer;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetOutput(
+ JNIEnv *, jobject, jlong, jint, jint, jobject, jint);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeSetInputLayout
+ * Signature: (JII)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetInputLayout(
+ JNIEnv *, jobject, jlong, jint, jint);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeSetOutputLayout
+ * Signature: (JII)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetOutputLayout(
+ JNIEnv *, jobject, jlong, jint, jint);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeGetInputSize
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeGetInputSize(JNIEnv *,
+ jobject,
+ jlong);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeGetOutputSize
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeGetOutputSize(JNIEnv *,
+ jobject,
+ jlong);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeGetInputTensorInfo
+ * Signature: (JILcom/samsung/onert/NativeSessionWrapper/InternalTensorInfo;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeGetInputTensorInfo(
+ JNIEnv *, jobject, jlong, jint, jobject);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeGetOutputTensorInfo
+ * Signature: (JILcom/samsung/onert/NativeSessionWrapper/InternalTensorInfo;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeGetOutputTensorInfo(
+ JNIEnv *, jobject, jlong, jint, jobject);
+
+/*
+ * Class: com_samsung_onert_NativeSessionWrapper
+ * Method: nativeSetAvailableBackends
+ * Signature: (JLjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_samsung_onert_NativeSessionWrapper_nativeSetAvailableBackends(
+ JNIEnv *, jobject, jlong, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/runtime/contrib/android/api/src/main/native/onert-native-helper.cpp b/runtime/contrib/android/api/src/main/native/onert-native-helper.cpp
new file mode 100644
index 000000000..e6b63aa10
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/native/onert-native-helper.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "onert-native-helper.h"
+
+#include <android/log.h>
+
+namespace
+{
+
+// android log tag
+const char *TAG = "ONERT_NATIVE";
+
+bool g_reflect_cached = false;
+struct ReflectInfo
+{
+ jclass info;
+ jfieldID type;
+ jfieldID rank;
+ jfieldID shape;
+};
+ReflectInfo g_cached_reflect_info;
+
+jboolean cacheReflectInfo(JNIEnv *env)
+{
+ jclass info_cls = env->FindClass("com/samsung/onert/NativeSessionWrapper$InternalTensorInfo");
+ if (info_cls == nullptr)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] java info class is failed",
+ __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ jfieldID type_fld = env->GetFieldID(info_cls, "type", "I");
+ if (type_fld == nullptr)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] TensorInfo's type field id is failed",
+ __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ jfieldID rank_fld = env->GetFieldID(info_cls, "rank", "I");
+ if (rank_fld == nullptr)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] TensorInfo's rank field id is failed",
+ __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ jfieldID shape_fld = env->GetFieldID(info_cls, "shape", "[I");
+ if (shape_fld == nullptr)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] TensorInfo's shape field id is failed",
+ __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ g_cached_reflect_info.info = info_cls;
+ g_cached_reflect_info.type = type_fld;
+ g_cached_reflect_info.rank = rank_fld;
+ g_cached_reflect_info.shape = shape_fld;
+ g_reflect_cached = true;
+ return JNI_TRUE;
+}
+
+} // namespace
+
+namespace jni_helper
+{
+
+jboolean verifyHandle(jlong handle)
+{
+ if (handle == 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] handle is null", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jboolean getTensorParams(JNIEnv *env, jint jindex, jint jtype, jobject jbuf, jint jbufsize,
+ jni::TensorParams &params)
+{
+ if (jindex < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] index(%d) is wrong", __PRETTY_FUNCTION__,
+ jindex);
+ return JNI_FALSE;
+ }
+ params.index = static_cast<uint32_t>(jindex);
+
+ if (jtype < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] type(%d) is wrong", __PRETTY_FUNCTION__,
+ jtype);
+ return JNI_FALSE;
+ }
+ params.type = static_cast<NNFW_TYPE>(jtype);
+
+ jbyte *buffer = reinterpret_cast<jbyte *>(env->GetDirectBufferAddress(jbuf));
+ if (buffer == nullptr)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] buffer is null", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+ params.buffer = buffer;
+
+ if (jbufsize < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] length(%d) is wrong", __PRETTY_FUNCTION__,
+ jbufsize);
+ return JNI_FALSE;
+ }
+ params.buffer_size = static_cast<size_t>(jbufsize);
+
+ return JNI_TRUE;
+}
+
+jboolean getLayoutParams(jint jindex, jint jlayout, jni::LayoutParams &params)
+{
+ if (jindex < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] index(%d) is wrong", __PRETTY_FUNCTION__,
+ jindex);
+ return JNI_FALSE;
+ }
+ params.index = static_cast<uint32_t>(jindex);
+
+ if (jlayout < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] layout(%d) is wrong", __PRETTY_FUNCTION__,
+ jlayout);
+ return JNI_FALSE;
+ }
+ params.layout = static_cast<NNFW_LAYOUT>(jlayout);
+
+ return JNI_TRUE;
+}
+
+jboolean setTensorInfoToJava(JNIEnv *env, const nnfw_tensorinfo &tensor_info, jobject jinfo)
+{
+ if (g_reflect_cached == false)
+ {
+ if (cacheReflectInfo(env) == JNI_FALSE)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+ }
+
+ jclass info_cls = g_cached_reflect_info.info;
+
+ jfieldID type_fld = g_cached_reflect_info.type;
+ jint jtype = static_cast<jint>(tensor_info.dtype);
+ env->SetIntField(jinfo, type_fld, jtype);
+
+ jfieldID rank_fld = g_cached_reflect_info.rank;
+ jint jrank = tensor_info.rank;
+ env->SetIntField(jinfo, rank_fld, jrank);
+
+ jfieldID shape_fld = g_cached_reflect_info.shape;
+ jintArray jshape = env->NewIntArray(jrank);
+ if (jshape == nullptr)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] TensorInfo's shape[] allocation is failed",
+ __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+ env->SetIntArrayRegion(jshape, 0, jrank, (tensor_info.dims));
+ env->SetObjectField(jinfo, shape_fld, jshape);
+
+ return JNI_TRUE;
+}
+
+jboolean getInputTensorInfo(jlong handle, jint jindex, jni::TensorInfo &info)
+{
+ if (jindex < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] index(%d) is wrong", __PRETTY_FUNCTION__,
+ jindex);
+ return JNI_FALSE;
+ }
+ auto index = static_cast<uint32_t>(jindex);
+
+ if (jni::getInputTensorInfo(handle, index, info) == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+jboolean getOutputTensorInfo(jlong handle, jint jindex, jni::TensorInfo &info)
+{
+ if (jindex < 0)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] index(%d) is wrong", __PRETTY_FUNCTION__,
+ jindex);
+ return JNI_FALSE;
+ }
+ auto index = static_cast<uint32_t>(jindex);
+
+ if (jni::getOutputTensorInfo(handle, index, info) == false)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, TAG, "%s] failed", __PRETTY_FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+} // namespace jni_helper
diff --git a/runtime/contrib/android/api/src/main/native/onert-native-helper.h b/runtime/contrib/android/api/src/main/native/onert-native-helper.h
new file mode 100644
index 000000000..3b350ca1c
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/native/onert-native-helper.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <jni.h>
+
+#include "onert-native-internal.h"
+
+namespace jni_helper
+{
+
+jboolean verifyHandle(jlong handle);
+jboolean getTensorParams(JNIEnv *env, jint jindex, jint jtype, jobject jbuf, jint jbufsize,
+ jni::TensorParams &params);
+jboolean getLayoutParams(jint jindex, jint jlayout, jni::LayoutParams &params);
+jboolean setTensorInfoToJava(JNIEnv *env, const nnfw_tensorinfo &tensor_info, jobject jinfo);
+jboolean getInputTensorInfo(jlong handle, jint jindex, jni::TensorInfo &info);
+jboolean getOutputTensorInfo(jlong handle, jint jindex, jni::TensorInfo &info);
+
+} // namespace jni_helper
diff --git a/runtime/contrib/android/api/src/main/native/onert-native-internal.cpp b/runtime/contrib/android/api/src/main/native/onert-native-internal.cpp
new file mode 100644
index 000000000..120ca4a99
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/native/onert-native-internal.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "onert-native-internal.h"
+
+namespace
+{
+
+inline nnfw_session *getSession(Handle handle) { return reinterpret_cast<nnfw_session *>(handle); }
+
+size_t getByteSizeOfDataType(NNFW_TYPE dtype)
+{
+ size_t size = 0;
+ switch (dtype)
+ {
+ case NNFW_TYPE_TENSOR_FLOAT32:
+ case NNFW_TYPE_TENSOR_INT32:
+ size = 4;
+ break;
+ case NNFW_TYPE_TENSOR_QUANT8_ASYMM:
+ case NNFW_TYPE_TENSOR_BOOL:
+ case NNFW_TYPE_TENSOR_UINT8:
+ size = 1;
+ break;
+ default:
+ break;
+ }
+ return size;
+}
+
+size_t getByteSize(const nnfw_tensorinfo &tensor_info)
+{
+ size_t size = getByteSizeOfDataType(tensor_info.dtype);
+ for (auto i = 0; i < tensor_info.rank; ++i)
+ {
+ size *= tensor_info.dims[i];
+ }
+ return size;
+}
+
+} // namespace
+
+namespace jni
+{
+
+Handle createSession()
+{
+ nnfw_session *sess = nullptr;
+ if (nnfw_create_session(&sess) == NNFW_STATUS_ERROR)
+ {
+ return 0; // nullptr
+ }
+ return reinterpret_cast<Handle>(sess);
+}
+
+void closeSession(Handle handle)
+{
+ nnfw_session *sess = getSession(handle);
+ nnfw_close_session(sess);
+}
+
+bool loadModel(Handle handle, const char *nnpkg_path)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_load_model_from_file(sess, nnpkg_path) == NNFW_STATUS_NO_ERROR);
+}
+
+bool prepare(Handle handle)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_prepare(sess) == NNFW_STATUS_NO_ERROR);
+}
+
+bool run(Handle handle)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_run(sess) == NNFW_STATUS_NO_ERROR);
+}
+
+bool setInput(Handle handle, const TensorParams &params)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_set_input(sess, params.index, params.type, params.buffer, params.buffer_size) ==
+ NNFW_STATUS_NO_ERROR);
+}
+
+bool setOutput(Handle handle, TensorParams &params)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_set_output(sess, params.index, params.type, params.buffer, params.buffer_size) ==
+ NNFW_STATUS_NO_ERROR);
+}
+
+bool setInputLayout(Handle handle, const LayoutParams &params)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_set_input_layout(sess, params.index, params.layout) == NNFW_STATUS_NO_ERROR);
+}
+
+bool setOutputLayout(Handle handle, const LayoutParams &params)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_set_output_layout(sess, params.index, params.layout) == NNFW_STATUS_NO_ERROR);
+}
+
+int getInputSize(Handle handle)
+{
+ nnfw_session *sess = getSession(handle);
+ uint32_t size = 0;
+ if (nnfw_input_size(sess, &size) == NNFW_STATUS_NO_ERROR)
+ return static_cast<int>(size);
+ else
+ return -1;
+}
+
+int getOutputSize(Handle handle)
+{
+ nnfw_session *sess = getSession(handle);
+ uint32_t size = 0;
+ if (nnfw_output_size(sess, &size) == NNFW_STATUS_NO_ERROR)
+ return static_cast<int>(size);
+ else
+ return -1;
+}
+
+bool setAvailableBackends(Handle handle, const char *backends)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_set_available_backends(sess, backends) == NNFW_STATUS_NO_ERROR);
+}
+
+bool getInputTensorInfo(Handle handle, uint32_t index, TensorInfo &info)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_input_tensorinfo(sess, index, &info) == NNFW_STATUS_NO_ERROR);
+}
+
+bool getOutputTensorInfo(Handle handle, uint32_t index, TensorInfo &info)
+{
+ nnfw_session *sess = getSession(handle);
+ return (nnfw_output_tensorinfo(sess, index, &info) == NNFW_STATUS_NO_ERROR);
+}
+
+} // namespace jni
diff --git a/runtime/contrib/android/api/src/main/native/onert-native-internal.h b/runtime/contrib/android/api/src/main/native/onert-native-internal.h
new file mode 100644
index 000000000..0cb1866ac
--- /dev/null
+++ b/runtime/contrib/android/api/src/main/native/onert-native-internal.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Independent from jni
+#pragma once
+
+// onert
+#include <nnfw.h> // TODO change nnfw.h to onert.h
+
+// from jni_md.h
+#ifdef _LP64 /* 64-bit Solaris */
+typedef long Handle;
+#else
+typedef long long Handle;
+#endif
+
+namespace jni
+{
+
+struct TensorParams
+{
+ uint32_t index;
+ NNFW_TYPE type;
+ void *buffer;
+ size_t buffer_size;
+};
+
+struct LayoutParams
+{
+ uint32_t index;
+ NNFW_LAYOUT layout;
+};
+
+using TensorInfo = nnfw_tensorinfo;
+
+Handle createSession();
+void closeSession(Handle handle);
+bool loadModel(Handle handle, const char *nnpkg_path);
+bool prepare(Handle handle);
+bool run(Handle handle);
+bool setInput(Handle handle, const TensorParams &params);
+bool setOutput(Handle handle, TensorParams &params);
+bool setInputLayout(Handle handle, const LayoutParams &params);
+bool setOutputLayout(Handle handle, const LayoutParams &params);
+int getInputSize(Handle handle);
+int getOutputSize(Handle handle);
+bool setAvailableBackends(Handle handle, const char *backends);
+bool getInputTensorInfo(Handle handle, uint32_t index, TensorInfo &info);
+bool getOutputTensorInfo(Handle handle, uint32_t index, TensorInfo &info);
+
+} // namespace jni
diff --git a/runtime/contrib/android/build.gradle b/runtime/contrib/android/build.gradle
new file mode 100644
index 000000000..663eb78f7
--- /dev/null
+++ b/runtime/contrib/android/build.gradle
@@ -0,0 +1,31 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+
+ repositories {
+ google()
+ jcenter()
+
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.6.2'
+
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+ delete "${rootDir}/api/build"
+ delete "${rootDir}/api/.cxx"
+}
diff --git a/runtime/contrib/android/gradle.properties b/runtime/contrib/android/gradle.properties
new file mode 100644
index 000000000..d196f51b9
--- /dev/null
+++ b/runtime/contrib/android/gradle.properties
@@ -0,0 +1,2 @@
+android.useAndroidX=false
+android.enableJetifier=false
diff --git a/runtime/contrib/android/gradle/wrapper/gradle-wrapper.jar b/runtime/contrib/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..490fda857
--- /dev/null
+++ b/runtime/contrib/android/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/runtime/contrib/android/gradle/wrapper/gradle-wrapper.properties b/runtime/contrib/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..a4b442974
--- /dev/null
+++ b/runtime/contrib/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/runtime/contrib/android/gradlew b/runtime/contrib/android/gradlew
new file mode 100755
index 000000000..2fe81a7d9
--- /dev/null
+++ b/runtime/contrib/android/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/runtime/contrib/android/gradlew.bat b/runtime/contrib/android/gradlew.bat
new file mode 100644
index 000000000..62bd9b9cc
--- /dev/null
+++ b/runtime/contrib/android/gradlew.bat
@@ -0,0 +1,103 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/runtime/contrib/android/settings.gradle b/runtime/contrib/android/settings.gradle
new file mode 100644
index 000000000..ca51add78
--- /dev/null
+++ b/runtime/contrib/android/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'onert android api'
+include ':api'
diff --git a/runtime/contrib/android/update_jni_header.sh b/runtime/contrib/android/update_jni_header.sh
new file mode 100755
index 000000000..3b5324131
--- /dev/null
+++ b/runtime/contrib/android/update_jni_header.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -x
+set -e
+
+./gradlew assembleRelease -x externalNativeBuildRelease
+
+pushd api/build/intermediates/javac/release/classes
+javah com.samsung.onert.NativeSessionWrapper
+popd
+
+mv -vf api/build/intermediates/javac/release/classes/com_samsung_onert_NativeSessionWrapper.h api/src/main/native/onert-native-api.h
diff --git a/runtime/contrib/android_benchmark_app/AndroidManifest.xml b/runtime/contrib/android_benchmark_app/AndroidManifest.xml
new file mode 100644
index 000000000..f0b967cfa
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.ndk.tflbench" >
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name="com.ndk.tflbench.MainActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/runtime/contrib/android_benchmark_app/CMakeLists.txt b/runtime/contrib/android_benchmark_app/CMakeLists.txt
new file mode 100644
index 000000000..beb279cb9
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/CMakeLists.txt
@@ -0,0 +1,97 @@
+if(NOT BUILD_ANDROID_BENCHMARK_APP)
+ return()
+endif(NOT BUILD_ANDROID_BENCHMARK_APP)
+
+if(NOT ANDROID)
+ message(STATUS "Sample app is disabled as non-Android build")
+ return()
+endif()
+
+if(NOT DEFINED ANDROID_BUILD_TOOLS_DIR)
+ message(STATUS "Sample app is disabled as ANDROID_BUILD_TOOLS_DIR is not defined")
+ return()
+endif()
+
+if(NOT DEFINED ANDROID_SDK_DIR)
+ message(STATUS "Sample app is disabled as ANDROID_SDK_DIR is not defined")
+ return()
+endif()
+
+if(NOT DEFINED TFLITE_MODEL_PATH)
+ message(STATUS "Sample app is disabled as TFLITE_MODEL_PATH is not defined")
+ return()
+endif()
+
+nnfw_find_package(ARMCompute REQUIRED)
+
+if(NOT CORE_LIBRARY OR NOT RUNTIME_LIBRARY)
+ message(STATUS "Sample app is disabled as ARM Compute Library is missing")
+ return()
+endif()
+
+get_filename_component(TFLITE_MODEL_FILENAME ${TFLITE_MODEL_PATH} NAME)
+
+set(ANDROID_API_VERSION 27)
+set(ANDROID_PLATFORM_DIR ${ANDROID_SDK_DIR}/platforms/android-${ANDROID_API_VERSION})
+
+set(GEN_DIR ${CMAKE_CURRENT_BINARY_DIR}/gen)
+set(OBJ_DIR ${CMAKE_CURRENT_BINARY_DIR}/obj)
+set(PKG_DIR ${CMAKE_CURRENT_BINARY_DIR}/pkg)
+set(LIB_DIR ${PKG_DIR}/lib/arm64-v8a)
+set(ASSETS_DIR ${PKG_DIR}/assets)
+set(SRC_LIST ${CMAKE_CURRENT_BINARY_DIR}/src.list)
+
+if (ANDROID_BOOST_ROOT)
+ set(BOOST_ROOT ${ANDROID_BOOST_ROOT})
+endif (ANDROID_BOOST_ROOT)
+
+nnfw_find_package(Boost REQUIRED)
+
+add_library(android_benchmark_native SHARED cpp/ndk_main.cpp)
+target_compile_definitions(android_benchmark_native PRIVATE MODEL_NAME="${TFLITE_MODEL_FILENAME}")
+target_include_directories(android_benchmark_native PRIVATE ${NNAS_EXTERNALS_DIR}/tensorflow)
+target_include_directories(android_benchmark_native PRIVATE ${Boost_INCLUDE_DIRS})
+target_link_libraries(android_benchmark_native nnfw_lib_tflite)
+target_link_libraries(android_benchmark_native nnfw_lib_misc)
+target_link_libraries(android_benchmark_native log)
+
+nnas_find_package(FlatBuffersSource EXACT 1.12 REQUIRED)
+target_include_directories(android_benchmark_native PUBLIC ${FlatBuffersSource_DIR}/include .)
+
+add_custom_target(android-benchmark-apk ALL
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${GEN_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${GEN_DIR}
+ COMMAND ${ANDROID_BUILD_TOOLS_DIR}/aapt package -m -J ${GEN_DIR}
+ -M ${CMAKE_CURRENT_SOURCE_DIR}/AndroidManifest.xml
+ -S ${CMAKE_CURRENT_SOURCE_DIR}/res
+ -I ${ANDROID_PLATFORM_DIR}/android.jar
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${OBJ_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${OBJ_DIR}
+ COMMAND ${CMAKE_COMMAND} -E remove -f ${SRC_LIST}
+ COMMAND find ${CMAKE_CURRENT_SOURCE_DIR}/java -name '*.java' >> ${SRC_LIST}
+ COMMAND find ${GEN_DIR} -name '*.java' >> ${SRC_LIST}
+ COMMAND javac -d ${OBJ_DIR} -source 1.7 -target 1.7 -bootclasspath "${JAVA_HOME}/jre/lib/rt.jar"
+ -classpath ${ANDROID_PLATFORM_DIR}/android.jar @${SRC_LIST}
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${PKG_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PKG_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${ASSETS_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${TFLITE_MODEL_PATH} ${ASSETS_DIR}/model.tflite
+ COMMAND ${ANDROID_BUILD_TOOLS_DIR}/dx --dex --output=${PKG_DIR}/classes.dex ${OBJ_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CORE_LIBRARY} ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${RUNTIME_LIBRARY} ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:android_benchmark_native> ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:onert> ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:onert_backend_acl_cl> ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:arm_compute_ex> ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:onert_backend_acl_neon> ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:onert_backend_cpu> ${LIB_DIR}
+ COMMAND ${CMAKE_COMMAND} -E echo ${ANDROID_BUILD_TOOLS_DIR}/aapt package -f -0 tflite -M ${CMAKE_CURRENT_SOURCE_DIR}/AndroidManifest.xml -S ${CMAKE_CURRENT_SOURCE_DIR}/res/ -I ${ANDROID_PLATFORM_DIR}/android.jar -F ${CMAKE_CURRENT_BINARY_DIR}/android-benchmark.unsigned.pkg ${PKG_DIR}
+ COMMAND ${ANDROID_BUILD_TOOLS_DIR}/aapt package -f
+ -0 tflite
+ -M ${CMAKE_CURRENT_SOURCE_DIR}/AndroidManifest.xml
+ -S ${CMAKE_CURRENT_SOURCE_DIR}/res/
+ -I ${ANDROID_PLATFORM_DIR}/android.jar
+ -F ${CMAKE_CURRENT_BINARY_DIR}/android-benchmark.unsigned.pkg
+ ${PKG_DIR}
+ DEPENDS android_benchmark_native onert onert_backend_acl_cl onert_backend_acl_neon onert_backend_cpu)
diff --git a/runtime/contrib/android_benchmark_app/README.md b/runtime/contrib/android_benchmark_app/README.md
new file mode 100644
index 000000000..19640e32f
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/README.md
@@ -0,0 +1,58 @@
+# Android Benchmark App
+
+An Android sample app that run `.tflite` and measure performance.
+
+You can run with two engines.
+
+- Tensorflow Lite Interpreter
+- NN API Delegate (onert)
+
+## Build
+
+In addition to aarch64-Android build, you need to specify more parameters.
+
+- `ANDROID_BUILD_TOOLS_DIR` : Android `build-tools` directory (You may find it in Android SDK directory)
+- `ANDROID_SDK_DIR` : Android SDK directory
+- `TFLITE_MODEL_PATH` : A model to run (Only one model can be packed)
+- `ANDROID_BOOST_ROOT` : Boost library root path
+ - This repo should contain `lib` and `include` directory
+ - How to build Boost for Android - Build with [this repo](https://github.com/moritz-wundke/Boost-for-Android)
+
+Example:
+
+```bash
+make TARGET_OS=android \
+ CROSS_BUILD=1 \
+ BUILD_TYPE=RELEASE \
+ NDK_DIR=/home/hanjoung/ws/android-tools/r20/ndk \
+ EXT_ACL_FOLDER=/home/hanjoung/ws/temp/arm_compute-v19.05-bin-android/lib/android-arm64-v8a-neon-cl \
+ ANDROID_BUILD_TOOLS_DIR=/home/hanjoung/ws/android-tools/sdk/build-tools/27.0.3/ \
+ ANDROID_SDK_DIR=/home/hanjoung/ws/android-tools/sdk \
+ TFLITE_MODEL_PATH=/Users/hanjoung/ws/ghent/STAR/nnfw/tests/scripts/models/cache/MODELS/mobilenet/mobilenet_v1_0.25_128.tflite \
+ ANDROID_BOOST_ROOT=/home/hanjoung/ws/gh/moritz-wundke/Boost-for-Android/build/out/arm64-v8a
+```
+
+And you will get `obj/contrib/android_benchmark_app/android-benchmark.unsigned.pkg`. This is an unsigned Android app package.
+
+## Sign APK
+
+Before installing the package you probably need to sign the package.
+
+- `apksigner` : This is in `build-tools` directory
+- Your keystore : How-to is TBD
+
+```bash
+apksigner sign \
+ --ks ~/.android/debug.keystore \
+ --in Product/aarch64-android.release/obj/contrib/android_benchmark_app/android-benchmark.unsigned.pkg \
+ --out tflbench.apk
+```
+
+You should enter the keystore password. Then you will get `tflbench.apk`.
+
+## Install APK
+
+```bash
+adb install tflbench.apk
+adb uninstall com.ndk.tflbench # To uninstall
+```
diff --git a/runtime/contrib/android_benchmark_app/cpp/ndk_main.cpp b/runtime/contrib/android_benchmark_app/cpp/ndk_main.cpp
new file mode 100644
index 000000000..4b0e4395f
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/cpp/ndk_main.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ndk_main.h"
+
+#include "tensorflow/lite/kernels/register.h"
+#include "tensorflow/lite/model.h"
+
+#include "tflite/Assert.h"
+#include "tflite/Session.h"
+#include "tflite/InterpreterSession.h"
+#include "tflite/NNAPISession.h"
+#include "tflite/ext/kernels/register.h"
+
+#include "misc/benchmark.h"
+
+#include <boost/accumulators/accumulators.hpp>
+#include <boost/accumulators/statistics/stats.hpp>
+#include <boost/accumulators/statistics/mean.hpp>
+#include <boost/accumulators/statistics/min.hpp>
+#include <boost/accumulators/statistics/max.hpp>
+
+#include <cassert>
+#include <chrono>
+#include <sstream>
+
+#include <android/log.h>
+
+using namespace tflite;
+using namespace tflite::ops::builtin;
+
+static StderrReporter error_reporter;
+
+static std::unique_ptr<FlatBufferModel> model;
+
+inline void setText(JNIEnv *env, jobject thisObj, const std::string &message)
+{
+ jclass thisClass = env->GetObjectClass(thisObj);
+ jmethodID setTextMethod = env->GetMethodID(thisClass, "setText", "(Ljava/lang/String;)V");
+
+ assert(setTextMethod != nullptr);
+
+ env->CallVoidMethod(thisObj, setTextMethod, env->NewStringUTF(message.c_str()));
+}
+
+inline void setTitle(JNIEnv *env, jobject thisObj, const std::string &message)
+{
+ jclass thisClass = env->GetObjectClass(thisObj);
+ jmethodID setTextMethod = env->GetMethodID(thisClass, "setTitle", "(Ljava/lang/String;)V");
+
+ assert(setTextMethod != nullptr);
+
+ env->CallVoidMethod(thisObj, setTextMethod, env->NewStringUTF(message.c_str()));
+
+ // Clear message
+ setText(env, thisObj, "");
+}
+
+inline void setText(JNIEnv *env, jobject thisObj, const std::stringstream &ss)
+{
+ setText(env, thisObj, ss.str());
+}
+
+inline std::unique_ptr<FlatBufferModel> loadModel(JNIEnv *env, jobject thisObj,
+ jobject model_buffer)
+{
+ const char *model_base = static_cast<char *>(env->GetDirectBufferAddress(model_buffer));
+ jlong model_size = env->GetDirectBufferCapacity(model_buffer);
+
+ return FlatBufferModel::BuildFromBuffer(model_base, static_cast<size_t>(model_size),
+ &error_reporter);
+}
+
+struct Activity
+{
+ virtual ~Activity() = default;
+
+ virtual void prepare(void) const = 0;
+ virtual void run(void) const = 0;
+ virtual void teardown(void) const = 0;
+};
+
+struct LiteActivity final : public Activity
+{
+public:
+ LiteActivity(nnfw::tflite::Session &sess) : _sess(sess)
+ {
+ // DO NOTHING
+ }
+
+public:
+ void prepare(void) const override { _sess.prepare(); }
+ void run(void) const override { _sess.run(); }
+ void teardown(void) const override { _sess.teardown(); }
+
+private:
+ nnfw::tflite::Session &_sess;
+};
+
+struct SimpleActivity final : public Activity
+{
+public:
+ SimpleActivity(const std::function<void(void)> &fn) : _fn{fn}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void prepare(void) const override {}
+ void run(void) const override { _fn(); }
+ void teardown(void) const override {}
+
+private:
+ std::function<void(void)> _fn;
+};
+
+inline void runBenchmark(JNIEnv *env, jobject thisObj, Activity &act)
+{
+ auto runTrial = [&](void) {
+ std::chrono::milliseconds elapsed(0);
+
+ act.prepare();
+ nnfw::misc::benchmark::measure(elapsed) << [&](void) { act.run(); };
+ act.teardown();
+
+ return elapsed;
+ };
+
+ // Warm-up
+ for (uint32_t n = 0; n < 3; ++n)
+ {
+ auto elapsed = runTrial();
+
+ std::stringstream ss;
+ ss << "Warm-up #" << n << " takes " << elapsed.count() << "ms" << std::endl;
+ setText(env, thisObj, ss);
+ }
+
+ // Measure
+ using namespace boost::accumulators;
+
+ accumulator_set<double, stats<tag::mean, tag::min, tag::max>> acc;
+
+ for (uint32_t n = 0; n < 100; ++n)
+ {
+ auto elapsed = runTrial();
+
+ std::stringstream ss;
+ ss << "Iteration #" << n << " takes " << elapsed.count() << "ms" << std::endl;
+ setText(env, thisObj, ss);
+
+ acc(elapsed.count());
+ }
+
+ std::stringstream ss;
+ ss << "Average is " << mean(acc) << "ms" << std::endl;
+ ss << "Min is " << min(acc) << "ms" << std::endl;
+ ss << "Max is " << max(acc) << "ms" << std::endl;
+ setText(env, thisObj, ss);
+}
+
+JNIEXPORT void JNICALL Java_com_ndk_tflbench_MainActivity_runInterpreterBenchmark(
+ JNIEnv *env, jobject thisObj, jobject model_buffer)
+{
+ setTitle(env, thisObj, "Running Interpreter Benchmark");
+
+ auto model = loadModel(env, thisObj, model_buffer);
+ assert(model != nullptr);
+
+ nnfw::tflite::BuiltinOpResolver resolver;
+ InterpreterBuilder builder(*model, resolver);
+
+ std::unique_ptr<Interpreter> interpreter;
+
+ TFLITE_ENSURE(builder(&interpreter));
+
+ interpreter->SetNumThreads(-1);
+
+ nnfw::tflite::InterpreterSession sess(interpreter.get());
+ LiteActivity act{sess};
+ runBenchmark(env, thisObj, act);
+}
+
+static void runNNAPIBenchmark(JNIEnv *env, jobject thisObj, jobject model_buffer)
+{
+ auto model = loadModel(env, thisObj, model_buffer);
+ assert(model != nullptr);
+
+ nnfw::tflite::BuiltinOpResolver resolver;
+ InterpreterBuilder builder(*model, resolver);
+
+ std::unique_ptr<Interpreter> interpreter;
+
+ TFLITE_ENSURE(builder(&interpreter));
+
+ nnfw::tflite::NNAPISession sess(interpreter.get());
+ LiteActivity act{sess};
+ runBenchmark(env, thisObj, act);
+}
+
+JNIEXPORT void JNICALL Java_com_ndk_tflbench_MainActivity_runNNAPIBenchmark(JNIEnv *env,
+ jobject thisObj,
+ jobject model_buffer)
+{
+ setTitle(env, thisObj, "Running NNAPI Benchmark");
+
+ try
+ {
+ runNNAPIBenchmark(env, thisObj, model_buffer);
+ }
+ catch (const std::exception &ex)
+ {
+ std::stringstream ss;
+ ss << "Caught an exception " << ex.what();
+ setText(env, thisObj, ss);
+ }
+}
+
+JNIEXPORT jstring JNICALL Java_com_ndk_tflbench_MainActivity_getModelName(JNIEnv *env,
+ jobject thisObj)
+{
+ return env->NewStringUTF(MODEL_NAME);
+}
+
+#define TF_ENSURE(e) \
+ { \
+ if (!(e).ok()) \
+ { \
+ throw std::runtime_error{"'" #e "' FAILED"}; \
+ } \
+ }
diff --git a/runtime/contrib/android_benchmark_app/cpp/ndk_main.h b/runtime/contrib/android_benchmark_app/cpp/ndk_main.h
new file mode 100644
index 000000000..8f2969870
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/cpp/ndk_main.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_ndk_tflbench_MainActivity */
+
+#ifndef _Included_com_ndk_tflbench_MainActivity
+#define _Included_com_ndk_tflbench_MainActivity
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef com_ndk_tflbench_MainActivity_BIND_ABOVE_CLIENT
+#define com_ndk_tflbench_MainActivity_BIND_ABOVE_CLIENT 8L
+#undef com_ndk_tflbench_MainActivity_BIND_ADJUST_WITH_ACTIVITY
+#define com_ndk_tflbench_MainActivity_BIND_ADJUST_WITH_ACTIVITY 128L
+#undef com_ndk_tflbench_MainActivity_BIND_ALLOW_OOM_MANAGEMENT
+#define com_ndk_tflbench_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
+#undef com_ndk_tflbench_MainActivity_BIND_AUTO_CREATE
+#define com_ndk_tflbench_MainActivity_BIND_AUTO_CREATE 1L
+#undef com_ndk_tflbench_MainActivity_BIND_DEBUG_UNBIND
+#define com_ndk_tflbench_MainActivity_BIND_DEBUG_UNBIND 2L
+#undef com_ndk_tflbench_MainActivity_BIND_EXTERNAL_SERVICE
+#define com_ndk_tflbench_MainActivity_BIND_EXTERNAL_SERVICE -2147483648L
+#undef com_ndk_tflbench_MainActivity_BIND_IMPORTANT
+#define com_ndk_tflbench_MainActivity_BIND_IMPORTANT 64L
+#undef com_ndk_tflbench_MainActivity_BIND_NOT_FOREGROUND
+#define com_ndk_tflbench_MainActivity_BIND_NOT_FOREGROUND 4L
+#undef com_ndk_tflbench_MainActivity_BIND_WAIVE_PRIORITY
+#define com_ndk_tflbench_MainActivity_BIND_WAIVE_PRIORITY 32L
+#undef com_ndk_tflbench_MainActivity_CONTEXT_IGNORE_SECURITY
+#define com_ndk_tflbench_MainActivity_CONTEXT_IGNORE_SECURITY 2L
+#undef com_ndk_tflbench_MainActivity_CONTEXT_INCLUDE_CODE
+#define com_ndk_tflbench_MainActivity_CONTEXT_INCLUDE_CODE 1L
+#undef com_ndk_tflbench_MainActivity_CONTEXT_RESTRICTED
+#define com_ndk_tflbench_MainActivity_CONTEXT_RESTRICTED 4L
+#undef com_ndk_tflbench_MainActivity_MODE_APPEND
+#define com_ndk_tflbench_MainActivity_MODE_APPEND 32768L
+#undef com_ndk_tflbench_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING
+#define com_ndk_tflbench_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L
+#undef com_ndk_tflbench_MainActivity_MODE_MULTI_PROCESS
+#define com_ndk_tflbench_MainActivity_MODE_MULTI_PROCESS 4L
+#undef com_ndk_tflbench_MainActivity_MODE_NO_LOCALIZED_COLLATORS
+#define com_ndk_tflbench_MainActivity_MODE_NO_LOCALIZED_COLLATORS 16L
+#undef com_ndk_tflbench_MainActivity_MODE_PRIVATE
+#define com_ndk_tflbench_MainActivity_MODE_PRIVATE 0L
+#undef com_ndk_tflbench_MainActivity_MODE_WORLD_READABLE
+#define com_ndk_tflbench_MainActivity_MODE_WORLD_READABLE 1L
+#undef com_ndk_tflbench_MainActivity_MODE_WORLD_WRITEABLE
+#define com_ndk_tflbench_MainActivity_MODE_WORLD_WRITEABLE 2L
+#undef com_ndk_tflbench_MainActivity_RECEIVER_VISIBLE_TO_INSTANT_APPS
+#define com_ndk_tflbench_MainActivity_RECEIVER_VISIBLE_TO_INSTANT_APPS 1L
+#undef com_ndk_tflbench_MainActivity_DEFAULT_KEYS_DIALER
+#define com_ndk_tflbench_MainActivity_DEFAULT_KEYS_DIALER 1L
+#undef com_ndk_tflbench_MainActivity_DEFAULT_KEYS_DISABLE
+#define com_ndk_tflbench_MainActivity_DEFAULT_KEYS_DISABLE 0L
+#undef com_ndk_tflbench_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL
+#define com_ndk_tflbench_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
+#undef com_ndk_tflbench_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL
+#define com_ndk_tflbench_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
+#undef com_ndk_tflbench_MainActivity_DEFAULT_KEYS_SHORTCUT
+#define com_ndk_tflbench_MainActivity_DEFAULT_KEYS_SHORTCUT 2L
+#undef com_ndk_tflbench_MainActivity_RESULT_CANCELED
+#define com_ndk_tflbench_MainActivity_RESULT_CANCELED 0L
+#undef com_ndk_tflbench_MainActivity_RESULT_FIRST_USER
+#define com_ndk_tflbench_MainActivity_RESULT_FIRST_USER 1L
+#undef com_ndk_tflbench_MainActivity_RESULT_OK
+#define com_ndk_tflbench_MainActivity_RESULT_OK -1L
+/*
+ * Class: com_ndk_tflbench_MainActivity
+ * Method: getModelName
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ndk_tflbench_MainActivity_getModelName(JNIEnv *, jobject);
+
+/*
+ * Class: com_ndk_tflbench_MainActivity
+ * Method: runInterpreterBenchmark
+ * Signature: (Ljava/nio/MappedByteBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_ndk_tflbench_MainActivity_runInterpreterBenchmark(JNIEnv *, jobject,
+ jobject);
+
+/*
+ * Class: com_ndk_tflbench_MainActivity
+ * Method: runNNAPIBenchmark
+ * Signature: (Ljava/nio/MappedByteBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_ndk_tflbench_MainActivity_runNNAPIBenchmark(JNIEnv *, jobject,
+ jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/runtime/contrib/android_benchmark_app/java/com/ndk/tflbench/MainActivity.java b/runtime/contrib/android_benchmark_app/java/com/ndk/tflbench/MainActivity.java
new file mode 100644
index 000000000..14bf239a6
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/java/com/ndk/tflbench/MainActivity.java
@@ -0,0 +1,110 @@
+package com.ndk.tflbench;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.content.Intent;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.TextView;
+import android.widget.Button;
+import android.net.Uri;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.Vector;
+
+public class MainActivity extends Activity {
+
+ static {
+ System.loadLibrary("android_benchmark_native");
+ }
+
+ private void setModel(final String message) {
+ final TextView textView = (TextView)findViewById(R.id.model_label);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() { textView.setText(message); }
+ });
+ }
+
+ private void setTitle(final String message) {
+ final TextView textView = (TextView)findViewById(R.id.title_label);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() { textView.setText(message); }
+ });
+ }
+
+ private void setText(final String message) {
+ final TextView textView = (TextView)findViewById(R.id.message_label);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() { textView.setText(message); }
+ });
+ }
+
+ private MappedByteBuffer buffer;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ setModel(getModelName());
+
+ // Load Tensorflow Lite model
+ try
+ {
+ AssetManager assets = getAssets();
+ AssetFileDescriptor fileDescriptor = assets.openFd("model.tflite");
+ FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
+ FileChannel fileChannel = inputStream.getChannel();
+ final long startOffset = fileDescriptor.getStartOffset();
+ final long declaredLength = fileDescriptor.getDeclaredLength();
+
+ buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
+ } catch (IOException e) {
+ Log.e("MYAPP", "exception", e);
+ }
+
+ Button btn_interp = (Button)findViewById(R.id.button_interp);
+ btn_interp.setOnClickListener(new Button.OnClickListener() {
+ @Override public void onClick(View view) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() { runInterpreterBenchmark(buffer); }
+ }).start();
+ }
+ });
+
+ Button btn_nnapi = (Button)findViewById(R.id.button_nnapi);
+ btn_nnapi.setOnClickListener(new Button.OnClickListener() {
+ @Override public void onClick(View view) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() { runNNAPIBenchmark(buffer); }
+ }).start();
+ }
+ });
+ }
+
+ public native String getModelName();
+ public native void runInterpreterBenchmark(MappedByteBuffer buffer);
+ public native void runNNAPIBenchmark(MappedByteBuffer buffer);
+}
diff --git a/runtime/contrib/android_benchmark_app/res/drawable-hdpi/ic_launcher.png b/runtime/contrib/android_benchmark_app/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..96a442e5b
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/runtime/contrib/android_benchmark_app/res/drawable-mdpi/ic_launcher.png b/runtime/contrib/android_benchmark_app/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..359047dfa
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/runtime/contrib/android_benchmark_app/res/drawable-xhdpi/ic_launcher.png b/runtime/contrib/android_benchmark_app/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..71c6d760f
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/runtime/contrib/android_benchmark_app/res/drawable-xxhdpi/ic_launcher.png b/runtime/contrib/android_benchmark_app/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..4df189464
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/runtime/contrib/android_benchmark_app/res/layout/activity_main.xml b/runtime/contrib/android_benchmark_app/res/layout/activity_main.xml
new file mode 100644
index 000000000..551952582
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <Button android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/button_interp"
+ android:text="Run Interp benchmark"/>
+
+ <Button android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/button_nnapi"
+ android:text="Run NNAPI benchmark"/>
+
+ <TextView android:text=""
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/model_label"
+ android:layout_centerHorizontal="true"
+ android:textSize="16dp"/>
+
+ <TextView android:text=""
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/title_label"
+ android:layout_centerHorizontal="true"
+ android:textSize="16dp"/>
+
+ <TextView android:text=""
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/message_label"
+ android:layout_centerHorizontal="true"
+ android:textSize="16dp"/>
+
+</LinearLayout>
diff --git a/runtime/contrib/android_benchmark_app/res/values-v21/styles.xml b/runtime/contrib/android_benchmark_app/res/values-v21/styles.xml
new file mode 100644
index 000000000..dba3c417b
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/res/values-v21/styles.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="AppTheme" parent="android:Theme.Material.Light">
+ </style>
+</resources>
diff --git a/runtime/contrib/android_benchmark_app/res/values/strings.xml b/runtime/contrib/android_benchmark_app/res/values/strings.xml
new file mode 100644
index 000000000..3c6c4aaa4
--- /dev/null
+++ b/runtime/contrib/android_benchmark_app/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">T/F Lite Benchmark</string>
+
+</resources>
diff --git a/runtime/contrib/android_tflite/CMakeLists.txt b/runtime/contrib/android_tflite/CMakeLists.txt
new file mode 100644
index 000000000..c035cedf5
--- /dev/null
+++ b/runtime/contrib/android_tflite/CMakeLists.txt
@@ -0,0 +1,31 @@
+if(NOT BUILD_ANDROID_TFLITE)
+ return()
+endif(NOT BUILD_ANDROID_TFLITE)
+
+nnfw_find_package(TensorFlowLite EXACT 1.13.1 REQUIRED)
+
+if(NOT DEFINED NDK_DIR)
+ message(FATAL_ERROR "NDK_DIR should be specified via environment variable")
+endif()
+message(STATUS "Found NDK: ${NDK_DIR}")
+
+#
+# Tensorflow Lite JNI library
+#
+set(TENSORFLOW_LITE_BASE "${TensorFlowSource_DIR}/tensorflow/lite")
+set(TFLITE_JNI_BASE ${TENSORFLOW_LITE_BASE}/java/src/main/native)
+set(TFLITE_JNI_SRCS ${TFLITE_JNI_BASE}/exception_jni.cc
+ ${TFLITE_JNI_BASE}/nativeinterpreterwrapper_jni.cc
+ ${TFLITE_JNI_BASE}/tensor_jni.cc
+ ${TFLITE_JNI_BASE}/tensorflow_lite_jni.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/builtin_ops_jni.cc # Use nnfw's OpResolver
+ )
+set(TFLITE_JNI_INCLUDES ${TENSORFLOW_LITE_BASE}/java/src/native)
+
+# TODO use tensorflow-lite static library instead of compiling all the sources again
+add_library(tensorflowlite_jni SHARED ${TFLITE_JNI_SRCS} ${TFLITE_SRCS})
+target_include_directories(tensorflowlite_jni PUBLIC ${TFLITE_JNI_INCLUDES} ${TFLITE_INCLUDES})
+target_link_libraries(tensorflowlite_jni eigen ${LIB_PTHREAD} dl)
+target_link_libraries(tensorflowlite_jni log)
+target_link_libraries(tensorflowlite_jni nnfw_lib_tflite)
+install(TARGETS tensorflowlite_jni DESTINATION lib)
diff --git a/runtime/contrib/android_tflite/builtin_ops_jni.cc b/runtime/contrib/android_tflite/builtin_ops_jni.cc
new file mode 100644
index 000000000..5770701ea
--- /dev/null
+++ b/runtime/contrib/android_tflite/builtin_ops_jni.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tensorflow/lite/kernels/register.h"
+#include "tflite/ext/kernels/register.h"
+
+namespace tflite
+{
+
+std::unique_ptr<OpResolver> CreateOpResolver()
+{
+ return std::unique_ptr<::nnfw::tflite::BuiltinOpResolver>(
+ new ::nnfw::tflite::BuiltinOpResolver());
+}
+
+} // namespace tflite
diff --git a/runtime/contrib/benchmark_acl/.FORMATDENY b/runtime/contrib/benchmark_acl/.FORMATDENY
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/runtime/contrib/benchmark_acl/.FORMATDENY
diff --git a/runtime/contrib/benchmark_acl/CMakeLists.txt b/runtime/contrib/benchmark_acl/CMakeLists.txt
new file mode 100644
index 000000000..b5fa3e529
--- /dev/null
+++ b/runtime/contrib/benchmark_acl/CMakeLists.txt
@@ -0,0 +1,24 @@
+if(NOT BUILD_BENCHMARK_ACL)
+ return()
+endif(NOT BUILD_BENCHMARK_ACL)
+
+nnfw_find_package(ARMCompute REQUIRED)
+
+add_library(arm_compute_benchmark SHARED "src/Benchmark.cpp")
+target_include_directories(arm_compute_benchmark PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(arm_compute_benchmark arm_compute_graph)
+install(TARGETS arm_compute_benchmark DESTINATION lib)
+
+# GoogLeNet benchmark
+add_executable(benchmark_googlenet "src/benchmark_googlenet.cpp")
+target_link_libraries(benchmark_googlenet arm_compute_benchmark)
+
+# GoogLeNet benchmark
+add_executable(benchmark_inception_v3 "src/benchmark_inception_v3.cpp")
+target_link_libraries(benchmark_inception_v3 arm_compute_benchmark)
+
+# MobileNet benchmark
+add_executable(benchmark_mobilenet "src/benchmark_mobilenet.cpp")
+target_link_libraries(benchmark_mobilenet arm_compute_benchmark)
+
+install(TARGETS benchmark_googlenet benchmark_inception_v3 benchmark_mobilenet DESTINATION bin)
diff --git a/runtime/contrib/benchmark_acl/src/Benchmark.cpp b/runtime/contrib/benchmark_acl/src/Benchmark.cpp
new file mode 100644
index 000000000..4a761ec76
--- /dev/null
+++ b/runtime/contrib/benchmark_acl/src/Benchmark.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Benchmark.h"
+
+#include <cstdlib>
+
+Count::Count() : _value(1)
+{
+ auto env = std::getenv("COUNT");
+
+ if (env)
+ {
+ _value = std::strtol(env, NULL, 0);
+ }
+}
+
+uint32_t Count::value(void) const { return _value; }
+
+#include <boost/accumulators/accumulators.hpp>
+#include <boost/accumulators/statistics/stats.hpp>
+#include <boost/accumulators/statistics/mean.hpp>
+
+#include <iostream>
+#include <chrono>
+
+using namespace boost::accumulators;
+
+void run_benchmark(arm_compute::graph::frontend::Stream &graph)
+{
+ // NOTE Here the number of warming-up iterations is hardcoded
+ // TODO Decide the number of warming-up iterations appropriately
+ for (uint32_t n = 0; n < 3; ++n)
+ {
+ auto beg = std::chrono::steady_clock::now();
+ graph.run();
+ auto end = std::chrono::steady_clock::now();
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - beg);
+
+ std::cout << "Warming-up " << n << ": " << elapsed.count() << "ms" << std::endl;
+ }
+
+ accumulator_set<double, stats<tag::mean>> acc;
+
+ const Count count;
+
+ for (uint32_t n = 0; n < count.value(); ++n)
+ {
+ auto beg = std::chrono::steady_clock::now();
+ graph.run();
+ auto end = std::chrono::steady_clock::now();
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - beg);
+
+ std::cout << "Iteration " << n << ": " << elapsed.count() << "ms" << std::endl;
+
+ acc(elapsed.count());
+ }
+
+ std::cout << "--------" << std::endl;
+ std::cout << "Mean: " << mean(acc) << "ms" << std::endl;
+}
diff --git a/runtime/contrib/benchmark_acl/src/Benchmark.h b/runtime/contrib/benchmark_acl/src/Benchmark.h
new file mode 100644
index 000000000..200f40952
--- /dev/null
+++ b/runtime/contrib/benchmark_acl/src/Benchmark.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ACL_BENCHMARK_H__
+#define __ACL_BENCHMARK_H__
+
+#include "arm_compute/graph/ITensorAccessor.h"
+#include "arm_compute/graph.h"
+#include "arm_compute/core/CL/OpenCL.h"
+
+struct InputAccessor final : public arm_compute::graph::ITensorAccessor
+{
+ InputAccessor() = default;
+ /** Allows instances to move constructed */
+ InputAccessor(InputAccessor &&) = default;
+
+ // Inherited methods overriden:
+ bool access_tensor(arm_compute::ITensor &tensor) override
+ {
+ return true;
+ }
+};
+
+struct OutputAccessor final : public arm_compute::graph::ITensorAccessor
+{
+ OutputAccessor() = default;
+ /** Allows instances to move constructed */
+ OutputAccessor(OutputAccessor &&) = default;
+
+ // Inherited methods overriden:
+ bool access_tensor(arm_compute::ITensor &tensor) override
+ {
+ return false;
+ }
+};
+
+template <typename T> std::unique_ptr<arm_compute::graph::ITensorAccessor> get_accessor()
+{
+ return std::unique_ptr<T>(new T());
+}
+
+class Count
+{
+public:
+ Count();
+
+public:
+ uint32_t value(void) const;
+
+private:
+ uint32_t _value;
+};
+
+inline arm_compute::graph::Target set_target_hint(int target)
+{
+ if(target == 1 && arm_compute::opencl_is_available())
+ {
+ // If type of target is OpenCL, check if OpenCL is available and initialize the scheduler
+ return arm_compute::graph::Target::CL;
+ }
+ else
+ {
+ return arm_compute::graph::Target::NEON;
+ }
+}
+
+void run_benchmark(arm_compute::graph::frontend::Stream &graph);
+
+#endif
diff --git a/runtime/contrib/benchmark_acl/src/benchmark_googlenet.cpp b/runtime/contrib/benchmark_acl/src/benchmark_googlenet.cpp
new file mode 100644
index 000000000..8b0fbfdac
--- /dev/null
+++ b/runtime/contrib/benchmark_acl/src/benchmark_googlenet.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright (c) 2017 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "arm_compute/graph.h"
+
+#include "Benchmark.h"
+
+#include <cstdlib>
+#include <tuple>
+
+using namespace arm_compute::graph::frontend;
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_input_accessor(void)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_random_accessor(float lower, float upper)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_weights_accessor(const std::string &path, const std::string &data_file, DataLayout file_layout = DataLayout::NCHW)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_output_accessor(void)
+{
+ return get_accessor<OutputAccessor>();
+}
+
+/** Example demonstrating how to implement Googlenet's network using the Compute Library's graph API
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL, 2 = OpenCL with Tuner), [optional] Path to the weights folder, [optional] image, [optional] labels, [optional] Fast math for convolution layer (0 = DISABLED, 1 = ENABLED) )
+ */
+class GraphGooglenetExample
+{
+public:
+ void do_setup(int argc, char **argv)
+ {
+ std::string data_path; /* Path to the trainable data */
+ std::string image; /* Image data */
+ std::string label; /* Label data */
+
+ const std::array<float, 3> mean_rgb{ { 122.68f, 116.67f, 104.01f } };
+ // Set target. 0 (NEON), 1 (OpenCL), 2 (OpenCL with Tuner). By default it is NEON
+ const int target = argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0;
+ Target target_hint = set_target_hint(target);
+ FastMathHint fast_math_hint = FastMathHint::Disabled;
+
+ // Parse arguments
+ if(argc < 2)
+ {
+ // Print help
+ std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No data folder provided: using random values\n\n";
+ }
+ else if(argc == 2)
+ {
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No data folder provided: using random values\n\n";
+ }
+ else if(argc == 3)
+ {
+ data_path = argv[2];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No image provided: using random values\n\n";
+ }
+ else if(argc == 4)
+ {
+ data_path = argv[2];
+ image = argv[3];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels] [fast_math_hint]\n\n";
+ std::cout << "No text file with labels provided: skipping output accessor\n\n";
+ }
+ else if(argc == 5)
+ {
+ data_path = argv[2];
+ image = argv[3];
+ label = argv[4];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " " << argv[4] << " [fast_math_hint]\n\n";
+ std::cout << "No fast math info provided: disabling fast math\n\n";
+ }
+ else
+ {
+ data_path = argv[2];
+ image = argv[3];
+ label = argv[4];
+ fast_math_hint = (std::strtol(argv[5], nullptr, 1) == 0) ? FastMathHint::Disabled : FastMathHint::Enabled;
+ }
+
+ graph << target_hint
+ << fast_math_hint
+ << InputLayer(TensorDescriptor(TensorShape(224U, 224U, 3U, 1U), DataType::F32),
+ get_input_accessor())
+ << ConvolutionLayer(
+ 7U, 7U, 64U,
+ get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv1/conv1_7x7_s2_w.npy"),
+ get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv1/conv1_7x7_s2_b.npy"),
+ PadStrideInfo(2, 2, 3, 3))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
+ << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL)))
+ << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f))
+ << ConvolutionLayer(
+ 1U, 1U, 64U,
+ get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_reduce_w.npy"),
+ get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_reduce_b.npy"),
+ PadStrideInfo(1, 1, 0, 0))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
+ << ConvolutionLayer(
+ 3U, 3U, 192U,
+ get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_w.npy"),
+ get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_b.npy"),
+ PadStrideInfo(1, 1, 1, 1))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
+ << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f))
+ << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL)));
+ graph << get_inception_node(data_path, "inception_3a", 64, std::make_tuple(96U, 128U), std::make_tuple(16U, 32U), 32U);
+ graph << get_inception_node(data_path, "inception_3b", 128, std::make_tuple(128U, 192U), std::make_tuple(32U, 96U), 64U);
+ graph << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL)));
+ graph << get_inception_node(data_path, "inception_4a", 192, std::make_tuple(96U, 208U), std::make_tuple(16U, 48U), 64U);
+ graph << get_inception_node(data_path, "inception_4b", 160, std::make_tuple(112U, 224U), std::make_tuple(24U, 64U), 64U);
+ graph << get_inception_node(data_path, "inception_4c", 128, std::make_tuple(128U, 256U), std::make_tuple(24U, 64U), 64U);
+ graph << get_inception_node(data_path, "inception_4d", 112, std::make_tuple(144U, 288U), std::make_tuple(32U, 64U), 64U);
+ graph << get_inception_node(data_path, "inception_4e", 256, std::make_tuple(160U, 320U), std::make_tuple(32U, 128U), 128U);
+ graph << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL)));
+ graph << get_inception_node(data_path, "inception_5a", 256, std::make_tuple(160U, 320U), std::make_tuple(32U, 128U), 128U);
+ graph << get_inception_node(data_path, "inception_5b", 384, std::make_tuple(192U, 384U), std::make_tuple(48U, 128U), 128U);
+ graph << PoolingLayer(PoolingLayerInfo(PoolingType::AVG, 7, PadStrideInfo(1, 1, 0, 0, DimensionRoundingType::CEIL)))
+ << FullyConnectedLayer(
+ 1000U,
+ get_weights_accessor(data_path, "/cnn_data/googlenet_model/loss3/loss3_classifier_w.npy"),
+ get_weights_accessor(data_path, "/cnn_data/googlenet_model/loss3/loss3_classifier_b.npy"))
+ << SoftmaxLayer()
+ << OutputLayer(get_output_accessor());
+
+ // Finalize graph
+ GraphConfig config;
+ config.use_tuner = (target == 2);
+ graph.finalize(target_hint, config);
+ }
+ void do_run()
+ {
+ run_benchmark(graph);
+ }
+
+private:
+ Stream graph{ 0, "GoogleNet" };
+
+ ConcatLayer get_inception_node(const std::string &data_path, std::string &&param_path,
+ unsigned int a_filt,
+ std::tuple<unsigned int, unsigned int> b_filters,
+ std::tuple<unsigned int, unsigned int> c_filters,
+ unsigned int d_filt)
+ {
+ std::string total_path = "/cnn_data/googlenet_model/" + param_path + "/" + param_path + "_";
+ SubStream i_a(graph);
+ i_a << ConvolutionLayer(
+ 1U, 1U, a_filt,
+ get_weights_accessor(data_path, total_path + "1x1_w.npy"),
+ get_weights_accessor(data_path, total_path + "1x1_b.npy"),
+ PadStrideInfo(1, 1, 0, 0))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU));
+
+ SubStream i_b(graph);
+ i_b << ConvolutionLayer(
+ 1U, 1U, std::get<0>(b_filters),
+ get_weights_accessor(data_path, total_path + "3x3_reduce_w.npy"),
+ get_weights_accessor(data_path, total_path + "3x3_reduce_b.npy"),
+ PadStrideInfo(1, 1, 0, 0))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
+ << ConvolutionLayer(
+ 3U, 3U, std::get<1>(b_filters),
+ get_weights_accessor(data_path, total_path + "3x3_w.npy"),
+ get_weights_accessor(data_path, total_path + "3x3_b.npy"),
+ PadStrideInfo(1, 1, 1, 1))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU));
+
+ SubStream i_c(graph);
+ i_c << ConvolutionLayer(
+ 1U, 1U, std::get<0>(c_filters),
+ get_weights_accessor(data_path, total_path + "5x5_reduce_w.npy"),
+ get_weights_accessor(data_path, total_path + "5x5_reduce_b.npy"),
+ PadStrideInfo(1, 1, 0, 0))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))
+ << ConvolutionLayer(
+ 5U, 5U, std::get<1>(c_filters),
+ get_weights_accessor(data_path, total_path + "5x5_w.npy"),
+ get_weights_accessor(data_path, total_path + "5x5_b.npy"),
+ PadStrideInfo(1, 1, 2, 2))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU));
+
+ SubStream i_d(graph);
+ i_d << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL)))
+ << ConvolutionLayer(
+ 1U, 1U, d_filt,
+ get_weights_accessor(data_path, total_path + "pool_proj_w.npy"),
+ get_weights_accessor(data_path, total_path + "pool_proj_b.npy"),
+ PadStrideInfo(1, 1, 0, 0))
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU));
+
+ return ConcatLayer(std::move(i_a), std::move(i_b), std::move(i_c), std::move(i_d));
+ }
+};
+
+/** Main program for Googlenet
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL, 2 = OpenCL with Tuner), [optional] Path to the weights folder, [optional] image, [optional] labels, [optional] Fast math for convolution layer (0 = DISABLED, 1 = ENABLED) )
+ */
+int main(int argc, char **argv)
+{
+ GraphGooglenetExample example;
+
+ example.do_setup(argc, argv);
+ example.do_run();
+
+ return 0;
+}
diff --git a/runtime/contrib/benchmark_acl/src/benchmark_inception_v3.cpp b/runtime/contrib/benchmark_acl/src/benchmark_inception_v3.cpp
new file mode 100644
index 000000000..382851f50
--- /dev/null
+++ b/runtime/contrib/benchmark_acl/src/benchmark_inception_v3.cpp
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright (c) 2017-2018 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 "arm_compute/graph.h"
+
+#include "Benchmark.h"
+
+#include <cstdlib>
+#include <tuple>
+
+using namespace arm_compute::graph::frontend;
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_input_accessor(void)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_random_accessor(float lower, float upper)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_weights_accessor(const std::string &path, const std::string &data_file, DataLayout file_layout = DataLayout::NCHW)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_output_accessor(void)
+{
+ return get_accessor<OutputAccessor>();
+}
+
+/** Example demonstrating how to implement InceptionV3's network using the Compute Library's graph API
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL, 2 = OpenCL with Tuner), [optional] Path to the weights folder, [optional] image, [optional] labels )
+ */
+class InceptionV3Example
+{
+public:
+ void do_setup(int argc, char **argv)
+ {
+ std::string data_path; /* Path to the trainable data */
+ std::string image; /* Image data */
+ std::string label; /* Label data */
+
+ // Set target. 0 (NEON), 1 (OpenCL), 2 (OpenCL with Tuner). By default it is NEON
+ const int target = argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0;
+ Target target_hint = set_target_hint(target);
+ FastMathHint fast_math_hint = FastMathHint::Disabled;
+
+ // Parse arguments
+ if(argc < 2)
+ {
+ // Print help
+ std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No data folder provided: using random values\n\n";
+ }
+ else if(argc == 2)
+ {
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No data folder provided: using random values\n\n";
+ }
+ else if(argc == 3)
+ {
+ data_path = argv[2];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No image provided: using random values\n\n";
+ }
+ else if(argc == 4)
+ {
+ data_path = argv[2];
+ image = argv[3];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels] [fast_math_hint]\n\n";
+ std::cout << "No text file with labels provided: skipping output accessor\n\n";
+ }
+ else if(argc == 5)
+ {
+ data_path = argv[2];
+ image = argv[3];
+ label = argv[4];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " " << argv[4] << " [fast_math_hint]\n\n";
+ std::cout << "No fast math info provided: disabling fast math\n\n";
+ }
+ else
+ {
+ data_path = argv[2];
+ image = argv[3];
+ label = argv[4];
+ fast_math_hint = (std::strtol(argv[5], nullptr, 1) == 0) ? FastMathHint::Disabled : FastMathHint::Enabled;
+ }
+
+ graph << target_hint
+ << fast_math_hint
+ << InputLayer(TensorDescriptor(TensorShape(299U, 299U, 3U, 1U), DataType::F32),
+ get_input_accessor())
+ << ConvolutionLayer(3U, 3U, 32U,
+ get_weights_accessor(data_path, "/cnn_data/inceptionv3_model/Conv2d_1a_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr), PadStrideInfo(2, 2, 0, 0))
+ .set_name("Conv2d_1a_3x3/convolution")
+ << BatchNormalizationLayer(get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_1a_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_1a_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f), get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_1a_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name("Conv2d_1a_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name("Conv2d_1a_3x3/Relu")
+ << ConvolutionLayer(3U, 3U, 32U,
+ get_weights_accessor(data_path, "/cnn_data/inceptionv3_model/Conv2d_2a_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr), PadStrideInfo(1, 1, 0, 0))
+ .set_name("Conv2d_2a_3x3/convolution")
+ << BatchNormalizationLayer(get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_2a_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_2a_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f), get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_2a_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name("Conv2d_2a_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name("Conv2d_2a_3x3/Relu")
+
+ << ConvolutionLayer(3U, 3U, 64U,
+ get_weights_accessor(data_path, "/cnn_data/inceptionv3_model/Conv2d_2b_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr), PadStrideInfo(1, 1, 1, 1))
+ .set_name("Conv2d_2b_3x3/convolution")
+ << BatchNormalizationLayer(get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_2b_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_2b_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f), get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_2b_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name("Conv2d_2b_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name("Conv2d_2b_3x3/Relu")
+
+ << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))).set_name("MaxPool_3a_3x3/MaxPool")
+
+ << ConvolutionLayer(1U, 1U, 80U,
+ get_weights_accessor(data_path, "/cnn_data/inceptionv3_model/Conv2d_3b_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr), PadStrideInfo(1, 1, 0, 0))
+ .set_name("Conv2d_3b_1x1/convolution")
+ << BatchNormalizationLayer(get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_3b_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_3b_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f), get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_3b_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name("Conv2d_3b_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name("Conv2d_3b_1x1/Relu")
+
+ << ConvolutionLayer(3U, 3U, 192U,
+ get_weights_accessor(data_path, "/cnn_data/inceptionv3_model/Conv2d_4a_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr), PadStrideInfo(1, 1, 0, 0))
+ .set_name("Conv2d_4a_3x3/convolution")
+ << BatchNormalizationLayer(get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_4a_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_4a_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f), get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Conv2d_4a_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name("Conv2d_4a_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name("Conv2d_4a_3x3/Relu")
+
+ << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))).set_name("MaxPool_5a_3x3/MaxPool");
+
+ graph << get_inception_node_A(data_path, "Mixed_5b", 64U, std::make_tuple(48U, 64U), std::make_tuple(64U, 96U, 96U),
+ 32U)
+ .set_name("Mixed_5b/concat");
+ graph << get_inception_node_A(data_path, "Mixed_5c", 64U, std::make_tuple(48U, 64U), std::make_tuple(64U, 96U, 96U),
+ 64U, true)
+ .set_name("Mixed_5c/concat");
+ graph << get_inception_node_A(data_path, "Mixed_5d", 64U, std::make_tuple(48U, 64U), std::make_tuple(64U, 96U, 96U),
+ 64U)
+ .set_name("Mixed_5d/concat");
+
+ graph << get_inception_node_B(data_path, "Mixed_6a", 384U, std::make_tuple(64U, 96U, 96U)).set_name("Mixed_6a/concat");
+
+ graph << get_inception_node_C(data_path, "Mixed_6b", 192U, std::make_tuple(128U, 128U, 192U),
+ std::make_tuple(128U, 128U, 128U, 128U, 192U), 192U)
+ .set_name("Mixed_6b/concat");
+ graph << get_inception_node_C(data_path, "Mixed_6c", 192U, std::make_tuple(160U, 160U, 192U),
+ std::make_tuple(160U, 160U, 160U, 160U, 192U), 192U)
+ .set_name("Mixed_6c/concat");
+ graph << get_inception_node_C(data_path, "Mixed_6d", 192U, std::make_tuple(160U, 160U, 192U),
+ std::make_tuple(160U, 160U, 160U, 160U, 192U), 192U)
+ .set_name("Mixed_6d/concat");
+ graph << get_inception_node_C(data_path, "Mixed_6e", 192U, std::make_tuple(192U, 192U, 192U),
+ std::make_tuple(192U, 192U, 192U, 192U, 192U), 192U)
+ .set_name("Mixed_6e/concat");
+
+ graph << get_inception_node_D(data_path, "Mixed_7a", std::make_tuple(192U, 320U),
+ std::make_tuple(192U, 192U, 192U, 192U))
+ .set_name("Mixed_7a/concat");
+
+ graph << get_inception_node_E(data_path, "Mixed_7b", 320U, std::make_tuple(384U, 384U, 384U),
+ std::make_tuple(448U, 384U, 384U, 384U), 192U)
+ .set_name("Mixed_7b/concat");
+ graph << get_inception_node_E(data_path, "Mixed_7c", 320U, std::make_tuple(384U, 384U, 384U),
+ std::make_tuple(448U, 384U, 384U, 384U), 192U, true)
+ .set_name("Mixed_7c/concat");
+
+ graph << PoolingLayer(PoolingLayerInfo(PoolingType::AVG, 8, PadStrideInfo(1, 1, 0, 0, DimensionRoundingType::CEIL))).set_name("Logits/AvgPool_1a_8x8/AvgPool")
+ << ConvolutionLayer(1U, 1U, 1001U, get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Logits_Conv2d_1c_1x1_weights.npy"),
+ get_weights_accessor(data_path,
+ "/cnn_data/inceptionv3_model/Logits_Conv2d_1c_1x1_biases.npy"),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name("Logits/Conv2d_1c_1x1/convolution")
+ << ReshapeLayer(TensorShape(1001U)).set_name("Predictions/Reshape")
+ << SoftmaxLayer().set_name("Predictions/Softmax")
+ << OutputLayer(get_output_accessor());
+
+ // Finalize graph
+ GraphConfig config;
+ config.use_tuner = (target == 2);
+ graph.finalize(target_hint, config);
+ }
+
+ void do_run()
+ {
+ run_benchmark(graph);
+ }
+
+private:
+ Stream graph{ 0, "InceptionV3" };
+
+private:
+ ConcatLayer get_inception_node_A(const std::string &data_path, std::string &&param_path,
+ unsigned int a_filt,
+ std::tuple<unsigned int, unsigned int> b_filters,
+ std::tuple<unsigned int, unsigned int, unsigned int> c_filters,
+ unsigned int d_filt,
+ bool is_name_different = false)
+ {
+ std::string total_path = "/cnn_data/inceptionv3_model/" + param_path + "_";
+
+ // This is due to a naming issue in the tf model
+ std::string conv_id0 = "_0a_";
+ std::string conv_id1 = "2d_0b_";
+ if(is_name_different)
+ {
+ conv_id0 = "_0b_";
+ conv_id1 = "_1_0c_";
+ }
+
+ SubStream i_a(graph);
+ i_a << ConvolutionLayer(
+ 1U, 1U, a_filt,
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_0/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_0/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_0/Conv2d_0a_1x1/Relu");
+
+ SubStream i_b(graph);
+ i_b << ConvolutionLayer(
+ 1U, 1U, std::get<0>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d" + conv_id0 + "1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_1/Conv2d" + conv_id0 + "1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d" + conv_id0 + "1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d" + conv_id0 + "1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d" + conv_id0 + "1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d" + conv_id0 + "1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d" + conv_id0 + "1x1/Relu")
+ << ConvolutionLayer(
+ 5U, 5U, std::get<1>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv" + conv_id1 + "5x5_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 2, 2))
+ .set_name(param_path + "/Branch_1/Conv2d" + conv_id1 + "5x5/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv" + conv_id1 + "5x5_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv" + conv_id1 + "5x5_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv" + conv_id1 + "5x5_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d" + conv_id1 + "5x5/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d" + conv_id1 + "5x5/Relu");
+
+ SubStream i_c(graph);
+ i_c << ConvolutionLayer(
+ 1U, 1U, std::get<0>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_2/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0a_1x1/Relu")
+ << ConvolutionLayer(
+ 3U, 3U, std::get<1>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 1, 1))
+ .set_name(param_path + "/Branch_2/Conv2d_0b_3x3/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0b_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0b_3x3/Relu")
+ << ConvolutionLayer(
+ 3U, 3U, std::get<2>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 1, 1))
+ .set_name(param_path + "/Branch_2/Conv2d_0c_3x3/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0c_3x3/BatchNorm/batcnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0c_3x3/Relu");
+
+ SubStream i_d(graph);
+ i_d << PoolingLayer(PoolingLayerInfo(PoolingType::AVG, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL), true)).set_name(param_path + "/Branch_3/AvgPool_0a_3x3/AvgPool")
+ << ConvolutionLayer(
+ 1U, 1U, d_filt,
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_3/Conv2d_0b_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_3/Conv2d_0b_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_3/Conv2d_0b_1x1/Relu");
+
+ return ConcatLayer(std::move(i_a), std::move(i_b), std::move(i_c), std::move(i_d));
+ }
+
+ ConcatLayer get_inception_node_B(const std::string &data_path, std::string &&param_path,
+ unsigned int a_filt,
+ std::tuple<unsigned int, unsigned int, unsigned int> b_filters)
+ {
+ std::string total_path = "/cnn_data/inceptionv3_model/" + param_path + "_";
+ SubStream i_a(graph);
+ i_a << ConvolutionLayer(
+ 3U, 3U, a_filt,
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_1a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(2, 2, 0, 0))
+ .set_name(param_path + "/Branch_0/Conv2d_1a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_1a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_1a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_1a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_0/Conv2d_1a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_0/Conv2d_1a_1x1/Relu");
+
+ SubStream i_b(graph);
+ i_b << ConvolutionLayer(
+ 1U, 1U, std::get<0>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0a_1x1/Relu")
+ << ConvolutionLayer(
+ 3U, 3U, std::get<1>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 1, 1))
+ .set_name(param_path + "/Branch_1/Conv2d_0b_3x3/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0b_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0b_3x3/Relu")
+ << ConvolutionLayer(
+ 3U, 3U, std::get<2>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_1a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(2, 2, 0, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_1a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_1a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_1a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_1a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_1a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_1a_1x1/Relu");
+
+ SubStream i_c(graph);
+ i_c << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))).set_name(param_path + "/Branch_2/MaxPool_1a_3x3/MaxPool");
+
+ return ConcatLayer(std::move(i_a), std::move(i_b), std::move(i_c));
+ }
+
+ ConcatLayer get_inception_node_C(const std::string &data_path, std::string &&param_path,
+ unsigned int a_filt,
+ std::tuple<unsigned int, unsigned int, unsigned int> b_filters,
+ std::tuple<unsigned int, unsigned int, unsigned int, unsigned int, unsigned int> c_filters,
+ unsigned int d_filt)
+ {
+ std::string total_path = "/cnn_data/inceptionv3_model/" + param_path + "_";
+ SubStream i_a(graph);
+ i_a << ConvolutionLayer(
+ 1U, 1U, a_filt,
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_0/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_0/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_0/Conv2d_0a_1x1/Relu");
+
+ SubStream i_b(graph);
+ i_b << ConvolutionLayer(
+ 1U, 1U, std::get<0>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0a_1x1/Relu")
+ << ConvolutionLayer(
+ 7U, 1U, std::get<1>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x7_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 3, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_0b_1x7/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x7_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x7_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x7_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0b_1x7/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0b_1x7/Relu")
+ << ConvolutionLayer(
+ 1U, 7U, std::get<2>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0c_7x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 3))
+ .set_name(param_path + "/Branch_1/Conv2d_0c_7x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0c_7x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0c_7x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0c_7x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0c_7x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_0/Conv2d_0c_7x1/Relu");
+
+ SubStream i_c(graph);
+ i_c << ConvolutionLayer(
+ 1U, 1U, std::get<0>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_2/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0a_1x1/Relu")
+ << ConvolutionLayer(
+ 1U, 7U, std::get<1>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_7x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 3))
+ .set_name(param_path + "/Branch_2/Conv2d_0b_7x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_7x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_7x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_7x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0b_7x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0b_7x1/Relu")
+ << ConvolutionLayer(
+ 7U, 1U, std::get<2>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_1x7_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 3, 0))
+ .set_name(param_path + "/Branch_2/Conv2d_0c_1x7/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_1x7_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_1x7_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_1x7_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0c_1x7/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0c_1x7/Relu")
+ << ConvolutionLayer(
+ 1U, 7U, std::get<3>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0d_7x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 3))
+ .set_name(param_path + "/Branch_2/Conv2d_0d_7x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0d_7x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0d_7x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0d_7x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0d_7x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0d_7x1/Relu")
+ << ConvolutionLayer(
+ 7U, 1U, std::get<4>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0e_1x7_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 3, 0))
+ .set_name(param_path + "/Branch_2/Conv2d_0e_1x7/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0e_1x7_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0e_1x7_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0e_1x7_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0e_1x7/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0e_1x7/Relu");
+
+ SubStream i_d(graph);
+ i_d << PoolingLayer(PoolingLayerInfo(PoolingType::AVG, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL), true)).set_name(param_path + "/Branch_3/AvgPool_0a_3x3/AvgPool")
+ << ConvolutionLayer(
+ 1U, 1U, d_filt,
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_3/Conv2d_0b_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_3/Conv2d_0b_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_3/Conv2d_0b_1x1/Relu");
+
+ return ConcatLayer(std::move(i_a), std::move(i_b), std::move(i_c), std::move(i_d));
+ }
+
+ ConcatLayer get_inception_node_D(const std::string &data_path, std::string &&param_path,
+ std::tuple<unsigned int, unsigned int> a_filters,
+ std::tuple<unsigned int, unsigned int, unsigned int, unsigned int> b_filters)
+ {
+ std::string total_path = "/cnn_data/inceptionv3_model/" + param_path + "_";
+ SubStream i_a(graph);
+ i_a << ConvolutionLayer(
+ 1U, 1U, std::get<0>(a_filters),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_0/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_0/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_0/Conv2d_0a_1x1/Relu")
+ << ConvolutionLayer(
+ 3U, 3U, std::get<1>(a_filters),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_1a_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(2, 2, 0, 0))
+ .set_name(param_path + "/Branch_0/Conv2d_1a_3x3/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_1a_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_1a_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_1a_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_0/Conv2d_1a_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_0/Conv2d_1a_3x3/Relu");
+
+ SubStream i_b(graph);
+ i_b << ConvolutionLayer(
+ 1U, 1U, std::get<0>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0a_1x1/Relu")
+ << ConvolutionLayer(
+ 7U, 1U, std::get<1>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x7_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 3, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_0b_1x7/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x7_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x7_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x7_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0b_1x7/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0b_1x7/Relu")
+ << ConvolutionLayer(
+ 1U, 7U, std::get<2>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0c_7x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 3))
+ .set_name(param_path + "/Branch_1/Conv2d_0c_7x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0c_7x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0c_7x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0c_7x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0c_7x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0c_7x1/Relu")
+ << ConvolutionLayer(
+ 3U, 3U, std::get<3>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_1a_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(2, 2, 0, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_1a_3x3/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_1a_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_1a_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_1a_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_1a_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_1a_3x3/Relu");
+
+ SubStream i_c(graph);
+ i_c << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))).set_name(param_path + "/Branch_2/MaxPool_1a_3x3/MaxPool");
+
+ return ConcatLayer(std::move(i_a), std::move(i_b), std::move(i_c));
+ }
+
+ ConcatLayer get_inception_node_E(const std::string &data_path, std::string &&param_path,
+ unsigned int a_filt,
+ std::tuple<unsigned int, unsigned int, unsigned int> b_filters,
+ std::tuple<unsigned int, unsigned int, unsigned int, unsigned int> c_filters,
+ unsigned int d_filt,
+ bool is_name_different = false)
+ {
+ // This is due to a naming issue in the tf model
+ std::string conv_id = "_0b_";
+ if(is_name_different)
+ {
+ conv_id = "_0c_";
+ }
+
+ std::string total_path = "/cnn_data/inceptionv3_model/" + param_path + "_";
+ SubStream i_a(graph);
+ i_a << ConvolutionLayer(
+ 1U, 1U, a_filt,
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_0/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_0_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_0/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_0/Conv2d_0a_1x1/Relu");
+
+ SubStream i_b(graph);
+ i_b << ConvolutionLayer(
+ 1U, 1U, std::get<0>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0a_1x1/Relu");
+
+ SubStream i_b1(static_cast<IStream &>(i_b));
+ i_b1 << ConvolutionLayer(
+ 3U, 1U, std::get<1>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 1, 0))
+ .set_name(param_path + "/Branch_1/Conv2d_0b_1x3/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d_0b_1x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d_0b_1x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d_0b_1x3/Relu");
+
+ SubStream i_b2(static_cast<IStream &>(i_b));
+ i_b2 << ConvolutionLayer(
+ 1U, 3U, std::get<2>(b_filters),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d" + conv_id + "3x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 1))
+ .set_name(param_path + "/Branch_1/Conv2d" + conv_id + "3x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d" + conv_id + "3x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d" + conv_id + "3x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_1_Conv2d" + conv_id + "3x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_1/Conv2d" + conv_id + "3x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_1/Conv2d" + conv_id + "3x1/Relu");
+
+ // Merge b1 and b2
+ i_b << ConcatLayer(std::move(i_b1), std::move(i_b2)).set_name(param_path + "/Branch_1/concat");
+
+ SubStream i_c(graph);
+ i_c << ConvolutionLayer(
+ 1U, 1U, std::get<0>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_2/Conv2d_0a_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0a_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0a_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0a_1x1/Relu")
+ << ConvolutionLayer(
+ 3U, 3U, std::get<1>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_3x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 1, 1))
+ .set_name(param_path + "/Branch_2/Conv2d_0b_3x3/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_3x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_3x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0b_3x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0b_3x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0b_3x3/Relu");
+
+ SubStream i_c1(static_cast<IStream &>(i_c));
+ i_c1 << ConvolutionLayer(
+ 3U, 1U, std::get<2>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_1x3_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 1, 0))
+ .set_name(param_path + "/Branch_2/Conv2d_0c_1x3/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_1x3_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_1x3_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0c_1x3_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0c_1x3/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0c_1x3/Relu");
+
+ SubStream i_c2(static_cast<IStream &>(i_c));
+ i_c2 << ConvolutionLayer(
+ 1U, 3U, std::get<3>(c_filters),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0d_3x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 1))
+ .set_name(param_path + "/Branch_2/Conv2d_0d_3x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0d_3x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0d_3x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_2_Conv2d_0d_3x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_2/Conv2d_0d_3x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_2/Conv2d_0d_3x1/Relu");
+
+ // Merge i_c1 and i_c2
+ i_c << ConcatLayer(std::move(i_c1), std::move(i_c2)).set_name(param_path + "/Branch_2/concat");
+
+ SubStream i_d(graph);
+ i_d << PoolingLayer(PoolingLayerInfo(PoolingType::AVG, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL), true)).set_name(param_path + "/Branch_3/AvgPool_0a_3x3/AvgPool")
+ << ConvolutionLayer(
+ 1U, 1U, d_filt,
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_weights.npy"),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name(param_path + "/Branch_3/Conv2d_0b_1x1/convolution")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_moving_variance.npy"),
+ get_random_accessor(1.f, 1.f),
+ get_weights_accessor(data_path, total_path + "Branch_3_Conv2d_0b_1x1_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(param_path + "/Branch_3/Conv2d_0b_1x1/BatchNorm/batchnorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name(param_path + "/Branch_3/Conv2d_0b_1x1/Relu");
+
+ return ConcatLayer(std::move(i_a), std::move(i_b), std::move(i_c), std::move(i_d));
+ }
+};
+
+/** Main program for Inception V3
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL, 2 = OpenCL with Tuner), [optional] Path to the weights folder, [optional] image, [optional] labels, [optional] Fast math for convolution layer (0 = DISABLED, 1 = ENABLED) )
+ */
+int main(int argc, char **argv)
+{
+ InceptionV3Example example;
+
+ example.do_setup(argc, argv);
+ example.do_run();
+
+ return 0;
+}
diff --git a/runtime/contrib/benchmark_acl/src/benchmark_mobilenet.cpp b/runtime/contrib/benchmark_acl/src/benchmark_mobilenet.cpp
new file mode 100644
index 000000000..085be184e
--- /dev/null
+++ b/runtime/contrib/benchmark_acl/src/benchmark_mobilenet.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright (c) 2017 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "arm_compute/graph.h"
+
+#include "Benchmark.h"
+
+#include <cstdlib>
+
+using namespace arm_compute::graph::frontend;
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_input_accessor(void)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_random_accessor(float lower, float upper)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_weights_accessor(const std::string &path, const std::string &data_file, DataLayout file_layout = DataLayout::NCHW)
+{
+ return get_accessor<InputAccessor>();
+}
+
+inline std::unique_ptr<arm_compute::graph::ITensorAccessor> get_output_accessor(void)
+{
+ return get_accessor<OutputAccessor>();
+}
+
+/** Example demonstrating how to implement MobileNet's network using the Compute Library's graph API
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels )
+ */
+class GraphMobilenetExample
+{
+public:
+ void do_setup(int argc, char **argv)
+ {
+ std::string data_path; /* Path to the trainable data */
+ std::string image; /* Image data */
+ std::string label; /* Label data */
+
+ // Set target. 0 (NEON), 1 (OpenCL), 2 (OpenCL with Tuner). By default it is NEON
+ const int target = argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0;
+ Target target_hint = set_target_hint(target);
+ ConvolutionMethod convolution_hint = ConvolutionMethod::GEMM;
+ DepthwiseConvolutionMethod depthwise_convolution_hint = DepthwiseConvolutionMethod::Optimized3x3;
+ FastMathHint fast_math_hint = FastMathHint::Disabled;
+
+ // Set model to execute. 0 (MobileNetV1_1.0_224), 1 (MobileNetV1_0.75_160)
+ int model_id = (argc > 2) ? std::strtol(argv[2], nullptr, 10) : 0;
+ ARM_COMPUTE_ERROR_ON_MSG(model_id > 1, "Invalid model ID. Model must be 0 (MobileNetV1_1.0_224) or 1 (MobileNetV1_0.75_160)");
+ int layout_id = (argc > 3) ? std::strtol(argv[3], nullptr, 10) : 0;
+ ARM_COMPUTE_ERROR_ON_MSG(layout_id > 1, "Invalid layout ID. Layout must be 0 (NCHW) or 1 (NHWC)");
+
+ float depth_scale = (model_id == 0) ? 1.f : 0.75;
+ unsigned int spatial_size = (model_id == 0) ? 224 : 160;
+ std::string model_path = (model_id == 0) ? "/cnn_data/mobilenet_v1_1_224_model/" : "/cnn_data/mobilenet_v1_075_160_model/";
+ TensorDescriptor input_descriptor_nchw = TensorDescriptor(TensorShape(spatial_size, spatial_size, 3U, 1U), DataType::F32);
+ TensorDescriptor input_descriptor_nhwc = TensorDescriptor(TensorShape(3U, spatial_size, spatial_size, 1U), DataType::F32).set_layout(DataLayout::NHWC);
+ TensorDescriptor input_descriptor = (layout_id == 0) ? input_descriptor_nchw : input_descriptor_nhwc;
+
+ // Parse arguments
+ if(argc < 2)
+ {
+ // Print help
+ std::cout << "Usage: " << argv[0] << " [target] [model] [layout] [path_to_data] [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No model ID provided: using MobileNetV1_1.0_224\n\n";
+ std::cout << "No data layout provided: using NCHW\n\n";
+ std::cout << "No data folder provided: using random values\n\n";
+ }
+ else if(argc == 2)
+ {
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " [model] [layout] [path_to_data] [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No model ID provided: using MobileNetV1_1.0_224\n\n";
+ std::cout << "No data layout provided: using NCHW\n\n";
+ std::cout << "No data folder provided: using random values\n\n";
+ }
+ else if(argc == 3)
+ {
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [layout] [path_to_data] [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No data layout provided: using NCHW\n\n";
+ std::cout << "No data folder provided: using random values\n\n";
+ }
+ else if(argc == 4)
+ {
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [path_to_data] [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No data folder provided: using random values\n\n";
+ }
+ else if(argc == 5)
+ {
+ data_path = argv[4];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " " << argv[4] << " [image] [labels] [fast_math_hint]\n\n";
+ std::cout << "No image provided: using random values\n\n";
+ std::cout << "No text file with labels provided: skipping output accessor\n\n";
+ }
+ else if(argc == 6)
+ {
+ data_path = argv[4];
+ image = argv[5];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels] [fast_math_hint]\n\n";
+ std::cout << "No text file with labels provided: skipping output accessor\n\n";
+ }
+ else if(argc == 7)
+ {
+ data_path = argv[4];
+ image = argv[5];
+ label = argv[6];
+ std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " " << argv[4] << " [fast_math_hint]\n\n";
+ std::cout << "No fast math info provided: disabling fast math\n\n";
+ }
+ else
+ {
+ data_path = argv[4];
+ image = argv[5];
+ label = argv[6];
+ fast_math_hint = (std::strtol(argv[7], nullptr, 1) == 0) ? FastMathHint::Disabled : FastMathHint::Enabled;
+ }
+
+ // Add model path to data path
+ if(!data_path.empty())
+ {
+ data_path += model_path;
+ }
+
+ graph << target_hint
+ << convolution_hint
+ << depthwise_convolution_hint
+ << fast_math_hint
+ << InputLayer(input_descriptor,
+ get_input_accessor())
+ << ConvolutionLayer(
+ 3U, 3U, 32U * depth_scale,
+ get_weights_accessor(data_path, "Conv2d_0_weights.npy", DataLayout::NCHW),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR))
+ .set_name("Conv2d_0")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, "Conv2d_0_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, "Conv2d_0_BatchNorm_moving_variance.npy"),
+ get_weights_accessor(data_path, "Conv2d_0_BatchNorm_gamma.npy"),
+ get_weights_accessor(data_path, "Conv2d_0_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name("Conv2d_0/BatchNorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)).set_name("Conv2d_0/Relu6");
+ graph << get_dwsc_node(data_path, "Conv2d_1", 64 * depth_scale, PadStrideInfo(1, 1, 1, 1), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_2", 128 * depth_scale, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_3", 128 * depth_scale, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_4", 256 * depth_scale, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_5", 256 * depth_scale, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_6", 512 * depth_scale, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_7", 512 * depth_scale, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_8", 512 * depth_scale, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_9", 512 * depth_scale, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_10", 512 * depth_scale, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_11", 512 * depth_scale, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_12", 1024 * depth_scale, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << get_dwsc_node(data_path, "Conv2d_13", 1024 * depth_scale, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::CEIL), PadStrideInfo(1, 1, 0, 0));
+ graph << PoolingLayer(PoolingLayerInfo(PoolingType::AVG)).set_name("Logits/AvgPool_1a")
+ << ConvolutionLayer(
+ 1U, 1U, 1001U,
+ get_weights_accessor(data_path, "Logits_Conv2d_1c_1x1_weights.npy", DataLayout::NCHW),
+ get_weights_accessor(data_path, "Logits_Conv2d_1c_1x1_biases.npy"),
+ PadStrideInfo(1, 1, 0, 0))
+ .set_name("Logits/Conv2d_1c_1x1")
+ << ReshapeLayer(TensorShape(1001U)).set_name("Reshape")
+ << SoftmaxLayer().set_name("Softmax")
+ << OutputLayer(get_output_accessor());
+
+ // Finalize graph
+ GraphConfig config;
+ config.use_tuner = (target == 2);
+ graph.finalize(target_hint, config);
+ }
+ void do_run()
+ {
+ run_benchmark(graph);
+ }
+
+private:
+ Stream graph{ 0, "MobileNetV1" };
+
+ ConcatLayer get_dwsc_node(const std::string &data_path, std::string &&param_path,
+ unsigned int conv_filt,
+ PadStrideInfo dwc_pad_stride_info, PadStrideInfo conv_pad_stride_info)
+ {
+ std::string total_path = param_path + "_";
+ SubStream sg(graph);
+ sg << DepthwiseConvolutionLayer(
+ 3U, 3U,
+ get_weights_accessor(data_path, total_path + "depthwise_depthwise_weights.npy", DataLayout::NCHW),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ dwc_pad_stride_info)
+ .set_name(total_path + "depthwise/depthwise")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_moving_variance.npy"),
+ get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_gamma.npy"),
+ get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(total_path + "depthwise/BatchNorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)).set_name(total_path + "depthwise/Relu6")
+ << ConvolutionLayer(
+ 1U, 1U, conv_filt,
+ get_weights_accessor(data_path, total_path + "pointwise_weights.npy", DataLayout::NCHW),
+ std::unique_ptr<arm_compute::graph::ITensorAccessor>(nullptr),
+ conv_pad_stride_info)
+ .set_name(total_path + "pointwise/Conv2D")
+ << BatchNormalizationLayer(
+ get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_moving_mean.npy"),
+ get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_moving_variance.npy"),
+ get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_gamma.npy"),
+ get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_beta.npy"),
+ 0.001f)
+ .set_name(total_path + "pointwise/BatchNorm")
+ << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)).set_name(total_path + "pointwise/Relu6");
+
+ return ConcatLayer(std::move(sg));
+ }
+};
+
+/** Main program for MobileNetV1
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL, 2 = OpenCL with Tuner),
+ * [optional] Model ID (0 = MobileNetV1_1.0_224, 1 = MobileNetV1_0.75_160),
+ * [optional] Path to the weights folder,
+ * [optional] image,
+ * [optional] labels,
+ * [optional] data layout,
+ * [optional] Fast math for convolution layer (0 = DISABLED, 1 = ENABLED) )
+ */
+int main(int argc, char **argv)
+{
+ GraphMobilenetExample example;
+
+ example.do_setup(argc, argv);
+ example.do_run();
+
+ return 0;
+}
diff --git a/runtime/contrib/custom_op/README.md b/runtime/contrib/custom_op/README.md
new file mode 100644
index 000000000..7815ce9d5
--- /dev/null
+++ b/runtime/contrib/custom_op/README.md
@@ -0,0 +1,25 @@
+This document is about custom operators.
+
+# Introduction
+
+# Requirements
+
+- [ ] Support tizen in-house custom op developer
+- [ ] Minimiz exposed headers (structures and functions)
+- [ ] Provide acceptable performance
+
+# Design
+
+## Design
+
+### Workflow
+
+![](customOp-workflow.png)
+
+## Candidate Architecture 1
+
+## Candidate Architecture 2
+
+## Discussion
+
+# Conclusion
diff --git a/runtime/contrib/detection/CMakeLists.txt b/runtime/contrib/detection/CMakeLists.txt
new file mode 100644
index 000000000..37d91b527
--- /dev/null
+++ b/runtime/contrib/detection/CMakeLists.txt
@@ -0,0 +1,11 @@
+if(NOT BUILD_DETECTION_APP)
+ return()
+endif(NOT BUILD_DETECTION_APP)
+
+nnfw_find_package(Tensorflow REQUIRED)
+
+list(APPEND SOURCES detection.cpp)
+
+add_executable(detection ${SOURCES})
+target_link_libraries(detection nnfw_lib_misc)
+target_link_libraries(detection tensorflow-core)
diff --git a/runtime/contrib/detection/detection.cpp b/runtime/contrib/detection/detection.cpp
new file mode 100644
index 000000000..8fe78ca57
--- /dev/null
+++ b/runtime/contrib/detection/detection.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <tensorflow/core/public/session.h>
+
+#include <iostream>
+#include <stdexcept>
+
+#include <cassert>
+#include <cstring>
+
+#include "misc/benchmark.h"
+
+#define CHECK_TF(e) \
+ { \
+ if (!(e).ok()) \
+ { \
+ throw std::runtime_error{"'" #e "' FAILED"}; \
+ } \
+ }
+
+int main(int argc, char **argv)
+{
+ if (argc < 2)
+ {
+ std::cerr << "USAGE: " << argv[0] << " [T/F model path] [output 0] [output 1] ..." << std::endl;
+ return 255;
+ }
+
+ std::vector<std::string> output_nodes;
+
+ for (int argn = 2; argn < argc; ++argn)
+ {
+ output_nodes.emplace_back(argv[argn]);
+ }
+
+ tensorflow::Session *sess;
+
+ CHECK_TF(tensorflow::NewSession(tensorflow::SessionOptions(), &sess));
+
+ tensorflow::GraphDef graph_def;
+
+ CHECK_TF(ReadBinaryProto(tensorflow::Env::Default(), argv[1], &graph_def));
+ CHECK_TF(sess->Create(graph_def));
+
+ tensorflow::Tensor input(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, 320, 320, 3}));
+ std::vector<tensorflow::Tensor> outputs;
+
+ for (uint32_t n = 0; n < 5; ++n)
+ {
+ std::chrono::milliseconds elapsed(0);
+
+ nnfw::misc::benchmark::measure(elapsed) << [&](void) {
+ CHECK_TF(sess->Run({{"input_node", input}}, output_nodes, {}, &outputs));
+ };
+
+ std::cout << "Takes " << elapsed.count() << "ms" << std::endl;
+ }
+
+ return 0;
+}
diff --git a/runtime/contrib/heap_trace/CMakeLists.txt b/runtime/contrib/heap_trace/CMakeLists.txt
new file mode 100644
index 000000000..3043e2c0c
--- /dev/null
+++ b/runtime/contrib/heap_trace/CMakeLists.txt
@@ -0,0 +1,23 @@
+if(NOT BUILD_HEAP_TRACE)
+ return()
+endif(NOT BUILD_HEAP_TRACE)
+
+add_library(heap_trace SHARED src/cl_create_buffer_stub.cc
+ src/cl_release_mem_object.cc
+ src/cl_retain_mem_object_stub.cc
+ src/free_stub.cc
+ src/malloc_stub.cc
+ src/realloc_stub.cc
+ src/valloc_stub.cc
+ src/calloc_stub.cc
+ src/posix_memalign_stub.cc
+ src/aligned_alloc_stub.cc
+ src/symbol_searcher.cc
+ src/trace.cc
+ src/memory_pool_for_symbol_searcher_internals.cc
+)
+target_link_libraries(heap_trace PRIVATE ${CMAKE_DL_LIBS})
+
+add_subdirectory(tests)
+
+install(TARGETS heap_trace DESTINATION lib)
diff --git a/runtime/contrib/heap_trace/src/aligned_alloc_stub.cc b/runtime/contrib/heap_trace/src/aligned_alloc_stub.cc
new file mode 100644
index 000000000..c70c24e1e
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/aligned_alloc_stub.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+void *aligned_alloc(size_t alignment, size_t sz) noexcept
+{
+ static auto isOriginalFunctionCallSuccessful = [](void *result) -> bool { return result; };
+
+ if (isCurrentAllocationForSymbolSearcherInternalUsage())
+ {
+ return MemoryPoolForSymbolSearcherInternals{}.allocate(sz);
+ }
+
+ static auto originalFunction = findFunctionByName<void *, size_t, size_t>("aligned_alloc");
+ void *result = originalFunction(alignment, sz);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logAllocationEvent(result, sz);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/src/calloc_stub.cc b/runtime/contrib/heap_trace/src/calloc_stub.cc
new file mode 100644
index 000000000..adc93a209
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/calloc_stub.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+void *calloc(size_t number_of_elements, size_t size_of_one_element) noexcept
+{
+ static auto isOriginalFunctionCallSuccessful = [](void *result) -> bool { return result; };
+
+ if (isCurrentAllocationForSymbolSearcherInternalUsage())
+ {
+ return MemoryPoolForSymbolSearcherInternals{}.allocate(number_of_elements *
+ size_of_one_element);
+ }
+
+ static auto originalFunction = findFunctionByName<void *, size_t, size_t>("calloc");
+ void *result = originalFunction(number_of_elements, size_of_one_element);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logAllocationEvent(result, number_of_elements * size_of_one_element);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/src/cl_create_buffer_stub.cc b/runtime/contrib/heap_trace/src/cl_create_buffer_stub.cc
new file mode 100644
index 000000000..d9d2700ee
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/cl_create_buffer_stub.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+
+#include <CL/cl.h>
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+cl_mem clCreateBuffer(cl_context context, cl_mem_flags flags, size_t size, void *host_ptr,
+ cl_int *errcode_ret)
+{
+ static auto isOriginalFunctionCallSuccessful = [](cl_mem result) -> bool { return result; };
+
+ static auto originalFunction =
+ findFunctionByName<cl_mem, cl_context, cl_mem_flags, size_t, void *, cl_int *>(
+ "clCreateBuffer");
+ cl_mem result = originalFunction(context, flags, size, host_ptr, errcode_ret);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logAllocationEvent(result, size);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/src/cl_release_mem_object.cc b/runtime/contrib/heap_trace/src/cl_release_mem_object.cc
new file mode 100644
index 000000000..f2f249e0b
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/cl_release_mem_object.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+
+#include <CL/cl.h>
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+cl_int clReleaseMemObject(cl_mem mem)
+{
+ static auto isOriginalFunctionCallSuccessful = [](cl_int result) -> bool {
+ return result == CL_SUCCESS;
+ };
+
+ auto originalFunction = findFunctionByName<cl_int, cl_mem>("clReleaseMemObject");
+ cl_int result = originalFunction(mem);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logDeallocationEvent(mem);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/src/cl_retain_mem_object_stub.cc b/runtime/contrib/heap_trace/src/cl_retain_mem_object_stub.cc
new file mode 100644
index 000000000..b1b56b60c
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/cl_retain_mem_object_stub.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+
+#include <CL/cl.h>
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+cl_int clRetainMemObject(cl_mem mem)
+{
+ static auto isOriginalFunctionCallSuccessful = [](cl_int result) -> bool {
+ return result == CL_SUCCESS;
+ };
+
+ auto originalFunction = findFunctionByName<cl_int, cl_mem>("clRetainMemObject");
+ cl_int result = originalFunction(mem);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logAllocationEvent(mem, 0);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/src/free_stub.cc b/runtime/contrib/heap_trace/src/free_stub.cc
new file mode 100644
index 000000000..21c311dfd
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/free_stub.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+void free(void *p) noexcept
+{
+ MemoryPoolForSymbolSearcherInternals pool;
+ if (pool.containsMemorySpaceStartedFromPointer(p))
+ {
+ return pool.deallocate(p);
+ }
+
+ static auto originalFunction = findFunctionByName<void, void *>("free");
+ originalFunction(p);
+ if (!Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logDeallocationEvent(p);
+ }
+}
+}
diff --git a/runtime/contrib/heap_trace/src/function_resolver.h b/runtime/contrib/heap_trace/src/function_resolver.h
new file mode 100644
index 000000000..9b6879539
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/function_resolver.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FUNCTION_RESOLVER_H
+#define FUNCTION_RESOLVER_H
+
+#include "symbol_searcher.h"
+
+template <typename ReturnType, typename... ArgTypes>
+ReturnType (*findFunctionByName(const char *function_name))(ArgTypes...)
+{
+ auto found_symbol = findSymbol(function_name);
+ return reinterpret_cast<ReturnType (*)(ArgTypes...)>(found_symbol);
+}
+
+#endif // ! FUNCTION_RESOLVER_H
diff --git a/runtime/contrib/heap_trace/src/malloc_stub.cc b/runtime/contrib/heap_trace/src/malloc_stub.cc
new file mode 100644
index 000000000..c27dcaa14
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/malloc_stub.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+void *malloc(size_t sz) noexcept
+{
+ static auto isOriginalFunctionCallSuccessful = [](void *result) -> bool { return result; };
+
+ if (isCurrentAllocationForSymbolSearcherInternalUsage())
+ {
+ return MemoryPoolForSymbolSearcherInternals{}.allocate(sz);
+ }
+
+ static auto originalFunction = findFunctionByName<void *, size_t>("malloc");
+ void *result = originalFunction(sz);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logAllocationEvent(result, sz);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/src/memory_pool_for_symbol_searcher_internals.cc b/runtime/contrib/heap_trace/src/memory_pool_for_symbol_searcher_internals.cc
new file mode 100644
index 000000000..9778d0f7b
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/memory_pool_for_symbol_searcher_internals.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+uint8_t MemoryPoolForSymbolSearcherInternals::_buffer[MAX_SIZE] = {0};
+uint8_t *volatile MemoryPoolForSymbolSearcherInternals::_ptr_to_free_space_start = _buffer;
+size_t volatile MemoryPoolForSymbolSearcherInternals::_size_of_last_allocated_space = 0;
diff --git a/runtime/contrib/heap_trace/src/memory_pool_for_symbol_searcher_internals.h b/runtime/contrib/heap_trace/src/memory_pool_for_symbol_searcher_internals.h
new file mode 100644
index 000000000..89797ad50
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/memory_pool_for_symbol_searcher_internals.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEMORY_POOL_FOR_SYMBOL_SEARCHER_INTERNALS_H
+#define MEMORY_POOL_FOR_SYMBOL_SEARCHER_INTERNALS_H
+
+#include <cstddef>
+#include <cstdint>
+
+// TODO this class possibly should be thread safe (or all symbols should be resolved at the start of
+// application as alternative)
+class MemoryPoolForSymbolSearcherInternals
+{
+ static constexpr size_t MAX_SIZE = 65536;
+
+public:
+ bool containsMemorySpaceStartedFromPointer(void *ptr) noexcept
+ {
+ return ptr >= _buffer && ptr < _buffer + MAX_SIZE;
+ }
+
+ // TODO this function should return alighned ptr to avoid potential problems
+ void *allocate(size_t size) noexcept
+ {
+ if (isSpaceOfRequiredSizeNotAvailable(size))
+ {
+ // TODO need to signalize about error
+ }
+
+ uint8_t *ptr_to_memory_space_begin = _ptr_to_free_space_start;
+ _ptr_to_free_space_start += size;
+ _size_of_last_allocated_space = size;
+ return ptr_to_memory_space_begin;
+ }
+
+ void deallocate(void *p) noexcept
+ {
+ if (p == _ptr_to_free_space_start - _size_of_last_allocated_space)
+ {
+ _ptr_to_free_space_start -= _size_of_last_allocated_space;
+ _size_of_last_allocated_space = 0;
+ }
+ }
+
+private:
+ bool isSpaceOfRequiredSizeNotAvailable(size_t size)
+ {
+ uint8_t *ptr_to_the_free_space_after_allocation = _ptr_to_free_space_start + size;
+ size_t size_of_reserved_space_after_allocation =
+ ptr_to_the_free_space_after_allocation - _buffer;
+ if (size_of_reserved_space_after_allocation >= MAX_SIZE)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+private:
+ static uint8_t _buffer[MAX_SIZE];
+ static uint8_t *volatile _ptr_to_free_space_start;
+ static volatile size_t _size_of_last_allocated_space;
+};
+
+#endif // ! MEMORY_POOL_FOR_SYMBOL_SEARCHER_INTERNALS_H
diff --git a/runtime/contrib/heap_trace/src/posix_memalign_stub.cc b/runtime/contrib/heap_trace/src/posix_memalign_stub.cc
new file mode 100644
index 000000000..d68c5736a
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/posix_memalign_stub.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+int posix_memalign(void **memptr, size_t alignment, size_t size) noexcept
+{
+ static auto isOriginalFunctionCallSuccessful = [](int result) -> bool { return result == 0; };
+
+ if (isCurrentAllocationForSymbolSearcherInternalUsage())
+ {
+ *memptr = MemoryPoolForSymbolSearcherInternals{}.allocate(size);
+ return 0;
+ }
+
+ static auto originalFunction = findFunctionByName<int, void **, size_t, size_t>("posix_memalign");
+ int result = originalFunction(memptr, alignment, size);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logAllocationEvent(*memptr, size);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/src/realloc_stub.cc b/runtime/contrib/heap_trace/src/realloc_stub.cc
new file mode 100644
index 000000000..636cfebfe
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/realloc_stub.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+void *realloc(void *ptr, size_t sz) noexcept
+{
+ static auto isOriginalFunctionCallSuccessful = [](void *result) -> bool { return result; };
+
+ if (isCurrentAllocationForSymbolSearcherInternalUsage())
+ {
+ return MemoryPoolForSymbolSearcherInternals{}.allocate(sz);
+ }
+
+ static auto originalFunction = findFunctionByName<void *, void *, size_t>("realloc");
+ void *result = originalFunction(ptr, sz);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logDeallocationEvent(ptr);
+ GlobalTrace->logAllocationEvent(result, sz);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/src/symbol_searcher.cc b/runtime/contrib/heap_trace/src/symbol_searcher.cc
new file mode 100644
index 000000000..9aaae6a2a
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/symbol_searcher.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "symbol_searcher.h"
+
+#include <dlfcn.h>
+#include <link.h>
+
+struct SymbolDescription
+{
+ const char *name;
+ void *address = nullptr; // address in memory where this symbol can be found
+
+ SymbolDescription(const char *name) : name(name) {}
+};
+
+using InfoAboutLoadedLib = struct dl_phdr_info *;
+
+static void tryToFindSymbolInLinkedLibraries(SymbolDescription &symbol);
+static void tryToFindSymbolInAllLoadedLibraries(SymbolDescription &symbol);
+static int checkIfLibraryContainsSymbol(InfoAboutLoadedLib library_description, size_t /* size */,
+ void *data);
+static bool isSymbolAddressNotInTheSameTranslationUnit(SymbolDescription *symbol);
+void *findSymbol(const char *name)
+{
+ signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage();
+ SymbolDescription symbol(name);
+ tryToFindSymbolInLinkedLibraries(symbol);
+ if (!symbol.address)
+ {
+ tryToFindSymbolInAllLoadedLibraries(symbol);
+ }
+ signalizeThatSymbolSearcherEndedOfWork();
+ return symbol.address;
+}
+
+static void tryToFindSymbolInLinkedLibraries(SymbolDescription &symbol)
+{
+ symbol.address = dlsym(RTLD_NEXT, symbol.name);
+}
+
+static void tryToFindSymbolInAllLoadedLibraries(SymbolDescription &symbol)
+{
+ dl_iterate_phdr(checkIfLibraryContainsSymbol, &symbol);
+}
+
+static int checkIfLibraryContainsSymbol(InfoAboutLoadedLib library_description, size_t /* size */,
+ void *data)
+{
+ SymbolDescription *symbol = (SymbolDescription *)data;
+
+ void *handle = dlopen(library_description->dlpi_name, RTLD_NOW);
+ symbol->address = dlsym(handle, symbol->name);
+ dlclose(handle);
+ if (symbol->address && isSymbolAddressNotInTheSameTranslationUnit(symbol))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+static bool isSymbolAddressNotInTheSameTranslationUnit(SymbolDescription *symbol)
+{
+ void *handle = dlopen("", RTLD_NOW);
+ void *addressInTheSameTranslationUnit = dlsym(handle, symbol->name);
+ dlclose(handle);
+
+ return addressInTheSameTranslationUnit == nullptr ||
+ addressInTheSameTranslationUnit != symbol->address;
+}
+
+// TODO should be thread_local (or all symbols should be resolved at the start of application as
+// alternative)
+static volatile bool are_next_allocations_will_be_for_symbol_searcher_internal_usage = false;
+
+void signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage()
+{
+ are_next_allocations_will_be_for_symbol_searcher_internal_usage = true;
+}
+
+void signalizeThatSymbolSearcherEndedOfWork()
+{
+ are_next_allocations_will_be_for_symbol_searcher_internal_usage = false;
+}
+
+bool isCurrentAllocationForSymbolSearcherInternalUsage()
+{
+ return are_next_allocations_will_be_for_symbol_searcher_internal_usage;
+}
diff --git a/runtime/contrib/heap_trace/src/symbol_searcher.h b/runtime/contrib/heap_trace/src/symbol_searcher.h
new file mode 100644
index 000000000..2408232d6
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/symbol_searcher.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYMBOL_SEARCHER_H
+#define SYMBOL_SEARCHER_H
+
+void signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage();
+void signalizeThatSymbolSearcherEndedOfWork();
+bool isCurrentAllocationForSymbolSearcherInternalUsage();
+
+void *findSymbol(const char *name);
+
+#endif // ! SYMBOL_SEARCHER_H
diff --git a/runtime/contrib/heap_trace/src/trace.cc b/runtime/contrib/heap_trace/src/trace.cc
new file mode 100644
index 000000000..020aeb90e
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/trace.cc
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+
+#include <memory>
+
+std::unique_ptr<Trace> GlobalTrace(new Trace);
+
+bool Trace::Guard::_is_trace_not_available = true;
+thread_local bool Trace::Guard::_is_recursion_detected = false;
+
+Trace::Trace()
+{
+ if (!_out.is_open())
+ {
+ _out.open(getLogFileNameFromEnvVariable("HEAP_TRACE_LOG"));
+ }
+
+ Guard{}.markTraceAsReady();
+}
+
+const char *Trace::getLogFileNameFromEnvVariable(const char *env_variable_name)
+{
+ return getenv(env_variable_name);
+}
+
+void Trace::logAllocationEvent(void *memory_ptr, size_t size_of_allocated_space_in_bytes)
+{
+ Guard{}.signalizeAboutPossibleRecursion();
+ std::lock_guard<std::mutex> guard(_lock);
+ _total_allocated_bytes_on_cpu += size_of_allocated_space_in_bytes;
+ if (_peak_heap_usage_on_cpu < _total_allocated_bytes_on_cpu - _total_deallocated_bytes_on_cpu)
+ {
+ _peak_heap_usage_on_cpu = _total_allocated_bytes_on_cpu - _total_deallocated_bytes_on_cpu;
+ }
+ _memory_in_use_on_cpu[memory_ptr] = size_of_allocated_space_in_bytes;
+ Guard{}.signalizeThatDangerOfRecursionHasPassed();
+}
+
+void Trace::logDeallocationEvent(void *memory_ptr)
+{
+ Guard{}.signalizeAboutPossibleRecursion();
+ std::lock_guard<std::mutex> guard(_lock);
+ auto found_memory_space_description = _memory_in_use_on_cpu.find(memory_ptr);
+ if (found_memory_space_description != _memory_in_use_on_cpu.end())
+ {
+ _total_deallocated_bytes_on_cpu += found_memory_space_description->second;
+ _memory_in_use_on_cpu.erase(found_memory_space_description);
+ }
+ Guard{}.signalizeThatDangerOfRecursionHasPassed();
+}
+
+void Trace::logAllocationEvent(cl_mem memory_ptr, size_t size_of_allocated_space_in_bytes)
+{
+ Guard{}.signalizeAboutPossibleRecursion();
+ std::lock_guard<std::mutex> guard(_lock);
+ auto found_memory_space_description = _memory_in_use_on_gpu.find(memory_ptr);
+ if (found_memory_space_description == _memory_in_use_on_gpu.end())
+ {
+ _memory_in_use_on_gpu.insert(
+ std::make_pair(memory_ptr, MemoryTraits(1, size_of_allocated_space_in_bytes)));
+ _total_allocated_bytes_on_gpu += size_of_allocated_space_in_bytes;
+ if (_peak_heap_usage_on_gpu < _total_allocated_bytes_on_gpu - _total_deallocated_bytes_on_gpu)
+ {
+ _peak_heap_usage_on_gpu = _total_allocated_bytes_on_gpu - _total_deallocated_bytes_on_gpu;
+ }
+ }
+ else
+ {
+ ++found_memory_space_description->second.ref_counter;
+ }
+ Guard{}.signalizeThatDangerOfRecursionHasPassed();
+}
+
+void Trace::logDeallocationEvent(cl_mem memory_ptr)
+{
+ Guard{}.signalizeAboutPossibleRecursion();
+ std::lock_guard<std::mutex> guard(_lock);
+ auto found_memory_space_description = _memory_in_use_on_gpu.find(memory_ptr);
+ if (found_memory_space_description != _memory_in_use_on_gpu.end())
+ {
+ if (--found_memory_space_description->second.ref_counter == 0)
+ {
+ _total_deallocated_bytes_on_gpu += found_memory_space_description->second.size;
+ _memory_in_use_on_gpu.erase(found_memory_space_description);
+ }
+ }
+ Guard{}.signalizeThatDangerOfRecursionHasPassed();
+}
+
+Trace::~Trace()
+{
+ Guard{}.markTraceAsNotReady();
+
+ _out << "On CPU - Peak heap usage: " << _peak_heap_usage_on_cpu
+ << " B, Total allocated: " << _total_allocated_bytes_on_cpu
+ << " B, Total deallocated: " << _total_deallocated_bytes_on_cpu << " B\n";
+ _out << "On GPU - Peak mem usage: " << _peak_heap_usage_on_gpu
+ << " B, Total allocated: " << _total_allocated_bytes_on_gpu
+ << " B, Total deallocated: " << _total_deallocated_bytes_on_gpu << " B\n";
+}
diff --git a/runtime/contrib/heap_trace/src/trace.h b/runtime/contrib/heap_trace/src/trace.h
new file mode 100644
index 000000000..647c51d54
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/trace.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TRACE_H_
+#define TRACE_H_
+
+#include <CL/cl.h>
+
+#include <unordered_map>
+#include <fstream>
+#include <mutex>
+
+class Trace
+{
+ struct MemoryTraits
+ {
+ size_t ref_counter;
+ size_t size;
+
+ MemoryTraits(size_t init_counter_value, size_t size_of_allocated_memory)
+ : ref_counter(init_counter_value), size(size_of_allocated_memory)
+ {
+ }
+ };
+
+public:
+ class Guard
+ {
+ friend class Trace;
+
+ public:
+ bool isActive() { return _is_trace_not_available || _is_recursion_detected; }
+
+ private:
+ void markTraceAsReady() { _is_trace_not_available = false; }
+ void markTraceAsNotReady() { _is_trace_not_available = true; }
+ void signalizeAboutPossibleRecursion() { _is_recursion_detected = true; }
+ void signalizeThatDangerOfRecursionHasPassed() { _is_recursion_detected = false; }
+
+ private:
+ static bool _is_trace_not_available;
+ static thread_local bool _is_recursion_detected;
+ };
+
+public:
+ Trace();
+ Trace(const Trace &) = delete;
+ const Trace &operator=(const Trace &) = delete;
+
+ void logAllocationEvent(void *memory_ptr, size_t size_of_allocated_space_in_bytes);
+ void logAllocationEvent(cl_mem memory_ptr, size_t size_of_allocated_space_in_bytes);
+ void logDeallocationEvent(void *memory_ptr);
+ void logDeallocationEvent(cl_mem memory_ptr);
+
+ ~Trace();
+
+private:
+ const char *getLogFileNameFromEnvVariable(const char *env_variable_name);
+
+private:
+ std::mutex _lock;
+ std::ofstream _out;
+ size_t _total_allocated_bytes_on_cpu = 0;
+ size_t _total_deallocated_bytes_on_cpu = 0;
+ size_t _peak_heap_usage_on_cpu = 0;
+ size_t _total_allocated_bytes_on_gpu = 0;
+ size_t _total_deallocated_bytes_on_gpu = 0;
+ size_t _peak_heap_usage_on_gpu = 0;
+ std::unordered_map<void *, size_t> _memory_in_use_on_cpu;
+ std::unordered_map<cl_mem, MemoryTraits> _memory_in_use_on_gpu;
+};
+
+#endif // !TRACE_H
diff --git a/runtime/contrib/heap_trace/src/valloc_stub.cc b/runtime/contrib/heap_trace/src/valloc_stub.cc
new file mode 100644
index 000000000..344591630
--- /dev/null
+++ b/runtime/contrib/heap_trace/src/valloc_stub.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trace.h"
+#include "function_resolver.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <memory>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+extern "C" {
+
+void *valloc(size_t sz) noexcept
+{
+ static auto isOriginalFunctionCallSuccessful = [](void *result) -> bool { return result; };
+
+ if (isCurrentAllocationForSymbolSearcherInternalUsage())
+ {
+ return MemoryPoolForSymbolSearcherInternals{}.allocate(sz);
+ }
+
+ static auto originalFunction = findFunctionByName<void *, size_t>("valloc");
+ void *result = originalFunction(sz);
+ if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive())
+ {
+ GlobalTrace->logAllocationEvent(result, sz);
+ }
+
+ return result;
+}
+}
diff --git a/runtime/contrib/heap_trace/tests/CMakeLists.txt b/runtime/contrib/heap_trace/tests/CMakeLists.txt
new file mode 100644
index 000000000..14e083e60
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/CMakeLists.txt
@@ -0,0 +1,48 @@
+set(HEAP_TRACE_TESTS heap_trace_test)
+
+find_package(OpenCL REQUIRED)
+
+add_library(test_sample1 SHARED src/test_sample1/test_sample1.cc)
+
+add_library(test_sample2 SHARED src/test_sample2/test_sample2.cc)
+target_link_libraries(test_sample2 test_sample3)
+
+add_library(test_sample3 SHARED src/test_sample3/test_sample3.cc)
+
+add_library(test_sample4 SHARED src/test_sample4/test_sample4.cc)
+
+add_executable(${HEAP_TRACE_TESTS} src/cl_release_mem_object_interception_test.cc
+ src/symbol_searcher_test.cc
+ src/cl_create_buffer_interception_test.cc
+ src/cl_retain_mem_object_interception_test.cc
+ src/free_interception_test.cc
+ src/main.cc
+ src/common_test_environment.cc
+ src/trace_test.cc
+ src/malloc_interception_test.cc
+ src/realloc_interception_test.cc
+ src/valloc_interception_test.cc
+ src/calloc_interception_test.cc
+ src/posix_memalign_interception_test.cc
+ src/aligned_alloc_interception_test.cc
+ src/file_content_manipulations.cc
+ src/memory_pool_for_symbol_searcher_internals_test.cc
+ )
+target_include_directories(${HEAP_TRACE_TESTS} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src)
+target_link_libraries(${HEAP_TRACE_TESTS} test_sample1)
+target_link_libraries(${HEAP_TRACE_TESTS} heap_trace)
+target_link_libraries(${HEAP_TRACE_TESTS} test_sample4)
+target_link_libraries(${HEAP_TRACE_TESTS} gtest)
+target_link_libraries(${HEAP_TRACE_TESTS} gtest_main)
+target_link_libraries(${HEAP_TRACE_TESTS} ${LIB_PTHREAD})
+target_link_libraries(${HEAP_TRACE_TESTS} ${CMAKE_DL_LIBS})
+target_link_libraries(${HEAP_TRACE_TESTS} ${OpenCL_LIBRARY})
+target_link_libraries(${HEAP_TRACE_TESTS} stdc++fs)
+
+add_test(${HEAP_TRACE_TESTS} ${HEAP_TRACE_TESTS})
+
+install(TARGETS test_sample1 DESTINATION unittest)
+install(TARGETS test_sample2 DESTINATION unittest)
+install(TARGETS test_sample3 DESTINATION unittest)
+install(TARGETS test_sample4 DESTINATION unittest)
+install(TARGETS ${HEAP_TRACE_TESTS} DESTINATION unittest)
diff --git a/runtime/contrib/heap_trace/tests/src/aligned_alloc_interception_test.cc b/runtime/contrib/heap_trace/tests/src/aligned_alloc_interception_test.cc
new file mode 100644
index 000000000..29e9a855d
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/aligned_alloc_interception_test.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+#include "symbol_searcher.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <limits>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct AlignedAllocStub : public TestEnv
+{
+ AlignedAllocStub() : TestEnv("aligned_alloc_interception_test.log") {}
+};
+
+TEST_F(AlignedAllocStub, must_allocate_space_as_standard_aligned_alloc)
+{
+ void *p = aligned_alloc(4, 128);
+
+ ASSERT_TRUE(p);
+ free(p);
+}
+
+TEST_F(AlignedAllocStub, must_log_allocation_events_if_trace_is_ready_for_it)
+{
+ GlobalTrace.reset();
+ void *p1 = aligned_alloc(4, 1024);
+
+ GlobalTrace.reset(new Trace);
+ void *p2 = aligned_alloc(4, 128);
+ void *p3 = aligned_alloc(4, 64);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p1 && p2 && p3);
+ ASSERT_STREQ(getContentOfFile("aligned_alloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 192 B, Total allocated: 192 B, Total deallocated: 0 "
+ "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+ free(p1);
+ free(p2);
+ free(p3);
+}
+
+TEST_F(AlignedAllocStub, must_not_do_the_record_about_allocation_event_if_original_function_failed)
+{
+ void *p = aligned_alloc(1, std::numeric_limits<size_t>::max());
+ GlobalTrace.reset();
+
+ ASSERT_FALSE(p);
+ ASSERT_STREQ(getContentOfFile("aligned_alloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(AlignedAllocStub,
+ should_allocate_memory_from_pool_for_symbol_searcher_internal_usage_if_need)
+{
+ signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage();
+ void *p = aligned_alloc(4, 1024);
+ signalizeThatSymbolSearcherEndedOfWork();
+ GlobalTrace.reset();
+
+ MemoryPoolForSymbolSearcherInternals pool;
+ ASSERT_TRUE(p);
+ ASSERT_TRUE(pool.containsMemorySpaceStartedFromPointer(p));
+ ASSERT_STREQ(getContentOfFile("aligned_alloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/calloc_interception_test.cc b/runtime/contrib/heap_trace/tests/src/calloc_interception_test.cc
new file mode 100644
index 000000000..56765e977
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/calloc_interception_test.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+#include "symbol_searcher.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <limits>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct CallocStub : public TestEnv
+{
+ CallocStub() : TestEnv("calloc_interception_test.log") {}
+};
+
+TEST_F(CallocStub, must_allocate_space_as_standard_calloc)
+{
+ std::array<char, 128 * 4> reference_data;
+ reference_data.fill(0);
+ void *p = calloc(128, 4);
+ ASSERT_TRUE(p);
+ ASSERT_TRUE(memcmp(p, reference_data.data(), reference_data.size()) == 0);
+ free(p);
+}
+
+TEST_F(CallocStub, must_log_allocation_events_if_trace_is_ready_for_it)
+{
+ GlobalTrace.reset();
+ void *p1 = calloc(1024, 4);
+
+ GlobalTrace.reset(new Trace);
+ void *p2 = calloc(128, 4);
+ void *p3 = calloc(64, 4);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p1 && p2 && p3);
+ ASSERT_STREQ(getContentOfFile("calloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 768 B, Total allocated: 768 B, Total deallocated: 0 "
+ "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+ free(p1);
+ free(p2);
+ free(p3);
+}
+
+TEST_F(CallocStub, must_not_do_the_record_about_allocation_event_if_original_function_failed)
+{
+ void *p = calloc(1, std::numeric_limits<size_t>::max());
+ GlobalTrace.reset();
+
+ ASSERT_FALSE(p);
+ ASSERT_STREQ(getContentOfFile("calloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(CallocStub, should_allocate_memory_from_pool_for_symbol_searcher_internal_usage_if_need)
+{
+ signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage();
+ void *p = calloc(10, 102);
+ signalizeThatSymbolSearcherEndedOfWork();
+ GlobalTrace.reset();
+
+ MemoryPoolForSymbolSearcherInternals pool;
+ ASSERT_TRUE(p);
+ ASSERT_TRUE(pool.containsMemorySpaceStartedFromPointer(p));
+ ASSERT_STREQ(getContentOfFile("calloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/cl_create_buffer_interception_test.cc b/runtime/contrib/heap_trace/tests/src/cl_create_buffer_interception_test.cc
new file mode 100644
index 000000000..33d01868e
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/cl_create_buffer_interception_test.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+
+#include <CL/cl.h>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct ClCreateBufferStub : public TestEnv
+{
+ cl_context context;
+
+ ClCreateBufferStub() : TestEnv("./cl_create_buffer_interception_test.log") {}
+
+ void SetUp() final
+ {
+ cl_device_id device_id;
+ int err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL);
+ context = clCreateContext(0, 1, &device_id, NULL, NULL, &err);
+
+ TestEnv::SetUp();
+ }
+
+ void TearDown() final
+ {
+ TestEnv::TearDown();
+
+ clReleaseContext(context);
+ }
+};
+
+TEST_F(ClCreateBufferStub, must_allocate_space_as_standard_ocl_function)
+{
+ cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024 * 1024, NULL, NULL);
+
+ ASSERT_TRUE(mem);
+
+ clReleaseMemObject(mem);
+}
+
+TEST_F(ClCreateBufferStub, must_log_allocation_events_if_trace_is_ready_for_it)
+{
+ GlobalTrace.reset();
+ clReleaseMemObject(clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, NULL, NULL));
+
+ GlobalTrace.reset(new Trace);
+ clReleaseMemObject(clCreateBuffer(context, CL_MEM_READ_WRITE, 128, NULL, NULL));
+ clReleaseMemObject(clCreateBuffer(context, CL_MEM_READ_WRITE, 64, NULL, NULL));
+ GlobalTrace.reset();
+
+ ASSERT_STREQ(getContentOfFile("./cl_create_buffer_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 128 B, Total allocated: 192 B, Total deallocated: 192 B\n");
+}
+
+TEST_F(ClCreateBufferStub,
+ must_not_do_the_record_about_allocation_event_if_original_function_failed)
+{
+ cl_context badContext = nullptr;
+ cl_mem p = clCreateBuffer(badContext, CL_MEM_READ_WRITE, 1024, nullptr, nullptr);
+ GlobalTrace.reset();
+
+ ASSERT_FALSE(p);
+ ASSERT_STREQ(getContentOfFile("./cl_create_buffer_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/cl_release_mem_object_interception_test.cc b/runtime/contrib/heap_trace/tests/src/cl_release_mem_object_interception_test.cc
new file mode 100644
index 000000000..49b8fd994
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/cl_release_mem_object_interception_test.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+
+#include <CL/cl.h>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct ClReleaseMemObjectStub : public TestEnv
+{
+ cl_context context;
+
+ ClReleaseMemObjectStub() : TestEnv("./cl_release_mem_object_interception_test.log") {}
+
+ void SetUp() final
+ {
+ cl_device_id device_id;
+ int err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL);
+ context = clCreateContext(0, 1, &device_id, NULL, NULL, &err);
+
+ TestEnv::SetUp();
+ }
+
+ void TearDown() final
+ {
+ TestEnv::TearDown();
+
+ clReleaseContext(context);
+ }
+};
+
+TEST_F(ClReleaseMemObjectStub, should_work_as_standard_version)
+{
+ cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, NULL, NULL);
+ clReleaseMemObject(mem);
+ ASSERT_TRUE(mem);
+}
+
+TEST_F(ClReleaseMemObjectStub, must_log_deallocation_events_if_trace_is_ready_for_it)
+{
+ GlobalTrace.reset();
+ cl_mem mem1 = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, NULL, NULL);
+ ASSERT_TRUE(mem1);
+ clReleaseMemObject(mem1);
+
+ GlobalTrace.reset(new Trace);
+ cl_mem mem2 = clCreateBuffer(context, CL_MEM_READ_WRITE, 128, NULL, NULL);
+ cl_mem mem3 = clCreateBuffer(context, CL_MEM_READ_WRITE, 64, NULL, NULL);
+ ASSERT_TRUE(mem2 && mem3);
+ clReleaseMemObject(mem2);
+ clReleaseMemObject(mem3);
+ GlobalTrace.reset();
+
+ ASSERT_STREQ(getContentOfFile("./cl_release_mem_object_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 192 B, Total allocated: 192 B, Total deallocated: 192 B\n");
+}
+
+TEST_F(ClReleaseMemObjectStub, must_log_deallocation_event_only_if_reference_counter_equals_to_zero)
+{
+ cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, NULL, NULL);
+ clRetainMemObject(mem);
+ clReleaseMemObject(mem);
+ GlobalTrace.reset();
+ ASSERT_STREQ(getContentOfFile("./cl_release_mem_object_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 1024 B, Total allocated: 1024 B, Total deallocated: 0 B\n");
+ clReleaseMemObject(mem);
+
+ GlobalTrace.reset(new Trace);
+ mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, NULL, NULL);
+ clRetainMemObject(mem);
+ clReleaseMemObject(mem);
+ clReleaseMemObject(mem);
+ GlobalTrace.reset();
+ ASSERT_STREQ(
+ getContentOfFile("./cl_release_mem_object_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 1024 B, Total allocated: 1024 B, Total deallocated: 1024 B\n");
+}
+
+TEST_F(ClReleaseMemObjectStub, must_not_log_deallocation_event_if_original_function_failed)
+{
+ cl_mem mem;
+ ASSERT_NE(clReleaseMemObject(mem), CL_SUCCESS);
+
+ GlobalTrace.reset();
+
+ ASSERT_STREQ(getContentOfFile("./cl_release_mem_object_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/cl_retain_mem_object_interception_test.cc b/runtime/contrib/heap_trace/tests/src/cl_retain_mem_object_interception_test.cc
new file mode 100644
index 000000000..f0b1902dc
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/cl_retain_mem_object_interception_test.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+
+#include <CL/cl.h>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct ClRetainMemObjectStub : public TestEnv
+{
+ cl_context context;
+
+ ClRetainMemObjectStub() : TestEnv("cl_retain_mem_object_interception_test.log") {}
+
+ void SetUp() final
+ {
+ cl_device_id device_id;
+ int err = clGetDeviceIDs(nullptr, CL_DEVICE_TYPE_GPU, 1, &device_id, nullptr);
+ context = clCreateContext(0, 1, &device_id, nullptr, nullptr, &err);
+ TestEnv::SetUp();
+ }
+
+ void TearDown() final
+ {
+ TestEnv::TearDown();
+ clReleaseContext(context);
+ }
+};
+
+TEST_F(ClRetainMemObjectStub, must_work_as_standard_version)
+{
+ cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024 * 1024, nullptr, nullptr);
+ cl_int retain_mem_result = clRetainMemObject(mem);
+ cl_int release_mem_result1 = clReleaseMemObject(mem);
+ cl_int release_mem_result2 = clReleaseMemObject(mem);
+
+ cl_mem bad_mem_object = nullptr;
+ cl_int retain_mem_result_with_bad_mem_object = clRetainMemObject(bad_mem_object);
+
+ ASSERT_TRUE(mem);
+ ASSERT_TRUE(retain_mem_result == CL_SUCCESS);
+ ASSERT_TRUE(release_mem_result1 == CL_SUCCESS);
+ ASSERT_TRUE(release_mem_result2 == CL_SUCCESS);
+ ASSERT_TRUE(retain_mem_result_with_bad_mem_object == CL_INVALID_MEM_OBJECT);
+}
+
+TEST_F(ClRetainMemObjectStub, must_do_not_log_new_allocation_event_just_increase_reference_count)
+{
+ GlobalTrace.reset();
+ cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, nullptr, nullptr);
+
+ GlobalTrace.reset(new Trace);
+ clRetainMemObject(mem);
+ GlobalTrace.reset();
+
+ cl_int release_mem_result1 = clReleaseMemObject(mem);
+ cl_int release_mem_result2 = clReleaseMemObject(mem);
+ ASSERT_TRUE(release_mem_result1 == CL_SUCCESS);
+ ASSERT_TRUE(release_mem_result2 == CL_SUCCESS);
+ ASSERT_STREQ(getContentOfFile("cl_retain_mem_object_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/common_test_environment.cc b/runtime/contrib/heap_trace/tests/src/common_test_environment.cc
new file mode 100644
index 000000000..e5c4dc121
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/common_test_environment.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+
+#include "trace.h"
+
+#include <experimental/filesystem>
+
+namespace fs = std::experimental::filesystem;
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+void TestEnv::SetUp() { configureTraceToMakeLogInFile(); }
+
+void TestEnv::TearDown() { removeOldTraceLogIfNeed(); }
+
+void TestEnv::configureTraceToMakeLogInFile()
+{
+ removeOldTraceLogIfNeed();
+ setNewNameOfTraceLog();
+}
+
+void TestEnv::removeOldTraceLogIfNeed()
+{
+ GlobalTrace.reset();
+ const char *trace_log_name = getenv("HEAP_TRACE_LOG");
+ if (trace_log_name)
+ {
+ fs::remove(trace_log_name);
+ }
+}
+
+void TestEnv::setNewNameOfTraceLog()
+{
+ setenv("HEAP_TRACE_LOG", test_log_file.c_str(), 1);
+ GlobalTrace.reset(new ::Trace);
+}
diff --git a/runtime/contrib/heap_trace/tests/src/common_test_environment.h b/runtime/contrib/heap_trace/tests/src/common_test_environment.h
new file mode 100644
index 000000000..8c4c9e396
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/common_test_environment.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMMON_TEST_ENVIRONMENT_H
+#define COMMON_TEST_ENVIRONMENT_H
+
+#include "gtest/gtest.h"
+
+struct TestEnv : public ::testing::Test
+{
+ TestEnv(const char *log_file) : test_log_file(log_file) {}
+
+ void SetUp() override;
+ void TearDown() override;
+
+private:
+ void configureTraceToMakeLogInFile();
+ void removeOldTraceLogIfNeed();
+ void setNewNameOfTraceLog();
+
+private:
+ std::string test_log_file;
+};
+
+#endif // ! COMMON_TEST_ENVIRONMENT_H
diff --git a/runtime/contrib/heap_trace/tests/src/file_content_manipulations.cc b/runtime/contrib/heap_trace/tests/src/file_content_manipulations.cc
new file mode 100644
index 000000000..0c968ab4b
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/file_content_manipulations.cc
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "file_content_manipulations.h"
+
+#include <fstream>
+
+std::string getContentOfFile(const char *file_name)
+{
+ std::ifstream in(file_name);
+ return std::string((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
+}
diff --git a/runtime/contrib/heap_trace/tests/src/file_content_manipulations.h b/runtime/contrib/heap_trace/tests/src/file_content_manipulations.h
new file mode 100644
index 000000000..ba938931c
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/file_content_manipulations.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_SUPPORT_H
+#define TEST_SUPPORT_H
+
+#include <string>
+
+std::string getContentOfFile(const char *file_name);
+
+#endif //! TEST_SUPPORT_H
diff --git a/runtime/contrib/heap_trace/tests/src/free_interception_test.cc b/runtime/contrib/heap_trace/tests/src/free_interception_test.cc
new file mode 100644
index 000000000..07aa88680
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/free_interception_test.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct FreeStub : public TestEnv
+{
+ FreeStub() : TestEnv("./free_interception_test.log") {}
+};
+
+TEST_F(FreeStub, should_work_as_standard_version)
+{
+ void *p = malloc(1024);
+ free(p);
+ ASSERT_TRUE(p);
+ // TODO Bad test. Need use death test from Google test framework
+}
+
+TEST_F(FreeStub, must_log_deallocation_events_if_trace_is_ready_for_it)
+{
+ GlobalTrace.reset();
+ void *p1 = malloc(1024);
+ ASSERT_TRUE(p1);
+ free(p1);
+
+ GlobalTrace.reset(new Trace);
+ void *p2 = malloc(128);
+ void *p3 = malloc(64);
+ ASSERT_TRUE(p2 && p3);
+ free(p2);
+ free(p3);
+ GlobalTrace.reset();
+
+ ASSERT_STREQ(getContentOfFile("./free_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 192 B, Total allocated: 192 B, Total deallocated: 192 "
+ "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(FreeStub, can_deallocate_memory_using_pool_for_symbol_searcher_internals)
+{
+
+ MemoryPoolForSymbolSearcherInternals pool;
+ void *volatile p1 = pool.allocate(1024);
+ free(p1);
+ void *volatile p2 = pool.allocate(1024);
+ free(p2);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p1 == p2);
+ ASSERT_STREQ(getContentOfFile("./free_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 "
+ "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/main.cc b/runtime/contrib/heap_trace/tests/src/main.cc
new file mode 100644
index 000000000..b53b2030b
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/main.cc
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+
+int main(int argc, char *argv[])
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/runtime/contrib/heap_trace/tests/src/malloc_interception_test.cc b/runtime/contrib/heap_trace/tests/src/malloc_interception_test.cc
new file mode 100644
index 000000000..ea3eb8256
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/malloc_interception_test.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+#include "symbol_searcher.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <limits>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct MallocStub : public TestEnv
+{
+ MallocStub() : TestEnv("./malloc_interception_test.log") {}
+};
+
+TEST_F(MallocStub, must_allocate_space_as_standard_malloc)
+{
+ void *p = malloc(128);
+
+ ASSERT_TRUE(p);
+ free(p);
+}
+
+TEST_F(MallocStub, must_log_allocation_events_if_trace_is_ready_for_it)
+{
+ GlobalTrace.reset();
+ void *p1 = malloc(1024);
+
+ GlobalTrace.reset(new Trace);
+ void *p2 = malloc(128);
+ void *p3 = malloc(64);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p1 && p2 && p3);
+ ASSERT_STREQ(getContentOfFile("./malloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 192 B, Total allocated: 192 B, Total deallocated: 0 "
+ "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+ free(p1);
+ free(p2);
+ free(p3);
+}
+
+TEST_F(MallocStub, must_not_do_the_record_about_allocation_event_if_original_function_failed)
+{
+ void *p = malloc(std::numeric_limits<size_t>::max());
+ GlobalTrace.reset();
+
+ ASSERT_FALSE(p);
+ ASSERT_STREQ(getContentOfFile("./malloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(MallocStub, should_allocate_memory_from_pool_for_symbol_searcher_internal_usage_if_need)
+{
+ signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage();
+ void *p = malloc(1024);
+ signalizeThatSymbolSearcherEndedOfWork();
+ GlobalTrace.reset();
+
+ MemoryPoolForSymbolSearcherInternals pool;
+ ASSERT_TRUE(p);
+ ASSERT_TRUE(pool.containsMemorySpaceStartedFromPointer(p));
+ ASSERT_STREQ(getContentOfFile("./malloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(
+ MallocStub,
+ should_not_influence_on_trace_results_even_if_orignal_function_return_any_not_null_ptr_when_incoming_size_is_zero)
+{
+ void *p = malloc(0);
+ free(p);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p);
+ ASSERT_STREQ(getContentOfFile("./malloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/memory_pool_for_symbol_searcher_internals_test.cc b/runtime/contrib/heap_trace/tests/src/memory_pool_for_symbol_searcher_internals_test.cc
new file mode 100644
index 000000000..c0e2e1d3c
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/memory_pool_for_symbol_searcher_internals_test.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+namespace backstage
+{
+
+struct MemoryPoolForSymbolSearcherInternals : public ::testing::Test
+{
+};
+
+TEST_F(MemoryPoolForSymbolSearcherInternals, can_help_users_allocate_deallocate_memory)
+{
+ ::MemoryPoolForSymbolSearcherInternals memory;
+
+ void *p1 = memory.allocate(1024);
+
+ ASSERT_TRUE(p1);
+ memory.deallocate(p1);
+}
+
+TEST_F(MemoryPoolForSymbolSearcherInternals,
+ should_reuse_memory_if_it_deallocated_just_after_allocations)
+{
+ ::MemoryPoolForSymbolSearcherInternals memory;
+
+ void *p1 = memory.allocate(1024);
+ memory.deallocate(p1);
+ void *p2 = memory.allocate(128);
+ memory.deallocate(p2);
+ void *p3 = memory.allocate(3467);
+ memory.deallocate(p3);
+
+ ASSERT_TRUE(p1 && p2 && p3);
+ ASSERT_TRUE(p1 == p2);
+ ASSERT_TRUE(p2 == p3);
+}
+
+TEST_F(MemoryPoolForSymbolSearcherInternals,
+ can_define_either_contains_memory_starting_from_incoming_pointer_or_not)
+{
+ ::MemoryPoolForSymbolSearcherInternals memory;
+
+ void *p1 = memory.allocate(1024);
+ void *p2 = malloc(1024);
+
+ ASSERT_TRUE(memory.containsMemorySpaceStartedFromPointer(p1));
+ ASSERT_FALSE(memory.containsMemorySpaceStartedFromPointer(p2));
+
+ memory.deallocate(p1);
+ free(p2);
+}
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/posix_memalign_interception_test.cc b/runtime/contrib/heap_trace/tests/src/posix_memalign_interception_test.cc
new file mode 100644
index 000000000..52c06e3de
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/posix_memalign_interception_test.cc
@@ -0,0 +1,101 @@
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+#include "symbol_searcher.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <limits>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct PosixMemalignStub : public TestEnv
+{
+ PosixMemalignStub() : TestEnv("posix_memalign_interception_test.log") {}
+};
+
+TEST_F(PosixMemalignStub, must_allocate_space_as_standard_posix_memalign)
+{
+ void *p = nullptr;
+ int res = posix_memalign(&p, 4, 12);
+
+ ASSERT_TRUE(res == 0);
+ ASSERT_TRUE(p);
+ free(p);
+}
+
+TEST_F(PosixMemalignStub, must_log_allocation_events_if_trace_is_ready_for_it)
+{
+ GlobalTrace.reset();
+ void *p1 = nullptr;
+ int res1 = posix_memalign(&p1, 4, 1024);
+
+ GlobalTrace.reset(new Trace);
+ void *p2 = nullptr;
+ int res2 = posix_memalign(&p2, 4, 128);
+ void *p3 = nullptr;
+ int res3 = posix_memalign(&p3, 4, 64);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(res1 == 0 && res2 == 0 && res3 == 0);
+ ASSERT_TRUE(p1 && p2 && p3);
+ ASSERT_STREQ(getContentOfFile("posix_memalign_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 192 B, Total allocated: 192 B, Total deallocated: 0 "
+ "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+ free(p1);
+ free(p2);
+ free(p3);
+}
+
+TEST_F(PosixMemalignStub, must_not_do_the_record_about_allocation_event_if_original_function_failed)
+{
+ void *p = nullptr;
+ int res = posix_memalign(&p, 1, std::numeric_limits<size_t>::max());
+ GlobalTrace.reset();
+
+ ASSERT_FALSE(res == 0);
+ ASSERT_FALSE(p);
+ ASSERT_STREQ(getContentOfFile("posix_memalign_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(PosixMemalignStub,
+ should_allocate_memory_from_pool_for_symbol_searcher_internal_usage_if_need)
+{
+ signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage();
+ void *p = nullptr;
+ int res = posix_memalign(&p, 1, 1024);
+ signalizeThatSymbolSearcherEndedOfWork();
+ GlobalTrace.reset();
+
+ MemoryPoolForSymbolSearcherInternals pool;
+ ASSERT_TRUE(res == 0);
+ ASSERT_TRUE(p);
+ ASSERT_TRUE(pool.containsMemorySpaceStartedFromPointer(p));
+ ASSERT_STREQ(getContentOfFile("posix_memalign_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/realloc_interception_test.cc b/runtime/contrib/heap_trace/tests/src/realloc_interception_test.cc
new file mode 100644
index 000000000..59660fad4
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/realloc_interception_test.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+#include "symbol_searcher.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <limits>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct ReallocStub : public TestEnv
+{
+ ReallocStub() : TestEnv("./realloc_interception_test.log") {}
+};
+
+TEST_F(ReallocStub, must_allocate_space_as_standard_realloc)
+{
+ void *p = malloc(128);
+ p = realloc(p, 1024);
+
+ ASSERT_TRUE(p);
+ free(p);
+}
+
+TEST_F(ReallocStub, must_log_allocation_deallocation_events_if_trace_is_ready_for_it)
+{
+ std::array<char, 1024> reference_data;
+ reference_data.fill('a');
+ void *p1 = malloc(1024);
+ memcpy(p1, reference_data.data(), reference_data.size());
+ void *p2 = realloc(p1, 64);
+ void *p3 = realloc(p2, 128);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p3);
+ ASSERT_TRUE(memcmp(p3, reference_data.data(), 64) == 0);
+ ASSERT_STREQ(getContentOfFile("./realloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 1024 B, Total allocated: 1216 B, Total deallocated: 1088 "
+ "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+ free(p3);
+}
+
+TEST_F(ReallocStub,
+ must_not_do_the_record_about_allocation_deallocation_events_if_original_function_failed)
+{
+ GlobalTrace.reset();
+ void *p = malloc(128);
+ GlobalTrace.reset(new Trace);
+
+ void *ptr_after_realloc = realloc(p, std::numeric_limits<size_t>::max());
+ ptr_after_realloc = realloc(p, 0);
+ GlobalTrace.reset();
+
+ ASSERT_FALSE(ptr_after_realloc);
+ ASSERT_STREQ(getContentOfFile("./realloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+
+ free(p);
+}
+
+TEST_F(ReallocStub, should_work_as_malloc_when_incoming_ptr_is_equal_to_nullptr)
+{
+ void *p = realloc(nullptr, 1024);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p);
+ ASSERT_STREQ(
+ getContentOfFile("./realloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 1024 B, Total allocated: 1024 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+
+ free(p);
+}
+
+TEST_F(
+ ReallocStub,
+ should_not_influence_on_trace_results_even_if_orignal_function_return_any_not_null_ptr_when_incoming_size_is_zero_and_ptr_is_null)
+{
+ void *p = realloc(nullptr, 0);
+ free(p);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p);
+ ASSERT_STREQ(getContentOfFile("./realloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(ReallocStub, should_allocate_memory_from_pool_for_symbol_searcher_internal_usage_if_need)
+{
+ signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage();
+ void *p = malloc(128);
+ p = realloc(p, 1024);
+ signalizeThatSymbolSearcherEndedOfWork();
+ GlobalTrace.reset();
+
+ MemoryPoolForSymbolSearcherInternals pool;
+ ASSERT_TRUE(p);
+ ASSERT_TRUE(pool.containsMemorySpaceStartedFromPointer(p));
+ ASSERT_STREQ(getContentOfFile("./realloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/symbol_searcher_test.cc b/runtime/contrib/heap_trace/tests/src/symbol_searcher_test.cc
new file mode 100644
index 000000000..59fdeedc9
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/symbol_searcher_test.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+#include "test_sample1.h"
+#include "test_sample2.h"
+#include "test_sample4.h"
+
+#include "symbol_searcher.h"
+#include "trace.h"
+
+#include <dlfcn.h>
+#include <linux/limits.h>
+#include <unistd.h>
+
+#include <experimental/filesystem>
+
+namespace fs = std::experimental::filesystem;
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+fs::path exePath()
+{
+ char result[PATH_MAX] = {0};
+ ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
+ return fs::path(result).parent_path();
+}
+
+namespace backstage
+{
+
+struct SymbolSearcher : TestEnv
+{
+ SymbolSearcher() : TestEnv("./symbol_searcher_test.log") {}
+};
+
+TEST_F(SymbolSearcher, should_find_symbol_in_linked_library)
+{
+ ASSERT_TRUE((void *)funcDefinedOnlyInTestSample4 == findSymbol("funcDefinedOnlyInTestSample4"));
+}
+
+TEST_F(SymbolSearcher, should_find_symbol_in_library_which_have_been_loaded_in_runtime)
+{
+ fs::path pathToTestLib = exePath() / "libtest_sample2.so";
+ void *handle = dlopen(pathToTestLib.c_str(), RTLD_NOW);
+
+ ASSERT_TRUE(handle);
+ ASSERT_TRUE(dlsym(handle, "funcDefinedOnlyInTestSample2") ==
+ findSymbol("funcDefinedOnlyInTestSample2"));
+ dlclose(handle);
+}
+
+TEST_F(SymbolSearcher,
+ should_ignore_symbols_found_in_current_translation_unit_if_there_is_another_alternative)
+{
+ fs::path pathToTestSample2 = exePath() / "libtest_sample2.so";
+ void *test_sample2_handle = dlopen(pathToTestSample2.c_str(), RTLD_NOW);
+ void *func_addr_in_test_sample2 =
+ dlsym(test_sample2_handle, "funcWhichCallFuncDefinedInTestSample3");
+
+ ASSERT_TRUE(test_sample2_handle);
+ ASSERT_TRUE((void *)funcDefinedInTestSample3_ButWrappedInTestSample1 !=
+ reinterpret_cast<void *(*)()>(func_addr_in_test_sample2)());
+
+ dlclose(test_sample2_handle);
+}
+
+TEST_F(SymbolSearcher, should_give_an_opportunity_do_not_log_its_internal_allocations)
+{
+ GlobalTrace.reset();
+ fs::path pathToTestLib = exePath() / "libtest_sample2.so";
+ void *handle = dlopen(pathToTestLib.c_str(), RTLD_NOW);
+
+ GlobalTrace.reset(new Trace);
+ void *symbolAddress = findSymbol("funcDefinedOnlyInTestSample2");
+ GlobalTrace.reset();
+
+ ASSERT_STREQ(getContentOfFile("./symbol_searcher_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+
+ dlclose(handle);
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/test_sample1.h b/runtime/contrib/heap_trace/tests/src/test_sample1.h
new file mode 100644
index 000000000..3abea56a3
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/test_sample1.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_SAMPLE1_H
+#define TEST_SAMPLE1_H
+
+extern "C" {
+
+void *funcDefinedInTestSample3_ButWrappedInTestSample1();
+}
+
+#endif // ! TEST_SAMPLE1_H
diff --git a/runtime/contrib/heap_trace/tests/src/test_sample1/test_sample1.cc b/runtime/contrib/heap_trace/tests/src/test_sample1/test_sample1.cc
new file mode 100644
index 000000000..1d2843707
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/test_sample1/test_sample1.cc
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../test_sample1.h"
+
+#include "../../../src/symbol_searcher.h"
+
+extern "C" {
+
+void *funcDefinedInTestSample3_ButWrappedInTestSample1()
+{
+ return findSymbol("funcDefinedInTestSample3_ButWrappedInTestSample1");
+}
+}
diff --git a/runtime/contrib/heap_trace/tests/src/test_sample2.h b/runtime/contrib/heap_trace/tests/src/test_sample2.h
new file mode 100644
index 000000000..785fc252d
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/test_sample2.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_SAMPLE2_H
+#define TEST_SAMPLE2_H
+
+extern "C" {
+
+void funcDefinedOnlyInTestSample2();
+void funcWhichCallFuncDefinedInTestSample3();
+}
+
+#endif // ! TEST_SAMPLE2_H
diff --git a/runtime/contrib/heap_trace/tests/src/test_sample2/test_sample2.cc b/runtime/contrib/heap_trace/tests/src/test_sample2/test_sample2.cc
new file mode 100644
index 000000000..792dba665
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/test_sample2/test_sample2.cc
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../test_sample2.h"
+#include "../test_sample3.h"
+
+extern "C" {
+
+void funcDefinedOnlyInTestSample2() {}
+void funcWhichCallFuncDefinedInTestSample3() { funcDefinedInTestSample3_ButWrappedInTestSample1(); }
+}
diff --git a/runtime/contrib/heap_trace/tests/src/test_sample3.h b/runtime/contrib/heap_trace/tests/src/test_sample3.h
new file mode 100644
index 000000000..8f85b8bd6
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/test_sample3.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_SAMPLE3_H
+#define TEST_SAMPLE3_H
+
+extern "C" {
+
+void funcDefinedInTestSample3_ButWrappedInTestSample1();
+}
+
+#endif // ! TEST_SAMPLE3_H
diff --git a/runtime/contrib/heap_trace/tests/src/test_sample3/test_sample3.cc b/runtime/contrib/heap_trace/tests/src/test_sample3/test_sample3.cc
new file mode 100644
index 000000000..ded78db85
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/test_sample3/test_sample3.cc
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" {
+
+void funcDefinedInTestSample3_ButWrappedInTestSample1() {}
+}
diff --git a/runtime/contrib/heap_trace/tests/src/test_sample4.h b/runtime/contrib/heap_trace/tests/src/test_sample4.h
new file mode 100644
index 000000000..47c9e8c92
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/test_sample4.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_SAMPLE4_H
+#define TEST_SAMPLE4_H
+
+extern "C" {
+
+void funcDefinedOnlyInTestSample4();
+}
+
+#endif // ! TEST_SAMPLE4_H
diff --git a/runtime/contrib/heap_trace/tests/src/test_sample4/test_sample4.cc b/runtime/contrib/heap_trace/tests/src/test_sample4/test_sample4.cc
new file mode 100644
index 000000000..55c96cb0e
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/test_sample4/test_sample4.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../test_sample4.h"
+
+extern "C" {
+void funcDefinedOnlyInTestSample4() {}
+}
diff --git a/runtime/contrib/heap_trace/tests/src/trace_test.cc b/runtime/contrib/heap_trace/tests/src/trace_test.cc
new file mode 100644
index 000000000..1cf4c530b
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/trace_test.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+
+#include <CL/cl.h>
+
+#include <experimental/filesystem>
+#include <thread>
+#include <atomic>
+
+using namespace std;
+namespace fs = experimental::filesystem;
+
+extern unique_ptr<::Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct Trace : TestEnv
+{
+ Trace() : TestEnv("./trace_test.log") {}
+
+ void generateGarbageInTestLogFile();
+ template <typename MemType>
+ static void emulateAllocationEvent(size_t eventsPoolId, size_t numberOfEmulation,
+ size_t numberOfBytesPerOneEmulation, atomic_bool &isPauseNeed);
+};
+
+TEST_F(Trace,
+ must_create_log_file_with_name_defined_in_env_var_HEAP_TRACE_LOG_during_initialization)
+{
+ ASSERT_TRUE(fs::exists("./trace_test.log"));
+}
+
+TEST_F(Trace, must_truncate_log_file_if_it_exists_during_initialization)
+{
+ GlobalTrace.reset();
+ generateGarbageInTestLogFile();
+ GlobalTrace.reset(new ::Trace);
+ GlobalTrace.reset();
+
+ ASSERT_STREQ(getContentOfFile("./trace_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+void Trace::generateGarbageInTestLogFile()
+{
+ ofstream log("./trace_test.log");
+ log << string(256, 'a');
+}
+
+TEST_F(Trace, should_not_generate_any_records_in_log_during_creation)
+{
+ GlobalTrace.reset();
+
+ ASSERT_STREQ(getContentOfFile("./trace_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(Trace, can_signalize_to_users_if_it_is_ready_for_using)
+{
+ ASSERT_FALSE(::Trace::Guard().isActive());
+}
+
+TEST_F(Trace, must_signalize_that_it_is_not_ready_for_using_until_it_is_not_created)
+{
+ GlobalTrace.reset();
+ ASSERT_TRUE(::Trace::Guard().isActive());
+}
+
+TEST_F(Trace, should_work_correctly_in_multithreaded_environment)
+{
+ constexpr size_t numberOfThreads = 10, numberOfEmulations = 100,
+ numberOfBytesPerOneEmulation = 1024;
+ atomic_bool isPauseNeed{true};
+ array<thread, numberOfThreads> threads;
+ for (size_t i = 0; i < numberOfThreads / 2; ++i)
+ {
+ threads[i] = thread(emulateAllocationEvent<void *>, i, numberOfEmulations,
+ numberOfBytesPerOneEmulation, ref(isPauseNeed));
+ }
+ for (size_t i = numberOfThreads / 2; i < numberOfThreads; ++i)
+ {
+ threads[i] = thread(emulateAllocationEvent<cl_mem>, i, numberOfEmulations,
+ numberOfBytesPerOneEmulation, ref(isPauseNeed));
+ }
+
+ GlobalTrace.reset(new ::Trace);
+ isPauseNeed = false;
+
+ for (size_t i = 0; i < numberOfThreads; ++i)
+ {
+ threads[i].join();
+ }
+ GlobalTrace.reset();
+
+ string thisShouldBeInLogFile =
+ "Total allocated: " +
+ to_string(numberOfThreads / 2 * numberOfEmulations * numberOfBytesPerOneEmulation) +
+ " B, Total deallocated: " +
+ to_string(numberOfThreads / 2 * numberOfEmulations * numberOfBytesPerOneEmulation) + " B\n";
+ string andThisToo =
+ "Total allocated: " +
+ to_string(numberOfThreads / 2 * numberOfEmulations * numberOfBytesPerOneEmulation) +
+ " B, Total deallocated: " +
+ to_string(numberOfThreads / 2 * numberOfEmulations * numberOfBytesPerOneEmulation) + " B\n";
+ ASSERT_TRUE(getContentOfFile("./trace_test.log").find(thisShouldBeInLogFile) != string::npos);
+ ASSERT_TRUE(getContentOfFile("./trace_test.log").find(andThisToo) != string::npos);
+}
+
+template <typename MemType>
+void Trace::emulateAllocationEvent(size_t eventsPoolId, size_t numberOfEmulation,
+ size_t numberOfBytesPerOneEmulation, atomic_bool &isPauseNeed)
+{
+ while (isPauseNeed)
+ {
+ continue;
+ }
+
+ for (size_t i = 1; i <= numberOfEmulation; ++i)
+ {
+ GlobalTrace->logAllocationEvent((MemType)(i + numberOfEmulation * eventsPoolId),
+ numberOfBytesPerOneEmulation);
+ }
+
+ for (size_t i = 1; i <= numberOfEmulation; ++i)
+ {
+ GlobalTrace->logDeallocationEvent((MemType)(i + numberOfEmulation * eventsPoolId));
+ }
+}
+
+TEST_F(Trace, must_log_allocation_and_deallocation_events)
+{
+ void *memOnCPU1 = (void *)1, *memOnCPU2 = (void *)3;
+ cl_mem memOnGPU1 = (cl_mem)2, memOnGPU2 = (cl_mem)4;
+ GlobalTrace->logAllocationEvent(memOnCPU1, 347);
+ GlobalTrace->logDeallocationEvent(memOnCPU1);
+ GlobalTrace->logAllocationEvent(memOnGPU2, 592);
+ GlobalTrace->logDeallocationEvent(memOnGPU2);
+ GlobalTrace->logAllocationEvent(memOnGPU1, 349);
+ GlobalTrace->logDeallocationEvent(memOnGPU1);
+ GlobalTrace->logAllocationEvent(memOnCPU2, 568);
+ GlobalTrace->logDeallocationEvent(memOnCPU2);
+ GlobalTrace.reset();
+
+ string shouldBeInLogFile = "On CPU - Peak heap usage: " + to_string(568) +
+ " B, Total allocated: " + to_string(347 + 568) +
+ " B, Total deallocated: " + to_string(347 + 568) +
+ " B\n"
+ "On GPU - Peak mem usage: " +
+ to_string(592) + " B, Total allocated: " + to_string(592 + 349) +
+ " B, Total deallocated: " + to_string(592 + 349) + " B\n";
+ ASSERT_STREQ(getContentOfFile("./trace_test.log").c_str(), shouldBeInLogFile.c_str());
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/heap_trace/tests/src/valloc_interception_test.cc b/runtime/contrib/heap_trace/tests/src/valloc_interception_test.cc
new file mode 100644
index 000000000..7a409ab25
--- /dev/null
+++ b/runtime/contrib/heap_trace/tests/src/valloc_interception_test.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test_environment.h"
+#include "file_content_manipulations.h"
+
+#include "trace.h"
+#include "symbol_searcher.h"
+#include "memory_pool_for_symbol_searcher_internals.h"
+
+#include <limits>
+
+extern std::unique_ptr<Trace> GlobalTrace;
+
+namespace backstage
+{
+
+struct VallocStub : public TestEnv
+{
+ VallocStub() : TestEnv("./valloc_interception_test.log") {}
+};
+
+TEST_F(VallocStub, must_allocate_space_as_standard_valloc)
+{
+ void *p = valloc(128);
+
+ ASSERT_TRUE(p);
+ free(p);
+}
+
+TEST_F(VallocStub, must_log_allocation_events_if_trace_is_ready_for_it)
+{
+ GlobalTrace.reset();
+ void *p1 = valloc(1024);
+
+ GlobalTrace.reset(new Trace);
+ void *p2 = valloc(128);
+ void *p3 = valloc(64);
+ GlobalTrace.reset();
+
+ ASSERT_TRUE(p1 && p2 && p3);
+ ASSERT_STREQ(getContentOfFile("./valloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 192 B, Total allocated: 192 B, Total deallocated: 0 "
+ "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+ free(p1);
+ free(p2);
+ free(p3);
+}
+
+TEST_F(VallocStub, must_not_do_the_record_about_allocation_event_if_original_function_failed)
+{
+ void *p = valloc(std::numeric_limits<size_t>::max());
+ GlobalTrace.reset();
+
+ ASSERT_FALSE(p);
+ ASSERT_STREQ(getContentOfFile("./valloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+TEST_F(VallocStub, should_allocate_memory_from_pool_for_symbol_searcher_internal_usage_if_need)
+{
+ signalizeThatNextAllocationsWillBeForSymbolSearcherInternalUsage();
+ void *p = valloc(1024);
+ signalizeThatSymbolSearcherEndedOfWork();
+ GlobalTrace.reset();
+
+ MemoryPoolForSymbolSearcherInternals pool;
+ ASSERT_TRUE(p);
+ ASSERT_TRUE(pool.containsMemorySpaceStartedFromPointer(p));
+ ASSERT_STREQ(getContentOfFile("./valloc_interception_test.log").c_str(),
+ "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn "
+ "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n");
+}
+
+} // namespace backstage
diff --git a/runtime/contrib/labs/CMakeLists.txt b/runtime/contrib/labs/CMakeLists.txt
new file mode 100644
index 000000000..57e28c11a
--- /dev/null
+++ b/runtime/contrib/labs/CMakeLists.txt
@@ -0,0 +1,5 @@
+if(NOT BUILD_LABS)
+ return()
+endif(NOT BUILD_LABS)
+
+add_subdirectories()
diff --git a/runtime/contrib/labs/jniacl/CMakeLists.txt b/runtime/contrib/labs/jniacl/CMakeLists.txt
new file mode 100644
index 000000000..6330febaa
--- /dev/null
+++ b/runtime/contrib/labs/jniacl/CMakeLists.txt
@@ -0,0 +1,18 @@
+#
+# Simple Android JNI execution test of ACL
+#
+
+if(NOT ANDROID)
+ return()
+endif(NOT ANDROID)
+
+nnfw_find_package(ARMCompute REQUIRED)
+
+link_directories(${CMAKE_INSTALL_PREFIX}/lib)
+
+set(JNIACL_SRCS src/jniacl_main.cc
+ src/io_accessor.cc)
+
+add_library(jniacl_jni SHARED ${JNIACL_SRCS})
+target_include_directories(jniacl_jni PUBLIC ${TFLITE_JNI_INCLUDES} src)
+target_link_libraries(jniacl_jni arm_compute_graph log)
diff --git a/runtime/contrib/labs/jniacl/src/io_accessor.cc b/runtime/contrib/labs/jniacl/src/io_accessor.cc
new file mode 100644
index 000000000..076c93f3d
--- /dev/null
+++ b/runtime/contrib/labs/jniacl/src/io_accessor.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (c) 2018 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 "io_accessor.h"
+#include <ostream>
+#include <android/log.h>
+
+bool InputAccessor::access_tensor(arm_compute::ITensor &tensor)
+{
+ // Subtract the mean value from each channel
+ arm_compute::Window window;
+ window.use_tensor_dimensions(tensor.info()->tensor_shape());
+
+ execute_window_loop(window, [&](const arm_compute::Coordinates &id) {
+ *reinterpret_cast<float *>(tensor.ptr_to_element(id)) = _test_input;
+ _test_input += _inc ? 1.0 : 0.0;
+
+ __android_log_print(ANDROID_LOG_DEBUG, "LOG_TAG", "Input %d, %d = %lf\r\n", id.y(), id.x(),
+ *reinterpret_cast<float *>(tensor.ptr_to_element(id)));
+ });
+ return true;
+}
+
+bool OutputAccessor::access_tensor(arm_compute::ITensor &tensor)
+{
+ // Subtract the mean value from each channel
+ arm_compute::Window window;
+ window.use_tensor_dimensions(tensor.info()->tensor_shape());
+
+ execute_window_loop(window, [&](const arm_compute::Coordinates &id) {
+ __android_log_print(ANDROID_LOG_DEBUG, "Output", "Input %d, %d = %lf\r\n", id.y(), id.x(),
+ *reinterpret_cast<float *>(tensor.ptr_to_element(id)));
+ });
+ return false; // end the network
+}
+
+bool WeightAccessor::access_tensor(arm_compute::ITensor &tensor)
+{
+ // Subtract the mean value from each channel
+ arm_compute::Window window;
+ window.use_tensor_dimensions(tensor.info()->tensor_shape());
+
+ execute_window_loop(window, [&](const arm_compute::Coordinates &id) {
+ *reinterpret_cast<float *>(tensor.ptr_to_element(id)) = _test_weight;
+ _test_weight += _inc ? 1.0 : 0.0;
+ });
+ return true;
+}
+
+bool BiasAccessor::access_tensor(arm_compute::ITensor &tensor)
+{
+ // Subtract the mean value from each channel
+ arm_compute::Window window;
+ window.use_tensor_dimensions(tensor.info()->tensor_shape());
+
+ execute_window_loop(window, [&](const arm_compute::Coordinates &id) {
+ *reinterpret_cast<float *>(tensor.ptr_to_element(id)) = 0.0;
+ });
+ return true;
+}
diff --git a/runtime/contrib/labs/jniacl/src/io_accessor.h b/runtime/contrib/labs/jniacl/src/io_accessor.h
new file mode 100644
index 000000000..bc4376644
--- /dev/null
+++ b/runtime/contrib/labs/jniacl/src/io_accessor.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (c) 2018 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 __IO_ACCESSOR_H__
+#define __IO_ACCESSOR_H__
+
+#include <arm_compute/graph/ITensorAccessor.h>
+
+class InputAccessor : public arm_compute::graph::ITensorAccessor
+{
+public:
+ InputAccessor(bool inc) : _inc(inc) { _test_input = 1.0; }
+ InputAccessor(InputAccessor &&) = default;
+
+ // Inherited methods overriden:
+ bool access_tensor(arm_compute::ITensor &tensor) override;
+
+private:
+ bool _inc;
+ float _test_input;
+};
+
+class OutputAccessor : public arm_compute::graph::ITensorAccessor
+{
+public:
+ OutputAccessor() = default;
+ OutputAccessor(OutputAccessor &&) = default;
+
+ // Inherited methods overriden:
+ bool access_tensor(arm_compute::ITensor &tensor) override;
+};
+
+class WeightAccessor : public arm_compute::graph::ITensorAccessor
+{
+public:
+ WeightAccessor(bool inc) : _inc(inc) { _test_weight = 1.0; }
+ WeightAccessor(WeightAccessor &&) = default;
+
+ // Inherited methods overriden:
+ bool access_tensor(arm_compute::ITensor &tensor) override;
+
+private:
+ bool _inc;
+ float _test_weight;
+};
+
+class BiasAccessor : public arm_compute::graph::ITensorAccessor
+{
+public:
+ BiasAccessor() = default;
+ BiasAccessor(BiasAccessor &&) = default;
+
+ // Inherited methods overriden:
+ bool access_tensor(arm_compute::ITensor &tensor) override;
+};
+
+#endif // __IO_ACCESSOR_H__
diff --git a/runtime/contrib/labs/jniacl/src/jniacl_main.cc b/runtime/contrib/labs/jniacl/src/jniacl_main.cc
new file mode 100644
index 000000000..01b928981
--- /dev/null
+++ b/runtime/contrib/labs/jniacl/src/jniacl_main.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <string>
+
+#include <arm_compute/graph/Graph.h>
+#include <arm_compute/graph/Nodes.h>
+
+#include "io_accessor.h"
+
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_samsung_testaclexec_ActivityMain_RunACLJNI(JNIEnv *env, jobject)
+{
+ using arm_compute::DataType;
+ using arm_compute::TensorInfo;
+ using arm_compute::TensorShape;
+ using arm_compute::graph::Graph;
+ using arm_compute::graph::TargetHint;
+ using arm_compute::graph::Tensor;
+
+ arm_compute::graph::Graph graph;
+ TargetHint target_hint = TargetHint::OPENCL;
+ bool autoinc = true;
+
+ graph << target_hint << Tensor(TensorInfo(TensorShape(3U, 3U, 1U, 1U), 1, DataType::F32),
+ std::unique_ptr<InputAccessor>(new InputAccessor(autoinc)))
+ << arm_compute::graph::ConvolutionLayer(
+ 3U, 3U, 1U, std::unique_ptr<WeightAccessor>(new WeightAccessor(autoinc)),
+ std::unique_ptr<BiasAccessor>(new BiasAccessor()),
+ arm_compute::PadStrideInfo(1, 1, 0, 0))
+ << Tensor(std::unique_ptr<OutputAccessor>(new OutputAccessor()));
+
+ graph.run();
+
+ std::string hello = "SoftMax Run OK";
+
+ return env->NewStringUTF(hello.c_str());
+}
diff --git a/runtime/contrib/labs/opencl_test/CMakeLists.txt b/runtime/contrib/labs/opencl_test/CMakeLists.txt
new file mode 100644
index 000000000..dc8f5f661
--- /dev/null
+++ b/runtime/contrib/labs/opencl_test/CMakeLists.txt
@@ -0,0 +1,11 @@
+if(NOT ${TARGET_ARCH_BASE} STREQUAL "arm")
+ return()
+endif(NOT ${TARGET_ARCH_BASE} STREQUAL "arm")
+
+list(APPEND OPENCL_INFO_SOURCE "src/opencl_test.cc")
+
+nnfw_find_package(ARMCompute REQUIRED)
+
+add_executable(opencl_test ${OPENCL_INFO_SOURCE})
+target_link_libraries(opencl_test arm_compute)
+target_link_libraries(opencl_test arm_compute_ex)
diff --git a/runtime/contrib/labs/opencl_test/README.md b/runtime/contrib/labs/opencl_test/README.md
new file mode 100644
index 000000000..950528f81
--- /dev/null
+++ b/runtime/contrib/labs/opencl_test/README.md
@@ -0,0 +1,8 @@
+This directory contains experients of OpenCL code.
+
+How to run:
+```
+LD_LIBRARY_PATH=Product/out/lib Product/obj/contrib/opencl_test/opencl_test [option]
+```
+ - `[option]`
+ - `-g`: prints devices inside GPU and check if they use same memory address
diff --git a/runtime/contrib/labs/opencl_test/src/opencl_test.cc b/runtime/contrib/labs/opencl_test/src/opencl_test.cc
new file mode 100644
index 000000000..1faa91478
--- /dev/null
+++ b/runtime/contrib/labs/opencl_test/src/opencl_test.cc
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*******************************************************************************
+ * Copyright (c) 2008-2015 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are 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 Materials.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ ******************************************************************************/
+
+#include "arm_compute/core/CL/OpenCL.h"
+
+#include <iostream>
+#include <vector>
+
+void printDeviceInfo(int n, cl::Device &device, cl::Device &default_device)
+{
+ bool is_default = (device() == default_device());
+ std::cout << "\t\t\t#" << n << " Device: (id: " << device() << ") "
+ << (is_default ? " -> default" : "") << "\n";
+
+ const auto name = device.getInfo<CL_DEVICE_NAME>();
+ std::cout << "\t\t\t\tName: " << name << "\n";
+
+ const auto compute_unit = device.getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>();
+ std::cout << "\t\t\t\tMax Compute Unit: " << compute_unit << "\n";
+
+ const auto max_work_item_size = device.getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
+ std::cout << "\t\t\t\tMax Work Item Size: [";
+ for (auto size : max_work_item_size)
+ std::cout << size << ",";
+ std::cout << "]\n";
+
+ const auto max_work_group_size = device.getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>();
+ std::cout << "\t\t\t\tMax Work Grpup Size: " << max_work_group_size << "\n";
+
+ const auto max_clock_frequency = device.getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>();
+ std::cout << "\t\t\t\tMax Clock Frequency: " << max_clock_frequency << "\n";
+
+ std::cout << "\n";
+}
+
+class OpenCLGpu
+{
+public:
+ cl::Platform platform_;
+ cl::Context context_;
+ cl::vector<cl::Device> devices_;
+ std::vector<cl::CommandQueue *> q_;
+ cl::Program program_;
+
+ OpenCLGpu()
+ {
+ cl_int cl_error;
+
+ platform_ = cl::Platform::getDefault();
+
+ try
+ {
+ cl_context_properties properties[3] = {CL_CONTEXT_PLATFORM,
+ (cl_context_properties)platform_(), 0};
+
+ context_ = cl::Context(CL_DEVICE_TYPE_GPU, properties, NULL, NULL, &cl_error);
+ }
+ catch (cl::Error &err) // thrown when there is no Context for this platform
+ {
+ std::cout << "\t\t No Context Found\n";
+ return;
+ }
+
+ devices_ = context_.getInfo<CL_CONTEXT_DEVICES>();
+
+ for (int dev_id = 0; dev_id < devices_.size(); dev_id++)
+ {
+ cl::CommandQueue *que = new cl::CommandQueue(context_, devices_[dev_id]);
+ q_.emplace_back(que);
+ }
+ }
+
+ ~OpenCLGpu()
+ {
+ for (auto each_q : q_)
+ delete each_q;
+ }
+
+ void buildProgram(std::string &kernel_source_code)
+ {
+ std::vector<std::string> programStrings{kernel_source_code};
+
+ program_ = cl::Program(context_, programStrings);
+
+ try
+ {
+ program_.build("-cl-std=CL1.2");
+ }
+ catch (cl::Error &err)
+ {
+ cl_int buildErr = CL_SUCCESS;
+ auto buildInfo = program_.getBuildInfo<CL_PROGRAM_BUILD_LOG>(&buildErr);
+ for (auto &pair : buildInfo)
+ {
+ std::cerr << pair.second << std::endl << std::endl;
+ }
+ }
+ }
+};
+
+void checkContextMem()
+{
+ cl_int cl_error;
+
+ // get context, devices
+ //
+ std::cout << "\nChecking if devices in GPU shares the same memory address:\n\n";
+
+ OpenCLGpu gpu;
+
+ std::cout << "\nDevices in GPU:\n\n";
+
+ auto &devices = gpu.devices_;
+ auto default_device = cl::Device::getDefault();
+
+ int d = 0;
+ for (auto device : devices)
+ printDeviceInfo(++d, device, default_device);
+
+ if (d < 2)
+ {
+ std::cout << "\t\t This options works when there are n (>= 2) devices.\n";
+ return;
+ }
+
+ // allocate and map memory
+
+ typedef cl_int T;
+ const int items_per_device = 128;
+ const int length = items_per_device * devices.size();
+
+ std::vector<T> input(length);
+ std::vector<T> output(length, 0);
+
+ for (int i = 0; i < length; i++)
+ input[i] = i;
+
+ cl::Buffer input_buf(gpu.context_, (cl_mem_flags)CL_MEM_USE_HOST_PTR, length * sizeof(T),
+ input.data(), &cl_error);
+ cl::Buffer output_buf(gpu.context_, (cl_mem_flags)CL_MEM_USE_HOST_PTR, length * sizeof(T),
+ output.data(), &cl_error);
+
+ // compile test cl code
+
+ std::string kernel_source{"typedef int T; \n"
+ "kernel void memory_test( \n"
+ " const int dev_id, \n"
+ " global T* input, \n"
+ " global T* output, \n"
+ " const int start_idx, \n"
+ " const int count) \n"
+ "{ \n"
+ " int input_idx = get_global_id(0); \n"
+ " if(input_idx < count) \n"
+ " { \n"
+ " int output_idx = start_idx + input_idx; \n"
+ " output[output_idx] = input[input_idx] + dev_id; \n"
+ " } \n"
+ "} \n"};
+
+ gpu.buildProgram(kernel_source);
+
+ try
+ {
+ auto kernel_functor = cl::KernelFunctor<cl_int, cl::Buffer, cl::Buffer, cl_int, cl_int>(
+ gpu.program_, "memory_test"); // name should be same as cl function name
+
+ // create a queue per device and queue a kernel job
+
+ for (int dev_id = 0; dev_id < devices.size(); dev_id++)
+ {
+ kernel_functor(cl::EnqueueArgs(*(gpu.q_[dev_id]), cl::NDRange(items_per_device)),
+ (cl_int)dev_id, // dev id
+ input_buf, output_buf,
+ (cl_int)(items_per_device * dev_id), // start index
+ (cl_int)(items_per_device), // count
+ cl_error);
+ }
+
+ // sync
+
+ for (d = 0; d < devices.size(); d++)
+ (gpu.q_[d])->finish();
+
+ // check if memory state changed by all devices
+
+ cl::copy(*(gpu.q_[0]), output_buf, begin(output), end(output));
+
+ bool use_same_memory = true;
+
+ for (int dev_id = 0; dev_id < devices.size(); dev_id++)
+ {
+ for (int i = 0; i < items_per_device; ++i)
+ {
+ int output_idx = items_per_device * dev_id + i;
+ if (output[output_idx] != input[i] + dev_id)
+ {
+ std::cout << "Output[" << output_idx << "] : "
+ << "expected = " << input[i] + dev_id << "; actual = " << output[output_idx]
+ << "\n";
+ use_same_memory = false;
+ break;
+ }
+ }
+ }
+
+ if (use_same_memory)
+ std::cout << "\n=> Mapped memory addresses used by devices in GPU are same.\n\n";
+ else
+ std::cout << "\n=> Mapped memory addresses used by devices in GPU are different.\n\n";
+ }
+ catch (cl::Error &err)
+ {
+ std::cerr << "error: code: " << err.err() << ", what: " << err.what() << std::endl;
+ }
+}
+
+void printHelp()
+{
+ std::cout << "opencl information: \n\n";
+ std::cout << "\t -h : help\n";
+ std::cout
+ << "\t -g : print if memory map is shared among devices in GPU (in default platform)\n\n";
+ std::cout << "\t -s : test for synchronized work by two devices in a GPU\n\n";
+}
+
+#include <mutex>
+#include <chrono>
+#include <thread>
+#include <condition_variable>
+
+#define MAX_DEVICE_NUM 8 // just for testing
+
+int kernel_idx[MAX_DEVICE_NUM];
+unsigned char kernel_completed = 0x00; // bit 0 = 1 means kernel by device[0] was completed.
+unsigned char
+ kernel_completed_flag; // if comparing kernel_completed with this var, all kernels are completed
+int device_num;
+std::mutex kernel_complete_handler_mutex;
+
+std::condition_variable wakeup_main;
+std::mutex wakeup_main_mutex;
+
+void notifyKernelFinished(cl_event ev, cl_int ev_info, void *device_idx)
+{
+ std::cout << "callback from device[" << *((int *)device_idx) << "] : ==> completed.\n";
+
+ std::unique_lock<std::mutex> lock(kernel_complete_handler_mutex);
+
+ kernel_completed |= 0x01 << *((int *)device_idx);
+ if (kernel_completed == kernel_completed_flag)
+ wakeup_main.notify_one();
+}
+
+void testSync()
+{
+ OpenCLGpu gpu;
+
+ cl_int cl_error;
+ typedef cl_int T;
+ const int items_per_device = 1024 * 768;
+ const int length = items_per_device * gpu.devices_.size();
+
+ std::vector<T> output(length, 0);
+
+ cl::Buffer output_buf(gpu.context_, (cl_mem_flags)CL_MEM_USE_HOST_PTR, length * sizeof(T),
+ output.data(), &cl_error);
+
+ std::string kernel_source{"kernel void test(global float* output, const int count) \n"
+ "{ \n"
+ " int idx = get_global_id(0); \n"
+ " if(idx < count) \n"
+ " { \n"
+ " float x = hypot(idx/1.111, idx*1.111); \n"
+ " for (int y = 0; y < 200; y++) \n"
+ " x = rootn(log(pown(rootn(log(pown(x, 20)), 5), 20)), 5); \n"
+ " output[idx] = x; \n"
+ " } \n"
+ "} \n"};
+
+ gpu.buildProgram(kernel_source);
+
+ try
+ {
+ auto kernel_functor = cl::KernelFunctor<cl::Buffer, cl_int>(
+ gpu.program_, "test"); // name should be same as cl function name
+
+ // variable init
+ cl::Event ev[MAX_DEVICE_NUM];
+
+ device_num = gpu.devices_.size();
+
+ kernel_completed = 0;
+ kernel_completed_flag = 0;
+ for (int i = 0; i < device_num; i++)
+ {
+ kernel_idx[i] = i;
+ kernel_completed_flag |= 0x01 << i;
+ }
+
+ // create a queue per device and queue a kernel job
+ // queueing with callback function
+ for (int dev_id = 0; dev_id < gpu.devices_.size(); dev_id++)
+ {
+ ev[dev_id] = kernel_functor(cl::EnqueueArgs(*(gpu.q_[dev_id]), cl::NDRange(items_per_device)),
+ output_buf,
+ (cl_int)(items_per_device), // count
+ cl_error);
+ ev[dev_id].setCallback(CL_COMPLETE, notifyKernelFinished, (void *)(kernel_idx + dev_id));
+
+ // how to check kernel execution status
+ //
+ // auto status = ev[dev_id].getInfo<CL_EVENT_COMMAND_EXECUTION_STATUS>();
+ // std::cout << "Event status = " << (status == CL_QUEUED ? "CL_QUEUED" : status ==
+ // CL_SUBMITTED ? "CL_SUBMITTED" : status == CL_COMPLETE ? "CL_COMPLETE" : "unknown")
+ // << std::endl;
+ // std::cout << "Event status code = " << status << std::endl;
+ }
+
+ // long wait until kernels are over
+ {
+ std::unique_lock<std::mutex> lk(wakeup_main_mutex);
+ wakeup_main.wait(lk, [] { return (kernel_completed == kernel_completed_flag); });
+
+ std::cout << "all devices were completed.\n";
+ }
+ }
+ catch (cl::Error &err)
+ {
+ std::cerr << "error: code: " << err.err() << ", what: " << err.what() << std::endl;
+ }
+}
+
+int main(const int argc, char **argv)
+{
+ if (argc < 2)
+ printHelp();
+ else
+ {
+ std::string option = argv[1];
+
+ if (option == "-h") // help
+ printHelp();
+ else if (option == "-g") // check if devices in GPU uses same memory address
+ checkContextMem();
+ else if (option == "-s") // check synchronization between devices in GPU
+ testSync();
+ }
+ return 0;
+}
diff --git a/runtime/contrib/labs/tflite_examples/CMakeLists.txt b/runtime/contrib/labs/tflite_examples/CMakeLists.txt
new file mode 100644
index 000000000..463bc5531
--- /dev/null
+++ b/runtime/contrib/labs/tflite_examples/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(tflite_conv_example "src/conv.cpp")
+target_link_libraries(tflite_conv_example tensorflow-lite ${LIB_PTHREAD} dl nnfw_lib_tflite)
diff --git a/runtime/contrib/labs/tflite_examples/src/conv.cpp b/runtime/contrib/labs/tflite_examples/src/conv.cpp
new file mode 100644
index 000000000..e8542c3f5
--- /dev/null
+++ b/runtime/contrib/labs/tflite_examples/src/conv.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/ext/kernels/register.h"
+#include "tensorflow/lite/model.h"
+#include "tensorflow/lite/builtin_op_data.h"
+
+#include <iostream>
+
+using namespace tflite;
+using namespace nnfw::tflite;
+
+namespace vector
+{
+
+template <typename T> struct View
+{
+ virtual ~View() = default;
+
+ virtual int32_t size(void) const = 0;
+ virtual T at(uint32_t off) const = 0;
+};
+} // namespace vector
+
+namespace feature
+{
+
+struct Shape
+{
+ int32_t C;
+ int32_t H;
+ int32_t W;
+};
+
+template <typename T> struct View
+{
+ virtual ~View() = default;
+
+ virtual const Shape &shape(void) const = 0;
+ virtual T at(uint32_t ch, uint32_t row, uint32_t col) const = 0;
+};
+} // namespace feature
+
+namespace kernel
+{
+
+struct Shape
+{
+ int32_t N;
+ int32_t C;
+ int32_t H;
+ int32_t W;
+};
+
+template <typename T> struct View
+{
+ virtual ~View() = default;
+
+ virtual const Shape &shape(void) const = 0;
+ virtual T at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const = 0;
+};
+} // namespace kernel
+
+const int32_t N = 1;
+const int32_t C = 2;
+
+class SampleBiasObject final : public vector::View<float>
+{
+public:
+ SampleBiasObject() : _size(N)
+ {
+ // DO NOTHING
+ }
+
+public:
+ int32_t size(void) const override { return _size; }
+
+ float at(uint32_t off) const override { return 0.0f; }
+
+private:
+ int32_t _size;
+};
+
+class SampleFeatureObject final : public feature::View<float>
+{
+public:
+ SampleFeatureObject()
+ {
+ _shape.C = C;
+ _shape.H = 3;
+ _shape.W = 4;
+
+ const uint32_t size = _shape.C * _shape.H * _shape.W;
+
+ for (uint32_t off = 0; off < size; ++off)
+ {
+ _value.emplace_back(off);
+ }
+
+ assert(_value.size() == size);
+ }
+
+public:
+ const feature::Shape &shape(void) const override { return _shape; };
+
+ float at(uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ return _value.at(ch * _shape.H * _shape.W + row * _shape.W + col);
+ }
+
+public:
+ float &at(uint32_t ch, uint32_t row, uint32_t col)
+ {
+ return _value.at(ch * _shape.H * _shape.W + row * _shape.W + col);
+ }
+
+private:
+ feature::Shape _shape;
+ std::vector<float> _value;
+};
+
+class SampleKernelObject final : public kernel::View<float>
+{
+public:
+ SampleKernelObject()
+ {
+ _shape.N = N;
+ _shape.C = C;
+ _shape.H = 3;
+ _shape.W = 4;
+
+ const uint32_t size = _shape.N * _shape.C * _shape.H * _shape.W;
+
+ for (uint32_t off = 0; off < size; ++off)
+ {
+ _value.emplace_back(off);
+ }
+
+ assert(_value.size() == size);
+ }
+
+public:
+ const kernel::Shape &shape(void) const override { return _shape; };
+
+ float at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ return _value.at(nth * _shape.C * _shape.H * _shape.W + ch * _shape.H * _shape.W +
+ row * _shape.W + col);
+ }
+
+private:
+ kernel::Shape _shape;
+ std::vector<float> _value;
+};
+
+int main(int argc, char **argv)
+{
+ const SampleFeatureObject ifm;
+ const SampleKernelObject kernel;
+ const SampleBiasObject bias;
+
+ const int32_t IFM_C = ifm.shape().C;
+ const int32_t IFM_H = ifm.shape().H;
+ const int32_t IFM_W = ifm.shape().W;
+
+ const int32_t KER_N = kernel.shape().N;
+ const int32_t KER_C = kernel.shape().C;
+ const int32_t KER_H = kernel.shape().H;
+ const int32_t KER_W = kernel.shape().W;
+
+ const int32_t OFM_C = kernel.shape().N;
+ const int32_t OFM_H = (IFM_H - KER_H) + 1;
+ const int32_t OFM_W = (IFM_W - KER_W) + 1;
+
+ // Assumption on this example
+ assert(IFM_C == KER_C);
+ assert(KER_N == bias.size());
+
+ // Comment from 'context.h'
+ //
+ // Parameters for asymmetric quantization. Quantized values can be converted
+ // back to float using:
+ // real_value = scale * (quantized_value - zero_point);
+ //
+ // Q: Is this necessary?
+ TfLiteQuantizationParams quantization;
+
+ quantization.scale = 1;
+ quantization.zero_point = 0;
+
+ Interpreter interp;
+
+ // On AddTensors(N) call, T/F Lite interpreter creates N tensors whose index is [0 ~ N)
+ interp.AddTensors(5);
+
+ // Configure OFM
+ interp.SetTensorParametersReadWrite(0, kTfLiteFloat32 /* type */, "output" /* name */,
+ {1 /*N*/, OFM_H, OFM_W, OFM_C} /* dims */, quantization);
+
+ // Configure IFM
+ interp.SetTensorParametersReadWrite(1, kTfLiteFloat32 /* type */, "input" /* name */,
+ {1 /*N*/, IFM_H, IFM_W, IFM_C} /* dims */, quantization);
+
+ // Configure Filter
+ const uint32_t kernel_size = KER_N * KER_C * KER_H * KER_W;
+ float kernel_data[kernel_size] = {
+ 0.0f,
+ };
+
+ // Fill kernel data in NHWC order
+ {
+ uint32_t off = 0;
+
+ for (uint32_t nth = 0; nth < KER_N; ++nth)
+ {
+ for (uint32_t row = 0; row < KER_H; ++row)
+ {
+ for (uint32_t col = 0; col < KER_W; ++col)
+ {
+ for (uint32_t ch = 0; ch < KER_C; ++ch)
+ {
+ const auto value = kernel.at(nth, ch, row, col);
+ kernel_data[off++] = value;
+ }
+ }
+ }
+ }
+
+ assert(kernel_size == off);
+ }
+
+ interp.SetTensorParametersReadOnly(
+ 2, kTfLiteFloat32 /* type */, "filter" /* name */, {KER_N, KER_H, KER_W, KER_C} /* dims */,
+ quantization, reinterpret_cast<const char *>(kernel_data), sizeof(kernel_data));
+
+ // Configure Bias
+ const uint32_t bias_size = bias.size();
+ float bias_data[bias_size] = {
+ 0.0f,
+ };
+
+ // Fill bias data
+ for (uint32_t off = 0; off < bias.size(); ++off)
+ {
+ bias_data[off] = bias.at(off);
+ }
+
+ interp.SetTensorParametersReadOnly(3, kTfLiteFloat32 /* type */, "bias" /* name */,
+ {bias.size()} /* dims */, quantization,
+ reinterpret_cast<const char *>(bias_data), sizeof(bias_data));
+
+ // Add Convolution Node
+ //
+ // NOTE AddNodeWithParameters take the ownership of param, and deallocate it with free
+ // So, param should be allocated with malloc
+ TfLiteConvParams *param = reinterpret_cast<TfLiteConvParams *>(malloc(sizeof(TfLiteConvParams)));
+
+ param->padding = kTfLitePaddingValid;
+ param->stride_width = 1;
+ param->stride_height = 1;
+ param->activation = kTfLiteActRelu;
+
+ // Run Convolution and store its result into Tensor #0
+ // - Read IFM from Tensor #1
+ // - Read Filter from Tensor #2,
+ // - Read Bias from Tensor #3
+ interp.AddNodeWithParameters({1, 2, 3}, {0}, nullptr, 0, reinterpret_cast<void *>(param),
+ BuiltinOpResolver().FindOp(BuiltinOperator_CONV_2D, 1));
+
+ // Set Tensor #1 as Input #0, and Tensor #0 as Output #0
+ interp.SetInputs({1});
+ interp.SetOutputs({0});
+
+ // Let's use NNAPI (if possible)
+ interp.UseNNAPI(true);
+
+ // Allocate Tensor
+ interp.AllocateTensors();
+
+ // Fill IFM data in HWC order
+ {
+ uint32_t off = 0;
+
+ for (uint32_t row = 0; row < ifm.shape().H; ++row)
+ {
+ for (uint32_t col = 0; col < ifm.shape().W; ++col)
+ {
+ for (uint32_t ch = 0; ch < ifm.shape().C; ++ch)
+ {
+ const auto value = ifm.at(ch, row, col);
+ interp.typed_input_tensor<float>(0)[off++] = value;
+ }
+ }
+ }
+ }
+
+ // Let's Rock-n-Roll!
+ interp.Invoke();
+
+ // Print OFM
+ {
+ uint32_t off = 0;
+
+ for (uint32_t row = 0; row < OFM_H; ++row)
+ {
+ for (uint32_t col = 0; col < OFM_W; ++col)
+ {
+ for (uint32_t ch = 0; ch < kernel.shape().N; ++ch)
+ {
+ std::cout << interp.typed_output_tensor<float>(0)[off++] << std::endl;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/runtime/contrib/logging/CMakeLists.txt b/runtime/contrib/logging/CMakeLists.txt
new file mode 100644
index 000000000..e6738f09f
--- /dev/null
+++ b/runtime/contrib/logging/CMakeLists.txt
@@ -0,0 +1,12 @@
+if(NOT BUILD_LOGGING)
+ return()
+endif(NOT BUILD_LOGGING)
+
+file(GLOB_RECURSE NNAPI_LOGGING_SRCS "src/*.cc")
+
+nnfw_find_package(Boost REQUIRED)
+
+add_library(neuralnetworks SHARED ${NNAPI_LOGGING_SRCS})
+target_include_directories(neuralnetworks PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_include_directories(neuralnetworks PRIVATE ${Boost_INCLUDE_DIRS})
+target_link_libraries(neuralnetworks PUBLIC nnfw-nnapi-header)
diff --git a/runtime/contrib/logging/include/operand.def b/runtime/contrib/logging/include/operand.def
new file mode 100644
index 000000000..c570cf026
--- /dev/null
+++ b/runtime/contrib/logging/include/operand.def
@@ -0,0 +1,12 @@
+// Extracted from tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h
+//
+// NNAPI_OPERAND(NAME, CODE)
+#ifndef NNAPI_OPERAND
+#error NNAPI_OPERAND should be defined
+#endif
+NNAPI_OPERAND(ANEURALNETWORKS_FLOAT32, 0)
+NNAPI_OPERAND(ANEURALNETWORKS_INT32, 1)
+NNAPI_OPERAND(ANEURALNETWORKS_UINT32, 2)
+NNAPI_OPERAND(ANEURALNETWORKS_TENSOR_FLOAT32, 3)
+NNAPI_OPERAND(ANEURALNETWORKS_TENSOR_INT32, 4)
+NNAPI_OPERAND(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM, 5)
diff --git a/runtime/contrib/logging/include/operation.def b/runtime/contrib/logging/include/operation.def
new file mode 100644
index 000000000..cace360d7
--- /dev/null
+++ b/runtime/contrib/logging/include/operation.def
@@ -0,0 +1,15 @@
+// Extracted from tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h
+//
+// NNAPI_OPERATION(NAME, CODE)
+#ifndef NNAPI_OPERATION
+#error NNAPI_OPERATION should be defined
+#endif
+NNAPI_OPERATION(ANEURALNETWORKS_AVERAGE_POOL_2D, 1)
+NNAPI_OPERATION(ANEURALNETWORKS_CONCATENATION, 2)
+NNAPI_OPERATION(ANEURALNETWORKS_CONV_2D, 3)
+NNAPI_OPERATION(ANEURALNETWORKS_DEPTHWISE_CONV_2D, 4)
+NNAPI_OPERATION(ANEURALNETWORKS_FULLY_CONNECTED, 9)
+NNAPI_OPERATION(ANEURALNETWORKS_MAX_POOL_2D, 17)
+NNAPI_OPERATION(ANEURALNETWORKS_RESHAPE, 22)
+NNAPI_OPERATION(ANEURALNETWORKS_RESIZE_BILINEAR, 23)
+NNAPI_OPERATION(ANEURALNETWORKS_SOFTMAX, 25)
diff --git a/runtime/contrib/logging/src/nnapi_logging.cc b/runtime/contrib/logging/src/nnapi_logging.cc
new file mode 100644
index 000000000..370e72a0a
--- /dev/null
+++ b/runtime/contrib/logging/src/nnapi_logging.cc
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+#include <NeuralNetworksEx.h>
+
+#include <stdexcept>
+#include <iostream>
+
+#include <string>
+#include <map>
+
+#include <cassert>
+
+#include <boost/format.hpp>
+
+namespace
+{
+
+class OperationCodeResolver
+{
+public:
+ OperationCodeResolver();
+
+public:
+ std::string resolve(int code) const;
+
+private:
+ void setName(int code, const std::string &name);
+
+private:
+ std::map<int, std::string> _table;
+
+public:
+ static const OperationCodeResolver &access()
+ {
+ static const OperationCodeResolver resolver;
+
+ return resolver;
+ }
+};
+
+OperationCodeResolver::OperationCodeResolver()
+{
+#define NNAPI_OPERATION(NAME, CODE) setName(CODE, #NAME);
+#include "operation.def"
+#undef NNAPI_OPERATION
+}
+
+void OperationCodeResolver::setName(int code, const std::string &name)
+{
+ assert(_table.find(code) == _table.end());
+ _table[code] = name;
+}
+
+std::string OperationCodeResolver::resolve(int code) const
+{
+ auto it = _table.find(code);
+
+ if (it == _table.end())
+ {
+ return boost::str(boost::format("unknown(%d)") % code);
+ }
+
+ return it->second;
+}
+
+class OperandCodeResolver
+{
+public:
+ OperandCodeResolver();
+
+public:
+ std::string resolve(int code) const;
+
+private:
+ void setName(int code, const std::string &name);
+
+private:
+ std::map<int, std::string> _table;
+
+public:
+ static const OperandCodeResolver &access()
+ {
+ static const OperandCodeResolver resolver;
+
+ return resolver;
+ }
+};
+
+OperandCodeResolver::OperandCodeResolver()
+{
+#define NNAPI_OPERAND(NAME, CODE) setName(CODE, #NAME);
+#include "operand.def"
+#undef NNAPI_OPERAND
+}
+
+void OperandCodeResolver::setName(int code, const std::string &name)
+{
+ assert(_table.find(code) == _table.end());
+ _table[code] = name;
+}
+
+std::string OperandCodeResolver::resolve(int code) const
+{
+ auto it = _table.find(code);
+
+ if (it == _table.end())
+ {
+ return boost::str(boost::format("unknown(%d)") % code);
+ }
+
+ return it->second;
+}
+} // namespace
+
+//
+// Asynchronous Event
+//
+struct ANeuralNetworksEvent
+{
+};
+
+int ANeuralNetworksEvent_wait(ANeuralNetworksEvent *event) { return ANEURALNETWORKS_NO_ERROR; }
+
+void ANeuralNetworksEvent_free(ANeuralNetworksEvent *event) { delete event; }
+
+//
+// Memory
+//
+struct ANeuralNetworksMemory
+{
+ // 1st approach - Store all the data inside ANeuralNetworksMemory object
+ // 2nd approach - Store metadata only, and defer data loading as much as possible
+};
+
+int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset,
+ ANeuralNetworksMemory **memory)
+{
+ *memory = new ANeuralNetworksMemory;
+
+ std::cout << __FUNCTION__ << "() --> (memory: " << *memory << ")" << std::endl;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksMemory_free(ANeuralNetworksMemory *memory)
+{
+ std::cout << __FUNCTION__ << "(" << memory << ")" << std::endl;
+ delete memory;
+}
+
+//
+// Model
+//
+struct ANeuralNetworksModel
+{
+ // ANeuralNetworksModel should be a factory for Graph IR (a.k.a ISA Frontend)
+ // TODO Record # of operands
+ uint32_t numOperands;
+
+ ANeuralNetworksModel() : numOperands(0)
+ {
+ // DO NOTHING
+ }
+};
+
+int ANeuralNetworksModel_create(ANeuralNetworksModel **model)
+{
+ *model = new ANeuralNetworksModel;
+
+ std::cout << __FUNCTION__ << "(" << model << ") --> (model: " << *model << ")" << std::endl;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksModel_free(ANeuralNetworksModel *model)
+{
+ std::cout << __FUNCTION__ << "(" << model << ")" << std::endl;
+
+ delete model;
+}
+
+int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model,
+ const ANeuralNetworksOperandType *type)
+{
+ std::cout << __FUNCTION__ << "(model: " << model
+ << ", type: " << ::OperandCodeResolver::access().resolve(type->type) << ")"
+ << std::endl;
+
+ auto id = model->numOperands;
+
+ std::cout << " id: " << id << std::endl;
+ std::cout << " rank: " << type->dimensionCount << std::endl;
+ for (uint32_t dim = 0; dim < type->dimensionCount; ++dim)
+ {
+ std::cout << " dim(" << dim << "): " << type->dimensions[dim] << std::endl;
+ }
+
+ model->numOperands += 1;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index,
+ const void *buffer, size_t length)
+{
+ std::cout << __FUNCTION__ << "(model: " << model << ", index: " << index << ")" << std::endl;
+
+ // TODO Implement this!
+ // NOTE buffer becomes invalid after ANeuralNetworksModel_setOperandValue returns
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model, int32_t index,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ std::cout << __FUNCTION__ << "(model: " << model << ", index: " << index << ")" << std::endl;
+
+ // TODO Implement this!
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationType type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ std::cout << __FUNCTION__ << "(model: " << model
+ << ", type: " << ::OperationCodeResolver::access().resolve(type)
+ << ", inputCount: " << inputCount << ", outputCount: " << outputCount << ")"
+ << std::endl;
+
+ for (uint32_t input = 0; input < inputCount; ++input)
+ {
+ std::cout << " input(" << input << "): " << inputs[input] << std::endl;
+ }
+ for (uint32_t output = 0; output < outputCount; ++output)
+ {
+ std::cout << " output(" << output << "): " << outputs[output] << std::endl;
+ }
+
+ // TODO Implement this!
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationTypeEx type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ std::cout << __FUNCTION__ << "(model: " << model << ", type: " << type
+ << ", inputCount: " << inputCount << ", outputCount: " << outputCount << ")"
+ << std::endl;
+
+ for (uint32_t input = 0; input < inputCount; ++input)
+ {
+ std::cout << " input(" << input << "): " << inputs[input] << std::endl;
+ }
+ for (uint32_t output = 0; output < outputCount; ++output)
+ {
+ std::cout << " output(" << output << "): " << outputs[output] << std::endl;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ std::cout << __FUNCTION__ << "(model: " << model << ")" << std::endl;
+
+ for (uint32_t input = 0; input < inputCount; ++input)
+ {
+ std::cout << " input(" << input << "): " << inputs[input] << std::endl;
+ }
+ for (uint32_t output = 0; output < outputCount; ++output)
+ {
+ std::cout << " output(" << output << "): " << outputs[output] << std::endl;
+ }
+
+ // TODO Implement this!
+ // NOTE It seems that this function identifies the input and output of the whole model
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_finish(ANeuralNetworksModel *model)
+{
+ std::cout << __FUNCTION__ << "(model: " << model << ")" << std::endl;
+
+ // TODO Implement this!
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+//
+// Compilation
+//
+struct ANeuralNetworksCompilation
+{
+ // ANeuralNetworksCompilation should hold a compiled IR
+};
+
+int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model,
+ ANeuralNetworksCompilation **compilation)
+{
+ *compilation = new ANeuralNetworksCompilation;
+
+ std::cout << __FUNCTION__ << "(model: " << model << ") --> (compilation: " << *compilation << ")"
+ << std::endl;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksCompilation_finish(ANeuralNetworksCompilation *compilation)
+{
+ std::cout << __FUNCTION__ << "(compilation: " << compilation << ")" << std::endl;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+//
+// Execution
+//
+struct ANeuralNetworksExecution
+{
+ // ANeuralNetworksExecution corresponds to NPU::Interp::Session
+};
+
+int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution)
+{
+ *execution = new ANeuralNetworksExecution;
+
+ std::cout << __FUNCTION__ << "(compilation: " << compilation << ") --> (execution: " << *execution
+ << ")" << std::endl;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+// ANeuralNetworksExecution_setInput and ANeuralNetworksExecution_setOutput specify HOST buffer for
+// input/output
+int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, const void *buffer,
+ size_t length)
+{
+ std::cout << __FUNCTION__ << "(execution: " << execution << ", type: ";
+
+ if (type == nullptr)
+ std::cout << "nullptr)" << std::endl;
+ else
+ std::cout << ::OperandCodeResolver::access().resolve(type->type) << ")" << std::endl;
+
+ // Q: Should we transfer input from HOST to DEVICE here, or in
+ // ANeuralNetworksExecution_startCompute?
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, void *buffer,
+ size_t length)
+{
+ std::cout << __FUNCTION__ << "(execution: " << execution << ", type: ";
+
+ if (type == nullptr)
+ std::cout << "nullptr)" << std::endl;
+ else
+ std::cout << ::OperandCodeResolver::access().resolve(type->type) << ")" << std::endl;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution,
+ ANeuralNetworksEvent **event)
+{
+ *event = new ANeuralNetworksEvent;
+
+ std::cout << __FUNCTION__ << "(execution: " << execution << ") --> (event: " << *event << ")"
+ << std::endl;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksExecution_free(ANeuralNetworksExecution *execution)
+{
+ std::cout << __FUNCTION__ << "(execution: " << execution << ")" << std::endl;
+
+ delete execution;
+}
+
+void ANeuralNetworksCompilation_free(ANeuralNetworksCompilation *compilation)
+{
+ std::cout << __FUNCTION__ << "(compilation: " << compilation << ")" << std::endl;
+ delete compilation;
+}
diff --git a/runtime/contrib/mlapse/CMakeLists.txt b/runtime/contrib/mlapse/CMakeLists.txt
new file mode 100644
index 000000000..bba79971a
--- /dev/null
+++ b/runtime/contrib/mlapse/CMakeLists.txt
@@ -0,0 +1,8 @@
+if(NOT BUILD_MLAPSE)
+ return()
+endif(NOT BUILD_MLAPSE)
+
+message(STATUS "Build mlapse: TRUE")
+
+# TODO Add "core"
+add_subdirectory(tfl)
diff --git a/runtime/contrib/mlapse/README.md b/runtime/contrib/mlapse/README.md
new file mode 100644
index 000000000..36f14ac39
--- /dev/null
+++ b/runtime/contrib/mlapse/README.md
@@ -0,0 +1,3 @@
+# mlapse
+
+_mlapse_ is a toolkit for model inference latency benchmark.
diff --git a/runtime/contrib/mlapse/tfl/CMakeLists.txt b/runtime/contrib/mlapse/tfl/CMakeLists.txt
new file mode 100644
index 000000000..06e8df311
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/CMakeLists.txt
@@ -0,0 +1,11 @@
+message(STATUS "Build mlapse-tfl: TRUE")
+
+file(GLOB_RECURSE SOURCES "*.cc")
+
+add_executable(mlapse-tfl ${SOURCES})
+target_include_directories(mlapse-tfl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(mlapse-tfl nnfw_lib_tflite)
+target_link_libraries(mlapse-tfl nnfw_lib_misc)
+target_link_libraries(mlapse-tfl tensorflow-lite)
+
+install(TARGETS mlapse-tfl DESTINATION bin)
diff --git a/runtime/contrib/mlapse/tfl/driver.cc b/runtime/contrib/mlapse/tfl/driver.cc
new file mode 100644
index 000000000..1ba23178c
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/driver.cc
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mlapse/benchmark_runner.h"
+#include "mlapse/multicast_observer.h"
+#include "mlapse/CSV_report_generator.h"
+
+#include "mlapse/tfl/load.h"
+
+// From 'nnfw_lib_tflite'
+#include <tflite/InterpreterSession.h>
+#include <tflite/NNAPISession.h>
+
+#include <memory>
+
+// From C++ Standard Library
+#include <cassert>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+namespace
+{
+
+using namespace mlapse;
+
+class ConsoleReporter final : public mlapse::BenchmarkObserver
+{
+public:
+ ConsoleReporter() = default;
+
+public:
+ void notify(const NotificationArg<PhaseBegin> &arg) final
+ {
+ _phase = arg.phase;
+ _count = arg.count;
+
+ std::cout << tag() << " BEGIN" << std::endl;
+ }
+
+ void notify(const NotificationArg<PhaseEnd> &arg) final
+ {
+ std::cout << tag() << " END" << std::endl;
+
+ _phase = mlapse::uninitialized_phase();
+ _count = 0;
+ }
+
+ void notify(const NotificationArg<IterationBegin> &arg) final { _index = arg.index; }
+
+ void notify(const NotificationArg<IterationEnd> &arg) final
+ {
+ std::cout << tag() << " " << progress() << " - " << arg.latency.count() << "ms" << std::endl;
+ }
+
+private:
+ std::string progress(void) const
+ {
+ return "[" + std::to_string(_index + 1) + "/" + std::to_string(_count) + "]";
+ }
+
+ std::string tag(void) const
+ {
+ switch (_phase)
+ {
+ case Phase::Warmup:
+ return "WARMUP";
+ case Phase::Record:
+ return "RECORD";
+ default:
+ break;
+ }
+
+ return "unknown";
+ }
+
+ Phase _phase = mlapse::uninitialized_phase();
+ uint32_t _count = 0;
+ uint32_t _index = 0;
+};
+
+} // namespace
+
+// Q. Is is worth to make a library for these routines?
+namespace
+{
+
+enum class SessionType
+{
+ Interp,
+ NNAPI,
+};
+
+class SessionBuilder
+{
+public:
+ SessionBuilder(const SessionType &type) : _type{type}
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::unique_ptr<nnfw::tflite::Session> with(tflite::Interpreter *interp) const
+ {
+ switch (_type)
+ {
+ case SessionType::Interp:
+ return std::make_unique<nnfw::tflite::InterpreterSession>(interp);
+ case SessionType::NNAPI:
+ return std::make_unique<nnfw::tflite::NNAPISession>(interp);
+ default:
+ break;
+ }
+
+ return nullptr;
+ }
+
+ std::unique_ptr<nnfw::tflite::Session>
+ with(const std::unique_ptr<tflite::Interpreter> &interp) const
+ {
+ return with(interp.get());
+ }
+
+private:
+ SessionType _type;
+};
+
+SessionBuilder make_session(const SessionType &type) { return SessionBuilder{type}; }
+
+} // namespace
+
+namespace
+{
+
+// mlapse-tfl
+// [REQUIRED] --model <path/to/tflite>
+// [OPTIONAL] --warmup-count N (default = 3)
+// [OPTIONAL] --record-count N (default = 10)
+// [OPTIONAL] --thread N or auto (default = auto)
+// [OPTIOANL] --nnapi (default = off)
+// [OPTIONAL] --pause N (default = 0)
+// [OPTIONAL] --csv-report <path/to/csv>
+int entry(const int argc, char **argv)
+{
+ // Create an observer
+ mlapse::MulticastObserver observer;
+
+ observer.append(std::make_unique<ConsoleReporter>());
+
+ // Set default parameters
+ std::string model_path;
+ bool model_path_initialized = false;
+
+ SessionType session_type = SessionType::Interp;
+ uint32_t warmup_count = 3;
+ uint32_t record_count = 10;
+ int num_thread = -1; // -1 means "auto"
+
+ // Read command-line arguments
+ std::map<std::string, std::function<uint32_t(const char *const *)>> opts;
+
+ opts["--model"] = [&model_path, &model_path_initialized](const char *const *tok) {
+ model_path = std::string{tok[0]};
+ model_path_initialized = true;
+ return 1; // # of arguments
+ };
+
+ opts["--record-count"] = [&record_count](const char *const *tok) {
+ record_count = std::stoi(tok[0]);
+ return 1; // # of arguments
+ };
+
+ opts["--thread"] = [](const char *const *tok) {
+ assert(std::string{tok[0]} == "auto");
+ return 1;
+ };
+
+ opts["--nnapi"] = [&session_type](const char *const *) {
+ session_type = SessionType::NNAPI;
+ return 0;
+ };
+
+ opts["--csv-report"] = [&observer](const char *const *tok) {
+ observer.append(std::make_unique<mlapse::CSVReportGenerator>(tok[0]));
+ return 1;
+ };
+
+ {
+ uint32_t offset = 1;
+
+ while (offset < argc)
+ {
+ auto opt = argv[offset];
+
+ auto it = opts.find(opt);
+
+ if (it == opts.end())
+ {
+ std::cout << "INVALID OPTION: " << opt << std::endl;
+ return 255;
+ }
+
+ auto func = it->second;
+
+ auto num_skip = func(argv + offset + 1);
+
+ offset += 1;
+ offset += num_skip;
+ }
+ }
+
+ // Check arguments
+ if (!model_path_initialized)
+ {
+ std::cerr << "ERROR: --model is missing" << std::endl;
+ return 255;
+ }
+
+ // Load T/F Lite model
+ auto model = mlapse::tfl::load_model(model_path);
+
+ if (model == nullptr)
+ {
+ std::cerr << "ERROR: Failed to load '" << model_path << "'" << std::endl;
+ return 255;
+ }
+
+ auto interp = mlapse::tfl::make_interpreter(model.get());
+
+ if (interp == nullptr)
+ {
+ std::cerr << "ERROR: Failed to create a T/F Lite interpreter" << std::endl;
+ return 255;
+ }
+
+ auto sess = make_session(session_type).with(interp);
+
+ if (sess == nullptr)
+ {
+ std::cerr << "ERROR: Failed to create a session" << std::endl;
+ }
+
+ // Run benchmark
+ mlapse::BenchmarkRunner benchmark_runner{warmup_count, record_count};
+
+ benchmark_runner.attach(&observer);
+ benchmark_runner.run(sess);
+
+ return 0;
+}
+
+} // namespace
+
+int main(int argc, char **argv)
+{
+ try
+ {
+ return entry(argc, argv);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
+
+ return 255;
+}
diff --git a/runtime/contrib/mlapse/tfl/mlapse/CSV_report_generator.cc b/runtime/contrib/mlapse/tfl/mlapse/CSV_report_generator.cc
new file mode 100644
index 000000000..c6237a04f
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/CSV_report_generator.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mlapse/CSV_report_generator.h"
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+
+std::string tag(const mlapse::Phase &phase)
+{
+ switch (phase)
+ {
+ case mlapse::Phase::Warmup:
+ return "WARMUP";
+ case mlapse::Phase::Record:
+ return "STEADY";
+ default:
+ break;
+ }
+
+ throw std::invalid_argument{"phase"};
+}
+
+} // namespace
+
+namespace mlapse
+{
+
+void CSVReportGenerator::notify(const NotificationArg<PhaseBegin> &arg)
+{
+ assert(_phase == uninitialized_phase());
+ _phase = arg.phase;
+}
+
+void CSVReportGenerator::notify(const NotificationArg<PhaseEnd> &arg)
+{
+ assert(_phase != uninitialized_phase());
+ _phase = uninitialized_phase();
+}
+
+void CSVReportGenerator::notify(const NotificationArg<IterationBegin> &arg)
+{
+ // DO NOTHING
+}
+
+void CSVReportGenerator::notify(const NotificationArg<IterationEnd> &arg)
+{
+ _ofs << tag(_phase) << "," << arg.latency.count() << std::endl;
+}
+
+} // namespace mlapse
diff --git a/runtime/contrib/mlapse/tfl/mlapse/CSV_report_generator.h b/runtime/contrib/mlapse/tfl/mlapse/CSV_report_generator.h
new file mode 100644
index 000000000..8842baf8e
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/CSV_report_generator.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MLAPSE_CSV_REPORT_GENERATOR_H__
+#define __MLAPSE_CSV_REPORT_GENERATOR_H__
+
+#include "mlapse/benchmark_observer.h"
+
+#include <fstream>
+#include <string>
+
+namespace mlapse
+{
+
+class CSVReportGenerator final : public BenchmarkObserver
+{
+public:
+ CSVReportGenerator(const std::string &path) : _ofs{path, std::ofstream::out}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void notify(const NotificationArg<PhaseBegin> &arg) final;
+ void notify(const NotificationArg<PhaseEnd> &arg) final;
+ void notify(const NotificationArg<IterationBegin> &arg) final;
+ void notify(const NotificationArg<IterationEnd> &arg);
+
+private:
+ std::ofstream _ofs;
+
+ Phase _phase = uninitialized_phase();
+};
+
+} // namespace mlapse
+
+#endif // __MLAPSE_MULTICAST_OBSERER_H__
diff --git a/runtime/contrib/mlapse/tfl/mlapse/benchmark_observer.cc b/runtime/contrib/mlapse/tfl/mlapse/benchmark_observer.cc
new file mode 100644
index 000000000..f6d596a7b
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/benchmark_observer.cc
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mlapse/benchmark_observer.h"
+
+namespace mlapse
+{
+
+Phase uninitialized_phase(void) { return static_cast<Phase>(0); }
+
+} // namespace mlapse
diff --git a/runtime/contrib/mlapse/tfl/mlapse/benchmark_observer.h b/runtime/contrib/mlapse/tfl/mlapse/benchmark_observer.h
new file mode 100644
index 000000000..792911157
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/benchmark_observer.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MLAPSE_BENCHMARK_OBSERVER_H__
+#define __MLAPSE_BENCHMARK_OBSERVER_H__
+
+#include <cstdint>
+#include <chrono>
+
+namespace mlapse
+{
+
+enum Phase : int32_t
+{
+ // 0 denotes "uninitialized value"
+ Warmup = 1,
+ Record = 2,
+};
+
+Phase uninitialized_phase(void);
+
+enum Notification
+{
+ PhaseBegin,
+ PhaseEnd,
+ IterationBegin,
+ IterationEnd,
+};
+
+template <Notification N> struct NotificationArg;
+
+template <> struct NotificationArg<PhaseBegin>
+{
+ Phase phase;
+ uint32_t count;
+};
+
+template <> struct NotificationArg<PhaseEnd>
+{
+};
+
+template <> struct NotificationArg<IterationBegin>
+{
+ uint32_t index;
+};
+
+template <> struct NotificationArg<IterationEnd>
+{
+ std::chrono::milliseconds latency;
+};
+
+struct BenchmarkObserver
+{
+ virtual ~BenchmarkObserver() = default;
+
+ virtual void notify(const NotificationArg<PhaseBegin> &arg) = 0;
+ virtual void notify(const NotificationArg<PhaseEnd> &arg) = 0;
+ virtual void notify(const NotificationArg<IterationBegin> &arg) = 0;
+ virtual void notify(const NotificationArg<IterationEnd> &arg) = 0;
+};
+
+} // namespace mlapse
+
+#endif // __MLAPSE_BENCHMARK_OBSERVER_H__
diff --git a/runtime/contrib/mlapse/tfl/mlapse/benchmark_runner.cc b/runtime/contrib/mlapse/tfl/mlapse/benchmark_runner.cc
new file mode 100644
index 000000000..f5fc7302d
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/benchmark_runner.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mlapse/benchmark_runner.h"
+
+// From 'nnfw_lib_misc'
+#include <misc/benchmark.h>
+
+// From C++ Standard Library
+#include <cassert>
+
+namespace mlapse
+{
+void BenchmarkRunner::attach(BenchmarkObserver *observer)
+{
+ assert(_observer == nullptr);
+ _observer = observer;
+}
+
+void BenchmarkRunner::run(nnfw::tflite::Session *sess) const
+{
+ for (auto phase : {Warmup, Record})
+ {
+ uint32_t const count = _count.at(phase);
+
+ // Notify when each phase begins
+ {
+ NotificationArg<PhaseBegin> arg;
+
+ arg.phase = phase;
+ arg.count = count;
+
+ notify(arg);
+ }
+
+ for (uint32_t n = 0; n < count; ++n)
+ {
+ std::chrono::milliseconds elapsed(0);
+
+ sess->prepare();
+
+ // Notify when each iteration begins
+ {
+ NotificationArg<IterationBegin> arg;
+
+ arg.index = n;
+
+ notify(arg);
+ };
+
+ nnfw::misc::benchmark::measure(elapsed) << [&](void) {
+ if (!sess->run())
+ {
+ throw std::runtime_error{"run failed"};
+ }
+ };
+
+ // Notify when each iteration ends
+ {
+ NotificationArg<IterationEnd> arg;
+
+ arg.latency = elapsed;
+
+ notify(arg);
+ };
+
+ sess->teardown();
+ }
+
+ // Notify when each phase ends
+ {
+ NotificationArg<PhaseEnd> arg;
+
+ notify(arg);
+ }
+ }
+}
+
+void BenchmarkRunner::notify(const NotificationArg<PhaseBegin> &arg) const
+{
+ if (_observer)
+ {
+ _observer->notify(arg);
+ }
+}
+
+void BenchmarkRunner::notify(const NotificationArg<PhaseEnd> &arg) const
+{
+ if (_observer)
+ {
+ _observer->notify(arg);
+ }
+}
+
+void BenchmarkRunner::notify(const NotificationArg<IterationBegin> &arg) const
+{
+ if (_observer)
+ {
+ _observer->notify(arg);
+ }
+}
+
+void BenchmarkRunner::notify(const NotificationArg<IterationEnd> &arg) const
+{
+ if (_observer)
+ {
+ _observer->notify(arg);
+ }
+}
+
+} // namespace mlapse
diff --git a/runtime/contrib/mlapse/tfl/mlapse/benchmark_runner.h b/runtime/contrib/mlapse/tfl/mlapse/benchmark_runner.h
new file mode 100644
index 000000000..7f10c059f
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/benchmark_runner.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MLAPSE_BENCHMARK_RUNNER_H__
+#define __MLAPSE_BENCHMARK_RUNNER_H__
+
+#include "mlapse/benchmark_observer.h"
+
+#include <tflite/Session.h>
+
+#include <chrono>
+#include <map>
+
+namespace mlapse
+{
+
+class BenchmarkRunner final
+{
+public:
+ BenchmarkRunner(uint32_t warmup_count, uint32_t record_count)
+ {
+ _count[Warmup] = warmup_count;
+ _count[Record] = record_count;
+ }
+
+public:
+ void attach(BenchmarkObserver *observer);
+
+public:
+ void run(nnfw::tflite::Session *sess) const;
+
+public:
+ void run(const std::unique_ptr<nnfw::tflite::Session> &sess) const { run(sess.get()); }
+
+private:
+ void notify(const NotificationArg<PhaseBegin> &arg) const;
+ void notify(const NotificationArg<PhaseEnd> &arg) const;
+ void notify(const NotificationArg<IterationBegin> &arg) const;
+ void notify(const NotificationArg<IterationEnd> &arg) const;
+
+private:
+ std::map<Phase, uint32_t> _count;
+
+private:
+ BenchmarkObserver *_observer = nullptr;
+};
+
+} // namespace mlapse
+
+#endif // __MLAPSE_BENCHMARK_RUNNER_H__
diff --git a/runtime/contrib/mlapse/tfl/mlapse/multicast_observer.cc b/runtime/contrib/mlapse/tfl/mlapse/multicast_observer.cc
new file mode 100644
index 000000000..639acfe45
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/multicast_observer.cc
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mlapse/multicast_observer.h"
diff --git a/runtime/contrib/mlapse/tfl/mlapse/multicast_observer.h b/runtime/contrib/mlapse/tfl/mlapse/multicast_observer.h
new file mode 100644
index 000000000..e4aac50a9
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/multicast_observer.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MLAPSE_MULTICAST_OBSERER_H__
+#define __MLAPSE_MULTICAST_OBSERER_H__
+
+#include "mlapse/benchmark_observer.h"
+
+#include <memory>
+#include <vector>
+
+namespace mlapse
+{
+
+class MulticastObserver final : public BenchmarkObserver
+{
+public:
+ MulticastObserver() = default;
+
+public:
+ void append(std::unique_ptr<BenchmarkObserver> &&o) { _observers.emplace_back(std::move(o)); }
+
+public:
+ void notify(const NotificationArg<PhaseBegin> &arg) final
+ {
+ for (const auto &o : _observers)
+ {
+ o->notify(arg);
+ }
+ }
+
+ void notify(const NotificationArg<PhaseEnd> &arg) final
+ {
+ for (const auto &o : _observers)
+ {
+ o->notify(arg);
+ }
+ }
+
+ void notify(const NotificationArg<IterationBegin> &arg) final
+ {
+ for (const auto &o : _observers)
+ {
+ o->notify(arg);
+ }
+ }
+
+ void notify(const NotificationArg<IterationEnd> &arg) final
+ {
+ for (const auto &o : _observers)
+ {
+ o->notify(arg);
+ }
+ }
+
+private:
+ std::vector<std::unique_ptr<BenchmarkObserver>> _observers;
+};
+
+} // namespace mlapse
+
+#endif // __MLAPSE_MULTICAST_OBSERER_H__
diff --git a/runtime/contrib/mlapse/tfl/mlapse/tfl/load.cc b/runtime/contrib/mlapse/tfl/mlapse/tfl/load.cc
new file mode 100644
index 000000000..9e770aecf
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/tfl/load.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mlapse/tfl/load.h"
+
+#include <tflite/ext/kernels/register.h>
+
+namespace
+{
+
+tflite::StderrReporter error_reporter;
+
+} // namespace
+
+namespace mlapse
+{
+namespace tfl
+{
+
+std::unique_ptr<tflite::FlatBufferModel> load_model(const std::string &path)
+{
+ return tflite::FlatBufferModel::BuildFromFile(path.c_str(), &error_reporter);
+}
+
+std::unique_ptr<tflite::Interpreter> make_interpreter(const tflite::FlatBufferModel *model)
+{
+ // Let's use extended resolver!
+ nnfw::tflite::BuiltinOpResolver resolver;
+ tflite::InterpreterBuilder builder(*model, resolver);
+
+ std::unique_ptr<tflite::Interpreter> interpreter;
+
+ if (builder(&interpreter) != kTfLiteOk)
+ {
+ return nullptr;
+ }
+
+ return std::move(interpreter);
+}
+
+} // namespace tfl
+} // namespace mlapse
diff --git a/runtime/contrib/mlapse/tfl/mlapse/tfl/load.h b/runtime/contrib/mlapse/tfl/mlapse/tfl/load.h
new file mode 100644
index 000000000..6f5a8f1ea
--- /dev/null
+++ b/runtime/contrib/mlapse/tfl/mlapse/tfl/load.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MLAPSE_TFL_LOAD_H__
+#define __MLAPSE_TFL_LOAD_H__
+
+#include <tensorflow/lite/interpreter.h>
+#include <tensorflow/lite/model.h>
+
+#include <memory>
+
+namespace mlapse
+{
+namespace tfl
+{
+
+std::unique_ptr<tflite::FlatBufferModel> load_model(const std::string &path);
+
+// WARNING
+//
+// model SHOULD outlive Interpreter
+std::unique_ptr<tflite::Interpreter> make_interpreter(const tflite::FlatBufferModel *model);
+
+} // namespace tfl
+} // namespace mlapse
+
+#endif // __MLAPSE_TFL_LOAD_H__
diff --git a/runtime/contrib/style_transfer_app/CMakeLists.txt b/runtime/contrib/style_transfer_app/CMakeLists.txt
new file mode 100644
index 000000000..b137231ea
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/CMakeLists.txt
@@ -0,0 +1,40 @@
+if(NOT BUILD_STYLE_TRANSFER_APP)
+ return()
+endif(NOT BUILD_STYLE_TRANSFER_APP)
+
+if(NOT BUILD_ONERT)
+ return()
+endif(NOT BUILD_ONERT)
+
+find_package(JPEG)
+if(JPEG_FOUND)
+ add_definitions(-DNNFW_ST_APP_JPEG_SUPPORTED)
+else(JPEG_FOUND)
+ message(WARNING "JPEG not found.")
+endif(JPEG_FOUND)
+
+list(APPEND STYLE_TRANSFER_APP_SRCS "src/style_transfer_app.cc")
+list(APPEND STYLE_TRANSFER_APP_SRCS "src/args.cc")
+list(APPEND STYLE_TRANSFER_APP_SRCS "src/bitmap_helper.cc")
+if(JPEG_FOUND)
+ list(APPEND STYLE_TRANSFER_APP_SRCS "src/jpeg_helper.cc")
+endif(JPEG_FOUND)
+
+nnfw_find_package(Boost REQUIRED program_options system filesystem)
+
+add_executable(style_transfer_app ${STYLE_TRANSFER_APP_SRCS})
+target_include_directories(style_transfer_app PRIVATE src)
+target_include_directories(style_transfer_app PRIVATE ${Boost_INCLUDE_DIRS})
+if(JPEG_FOUND)
+ target_include_directories(style_transfer_app PRIVATE ${JPEG_INCLUDE_DIRS})
+endif(JPEG_FOUND)
+
+target_link_libraries(style_transfer_app onert_core onert tflite_loader)
+target_link_libraries(style_transfer_app tensorflow-lite ${LIB_PTHREAD} dl nnfw_lib_tflite)
+target_link_libraries(style_transfer_app nnfw-dev)
+target_link_libraries(tflite_loader_test_tool ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY})
+if(JPEG_FOUND)
+ target_link_libraries(style_transfer_app ${JPEG_LIBRARIES})
+endif(JPEG_FOUND)
+
+install(TARGETS style_transfer_app DESTINATION bin)
diff --git a/runtime/contrib/style_transfer_app/README.md b/runtime/contrib/style_transfer_app/README.md
new file mode 100644
index 000000000..f56cb806e
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/README.md
@@ -0,0 +1,23 @@
+# style_transfer_app
+
+A sample app that runs `style transfer models`
+
+It reads a neural network model from an `nnpackage` and an input image, converts the image through the network, and produces an output image.
+
+It supports both JPG and BMP image formats. It uses **runtime API** internally.
+
+## How to use
+
+```
+$ ./style_transfer_app --nnpackage path_to_nnpackage --input input_image --output output_image
+```
+
+## Install libjpeg
+
+To read/write JPG images, you should install `libjpeg` on the host and target device.
+
+```bash
+$ sudo apt-get install libjpeg-dev
+```
+
+If `libjpeg` is not installed on the host or target, this app only supports the BMP file format.
diff --git a/runtime/contrib/style_transfer_app/src/args.cc b/runtime/contrib/style_transfer_app/src/args.cc
new file mode 100644
index 000000000..e194b8203
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/src/args.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "args.h"
+
+#include <iostream>
+#include <boost/filesystem.hpp>
+
+namespace StyleTransferApp
+{
+
+Args::Args(const int argc, char **argv) noexcept
+{
+ Initialize();
+ Parse(argc, argv);
+}
+
+void Args::Initialize(void)
+{
+ // General options
+ po::options_description general("General options");
+
+ // clang-format off
+ general.add_options()
+ ("help,h", "Display available options")
+ ("nnpackage", po::value<std::string>()->required(), "nnpackage path")
+ ("input,i", po::value<std::string>()->required(), "Input image path")
+ ("output,o", po::value<std::string>()->required(), "Output image path");
+ // clang-format on
+
+ _options.add(general);
+ _positional.add("nnpackage", 1);
+}
+
+void Args::Parse(const int argc, char **argv)
+{
+
+ po::variables_map vm;
+ try
+ {
+ po::store(po::command_line_parser(argc, argv).options(_options).positional(_positional).run(),
+ vm);
+
+ if (vm.count("help"))
+ {
+ std::cout << "style_transfer_app\n\n";
+ std::cout << "Usage: " << argv[0] << " path to nnpackage root directory [<options>]\n\n";
+ std::cout << _options;
+ std::cout << "\n";
+
+ exit(0);
+ }
+
+ po::notify(vm);
+
+ if (vm.count("input"))
+ {
+ _input_filename = vm["input"].as<std::string>();
+ }
+
+ if (vm.count("output"))
+ {
+ _output_filename = vm["output"].as<std::string>();
+ }
+
+ if (vm.count("nnpackage"))
+ {
+ _package_filename = vm["nnpackage"].as<std::string>();
+
+ if (!boost::filesystem::exists(_package_filename))
+ {
+ std::cerr << "nnpackage not found: " << _package_filename << "\n";
+ }
+ }
+ }
+ catch (const boost::program_options::required_option &e)
+ {
+ std::cerr << e.what() << std::endl;
+ return exit(-1);
+ }
+}
+
+} // namespace StyleTransferApp
diff --git a/runtime/contrib/style_transfer_app/src/args.h b/runtime/contrib/style_transfer_app/src/args.h
new file mode 100644
index 000000000..75cdc6fdd
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/src/args.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __STYLE_TRANSFER_APP_ARGS_H__
+#define __STYLE_TRANSFER_APP_ARGS_H__
+
+#include <string>
+#include <boost/program_options.hpp>
+
+namespace po = boost::program_options;
+
+namespace StyleTransferApp
+{
+
+class Args
+{
+public:
+ Args(const int argc, char **argv) noexcept;
+ void print(void);
+
+ const std::string &getPackageFilename(void) const { return _package_filename; }
+ const std::string &getInputFilename(void) const { return _input_filename; }
+ const std::string &getOutputFilename(void) const { return _output_filename; }
+
+private:
+ void Initialize();
+ void Parse(const int argc, char **argv);
+
+private:
+ po::positional_options_description _positional;
+ po::options_description _options;
+
+ std::string _package_filename;
+ std::string _input_filename;
+ std::string _output_filename;
+};
+
+} // end of namespace StyleTransferApp
+
+#endif // __STYLE_TRANSFER_APP_ARGS_H__
diff --git a/runtime/contrib/style_transfer_app/src/bitmap_helper.cc b/runtime/contrib/style_transfer_app/src/bitmap_helper.cc
new file mode 100644
index 000000000..6211ea476
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/src/bitmap_helper.cc
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+
+#include <unistd.h> // NOLINT(build/include_order)
+
+#include "bitmap_helper.h"
+
+#define LOG(x) std::cerr
+
+namespace StyleTransferApp
+{
+
+unsigned char *BitmapHelper::createBitmapFileHeader(int height, int width, int paddingSize)
+{
+ int fileSize = fileHeaderSize + infoHeaderSize + (bytesPerPixel * width + paddingSize) * height;
+
+ static unsigned char fileHeader[] = {
+ 0, 0, /// signature
+ 0, 0, 0, 0, /// image file size in bytes
+ 0, 0, 0, 0, /// reserved
+ 0, 0, 0, 0, /// start of pixel array
+ };
+
+ fileHeader[0] = (unsigned char)('B');
+ fileHeader[1] = (unsigned char)('M');
+ fileHeader[2] = (unsigned char)(fileSize);
+ fileHeader[3] = (unsigned char)(fileSize >> 8);
+ fileHeader[4] = (unsigned char)(fileSize >> 16);
+ fileHeader[5] = (unsigned char)(fileSize >> 24);
+ fileHeader[10] = (unsigned char)(fileHeaderSize + infoHeaderSize);
+
+ return fileHeader;
+}
+
+unsigned char *BitmapHelper::createBitmapInfoHeader(int height, int width)
+{
+ static unsigned char infoHeader[] = {
+ 0, 0, 0, 0, /// header size
+ 0, 0, 0, 0, /// image width
+ 0, 0, 0, 0, /// image height
+ 0, 0, /// number of color planes
+ 0, 0, /// bits per pixel
+ 0, 0, 0, 0, /// compression
+ 0, 0, 0, 0, /// image size
+ 0, 0, 0, 0, /// horizontal resolution
+ 0, 0, 0, 0, /// vertical resolution
+ 0, 0, 0, 0, /// colors in color table
+ 0, 0, 0, 0, /// important color count
+ };
+
+ // Minus height means top to bottom write
+ height = -height;
+
+ infoHeader[0] = (unsigned char)(infoHeaderSize);
+ infoHeader[4] = (unsigned char)(width);
+ infoHeader[5] = (unsigned char)(width >> 8);
+ infoHeader[6] = (unsigned char)(width >> 16);
+ infoHeader[7] = (unsigned char)(width >> 24);
+ infoHeader[8] = (unsigned char)(height);
+ infoHeader[9] = (unsigned char)(height >> 8);
+ infoHeader[10] = (unsigned char)(height >> 16);
+ infoHeader[11] = (unsigned char)(height >> 24);
+ infoHeader[12] = (unsigned char)(1);
+ infoHeader[14] = (unsigned char)(bytesPerPixel * 8);
+
+ return infoHeader;
+}
+
+std::vector<uint8_t> BitmapHelper::decode_bmp(const uint8_t *input, int row_size, int width,
+ int height, int channels, bool top_down)
+{
+ std::vector<uint8_t> output(height * width * channels);
+ for (int i = 0; i < height; i++)
+ {
+ int src_pos;
+ int dst_pos;
+
+ for (int j = 0; j < width; j++)
+ {
+ if (!top_down)
+ {
+ src_pos = ((height - 1 - i) * row_size) + j * channels;
+ }
+ else
+ {
+ src_pos = i * row_size + j * channels;
+ }
+
+ dst_pos = (i * width + j) * channels;
+
+ switch (channels)
+ {
+ case 1:
+ output[dst_pos] = input[src_pos];
+ break;
+ case 3:
+ // BGR -> RGB
+ output[dst_pos] = input[src_pos + 2];
+ output[dst_pos + 1] = input[src_pos + 1];
+ output[dst_pos + 2] = input[src_pos];
+ break;
+ case 4:
+ // BGRA -> RGBA
+ output[dst_pos] = input[src_pos + 2];
+ output[dst_pos + 1] = input[src_pos + 1];
+ output[dst_pos + 2] = input[src_pos];
+ output[dst_pos + 3] = input[src_pos + 3];
+ break;
+ default:
+ LOG(FATAL) << "Unexpected number of channels: " << channels;
+ break;
+ }
+ }
+ }
+ return output;
+}
+
+int BitmapHelper::read_bmp(const std::string &input_bmp_name, std::vector<float> &input,
+ int model_width, int model_height)
+{
+ int begin, end;
+ int width, height, channels;
+
+ std::ifstream file(input_bmp_name, std::ios::in | std::ios::binary);
+ if (!file)
+ {
+ LOG(FATAL) << "Error opening " << input_bmp_name << "\n";
+ exit(-1);
+ }
+
+ begin = file.tellg();
+ file.seekg(0, std::ios::end);
+ end = file.tellg();
+ size_t len = end - begin;
+
+ std::vector<uint8_t> img_bytes(len);
+ file.seekg(0, std::ios::beg);
+ file.read(reinterpret_cast<char *>(img_bytes.data()), len);
+ const int32_t header_size = *(reinterpret_cast<const int32_t *>(img_bytes.data() + 10));
+ width = *(reinterpret_cast<const int32_t *>(img_bytes.data() + 18));
+ height = *(reinterpret_cast<const int32_t *>(img_bytes.data() + 22));
+ const int32_t bpp = *(reinterpret_cast<const int32_t *>(img_bytes.data() + 28));
+ channels = bpp / 8;
+
+ // TODO: Implement resize function
+ assert(model_width == width);
+ assert(model_height == height);
+
+ // there may be padding bytes when the width is not a multiple of 4 bytes
+ // 8 * channels == bits per pixel
+ const int row_size = (8 * channels * width + 31) / 32 * 4;
+
+ // if height is negative, data layout is top down
+ // otherwise, it's bottom up
+ bool top_down = (height < 0);
+
+ // Decode image, allocating tensor once the image size is known
+ const uint8_t *bmp_pixels = &img_bytes[header_size];
+ std::vector<uint8_t> bmp =
+ decode_bmp(bmp_pixels, row_size, width, abs(height), channels, top_down);
+ for (uint32_t j = 0; j < bmp.size(); j++)
+ {
+ input.push_back(static_cast<float>(bmp[j]));
+ }
+ return 0;
+}
+
+int BitmapHelper::write_bmp(const std::string &output_bmp_name, std::vector<float> &output,
+ int width, int height, int channels)
+{
+ std::ofstream file(output_bmp_name, std::ios::out | std::ios::binary);
+ if (!file)
+ {
+ LOG(FATAL) << "Error opening " << output_bmp_name << "\n";
+ exit(-1);
+ }
+
+ unsigned char padding[3] = {0, 0, 0};
+ int paddingSize = (4 - (width * channels) % 4) % 4;
+
+ const unsigned char *fileHeader = createBitmapFileHeader(height, width, paddingSize);
+ const unsigned char *infoHeader = createBitmapInfoHeader(height, width);
+
+ file.write((char *)fileHeader, fileHeaderSize);
+ file.write((char *)infoHeader, infoHeaderSize);
+
+ // RGB to BGR
+ for (int i = 0; i < output.size(); i += 3)
+ {
+ file << static_cast<unsigned char>(output[i + 2]);
+ file << static_cast<unsigned char>(output[i + 1]);
+ file << static_cast<unsigned char>(output[i]);
+ for (int j = 0; j < paddingSize; j++)
+ {
+ file << padding;
+ }
+ }
+ file.close();
+ return 0;
+}
+
+} // namespace StyleTransferApp
diff --git a/runtime/contrib/style_transfer_app/src/bitmap_helper.h b/runtime/contrib/style_transfer_app/src/bitmap_helper.h
new file mode 100644
index 000000000..f499fff62
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/src/bitmap_helper.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#ifndef __STYLE_TRANSFER_APP_BITMAP_HELPER_H__
+#define __STYLE_TRANSFER_APP_BITMAP_HELPER_H__
+
+#include <vector>
+
+namespace StyleTransferApp
+{
+
+class BitmapHelper
+{
+public:
+ BitmapHelper(){/* DO NOTHING */};
+ int read_bmp(const std::string &input_bmp_name, std::vector<float> &input, int model_width,
+ int model_height);
+ int write_bmp(const std::string &output_bmp_name, std::vector<float> &output, int width,
+ int height, int channels);
+
+private:
+ unsigned char *createBitmapFileHeader(int height, int width, int paddingSize);
+ unsigned char *createBitmapInfoHeader(int height, int width);
+ std::vector<uint8_t> decode_bmp(const uint8_t *input, int row_size, int width, int height,
+ int channels, bool top_down);
+
+ const int fileHeaderSize = 14;
+ const int infoHeaderSize = 40;
+ const int bytesPerPixel = 3;
+};
+
+} // namespace StyleTransferApp
+
+#endif // __STYLE_TRANSFER_APP_BITMAP_HELPER_H__
diff --git a/runtime/contrib/style_transfer_app/src/jpeg_helper.cc b/runtime/contrib/style_transfer_app/src/jpeg_helper.cc
new file mode 100644
index 000000000..ed5ae25a1
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/src/jpeg_helper.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jpeg_helper.h"
+
+#include <cassert>
+#include <stdio.h>
+#include <jpeglib.h>
+#include <stdlib.h>
+#include <vector>
+
+namespace StyleTransferApp
+{
+
+JpegHelper::JpegHelper(int bytes_per_pixel, J_COLOR_SPACE color_space)
+ : _bytes_per_pixel(bytes_per_pixel), _color_space(color_space)
+{
+ // DO NOTHING
+}
+
+int JpegHelper::readJpeg(const std::string filename, std::vector<float> &raw_image, int width,
+ int height)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+
+ FILE *infile = fopen(filename.c_str(), "rb");
+ unsigned long location = 0;
+ int i = 0;
+
+ if (!infile)
+ {
+ printf("Error opening jpeg file %s\n!", filename);
+ return -1;
+ }
+
+ cinfo.err = jpeg_std_error(&jerr);
+
+ jpeg_create_decompress(&cinfo);
+
+ jpeg_stdio_src(&cinfo, infile);
+
+ jpeg_read_header(&cinfo, TRUE);
+
+ jpeg_start_decompress(&cinfo);
+
+ // TODO: Implement resize function
+ assert(cinfo.output_width == width);
+ assert(cinfo.output_height == height);
+
+ raw_image.resize(cinfo.output_width * cinfo.output_height * cinfo.num_components);
+
+ unsigned char *ptr = new unsigned char[cinfo.output_width * cinfo.num_components];
+
+ while (cinfo.output_scanline < cinfo.image_height)
+ {
+ jpeg_read_scanlines(&cinfo, &ptr, 1);
+ for (i = 0; i < cinfo.image_width * cinfo.num_components; i++)
+ {
+ raw_image[location++] = static_cast<float>(ptr[i]);
+ }
+ }
+
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ delete (ptr);
+ fclose(infile);
+
+ return 1;
+}
+
+int JpegHelper::writeJpeg(const std::string filename, std::vector<float> &raw_image, int width,
+ int height)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ unsigned long location = 0;
+
+ FILE *outfile = fopen(filename.c_str(), "wb");
+
+ if (!outfile)
+ {
+ printf("Error opening output jpeg file %s\n!", filename);
+ return -1;
+ }
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = _bytes_per_pixel;
+ cinfo.in_color_space = _color_space;
+
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+ unsigned char *ptr = new unsigned char[cinfo.image_width * cinfo.input_components];
+
+ while (cinfo.next_scanline < cinfo.image_height)
+ {
+ for (int i = 0; i < cinfo.image_width * cinfo.input_components; i++)
+ {
+ ptr[i] = static_cast<unsigned char>(raw_image[location++]);
+ }
+ jpeg_write_scanlines(&cinfo, &ptr, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ fclose(outfile);
+ delete (ptr);
+
+ jpeg_destroy_compress(&cinfo);
+
+ return 1;
+}
+
+} // namespace StyleTransferApp
diff --git a/runtime/contrib/style_transfer_app/src/jpeg_helper.h b/runtime/contrib/style_transfer_app/src/jpeg_helper.h
new file mode 100644
index 000000000..e6d7845b5
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/src/jpeg_helper.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __STYLE_TRANSFER_APP_JPEG_HELPER_H__
+#define __STYLE_TRANSFER_APP_JPEG_HELPER_H__
+
+#include <vector>
+#include <string>
+#include <jpeglib.h>
+
+namespace StyleTransferApp
+{
+
+class JpegHelper
+{
+public:
+ JpegHelper(){/* DO NOTHING */};
+ JpegHelper(int bytes_per_pixel, J_COLOR_SPACE color_space);
+
+ int readJpeg(const std::string filename, std::vector<float> &raw_image, int width, int height);
+ int writeJpeg(const std::string filename, std::vector<float> &raw_image, int width, int height);
+
+private:
+ int _bytes_per_pixel = 3; /* or 1 for GRACYSCALE images */
+ J_COLOR_SPACE _color_space = JCS_RGB; /* or JCS_GRAYSCALE for grayscale images */
+};
+
+} // namespace StyleTransferApp
+
+#endif // __STYLE_TRANSFER_APP_JPEG_HELPER_H__
diff --git a/runtime/contrib/style_transfer_app/src/style_transfer_app.cc b/runtime/contrib/style_transfer_app/src/style_transfer_app.cc
new file mode 100644
index 000000000..eed0c4288
--- /dev/null
+++ b/runtime/contrib/style_transfer_app/src/style_transfer_app.cc
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "args.h"
+#include "bitmap_helper.h"
+#include "nnfw.h"
+
+#ifdef NNFW_ST_APP_JPEG_SUPPORTED
+#include "jpeg_helper.h"
+#endif
+
+#include <cassert>
+#include <chrono>
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <unordered_map>
+#include <math.h>
+
+#define NNPR_ENSURE_STATUS(a) \
+ do \
+ { \
+ if ((a) != NNFW_STATUS_NO_ERROR) \
+ { \
+ exit(-1); \
+ } \
+ } while (0)
+
+enum ImageFormat
+{
+ JPEG = 0,
+ BMP,
+ OTHERS
+};
+
+uint64_t NowMicros()
+{
+ auto time_point = std::chrono::high_resolution_clock::now();
+ auto since_epoch = time_point.time_since_epoch();
+ // default precision of high resolution clock is 10e-9 (nanoseconds)
+ return std::chrono::duration_cast<std::chrono::microseconds>(since_epoch).count();
+}
+
+uint64_t num_elems(const nnfw_tensorinfo *ti)
+{
+ uint64_t n = 1;
+ for (uint32_t i = 0; i < ti->rank; ++i)
+ {
+ assert(ti->dims[i] >= 0);
+ n *= ti->dims[i];
+ }
+ return n;
+}
+
+NNFW_STATUS resolve_op_backend(nnfw_session *session)
+{
+ static std::unordered_map<std::string, std::string> operation_map = {
+ {"TRANSPOSE_CONV", "OP_BACKEND_TransposeConv"}, {"CONV_2D", "OP_BACKEND_Conv2D"},
+ {"DEPTHWISE_CONV_2D", "OP_BACKEND_DepthwiseConv2D"}, {"MEAN", "OP_BACKEND_Mean"},
+ {"AVERAGE_POOL_2D", "OP_BACKEND_AvgPool2D"}, {"MAX_POOL_2D", "OP_BACKEND_MaxPool2D"},
+ {"INSTANCE_NORM", "OP_BACKEND_InstanceNorm"}, {"ADD", "OP_BACKEND_Add"}};
+
+ for (auto i : operation_map)
+ {
+ char *default_backend = std::getenv(i.second.c_str());
+ if (default_backend)
+ {
+ NNFW_STATUS return_result = nnfw_set_op_backend(session, i.first.c_str(), default_backend);
+ if (return_result == NNFW_STATUS_ERROR)
+ return return_result;
+ }
+ }
+
+ return NNFW_STATUS_NO_ERROR;
+}
+
+ImageFormat get_image_format(const std::string &FileName)
+{
+ std::string ext;
+ if (FileName.find_last_of(".") != std::string::npos)
+ ext = FileName.substr(FileName.find_last_of(".") + 1);
+
+ if (ext == "jpeg" || ext == "jpg")
+ return ImageFormat::JPEG;
+ else if (ext == "bmp")
+ return ImageFormat::BMP;
+ else
+ return ImageFormat::OTHERS;
+}
+
+static int vector_tanh(std::vector<float> &a)
+{
+ int size = a.size();
+
+#pragma omp parallel for
+ for (int i = 0; i < size; i++)
+ {
+ float temp = tanh(a[i]) * 150 + 127.5f;
+ a[i] = temp > 255 ? 255 : temp < 0 ? 0 : temp;
+ }
+
+ return 0;
+}
+
+int main(const int argc, char **argv)
+{
+ StyleTransferApp::Args args(argc, argv);
+ auto nnpackage_path = args.getPackageFilename();
+
+ nnfw_session *session = nullptr;
+ NNPR_ENSURE_STATUS(nnfw_create_session(&session));
+ char *available_backends = std::getenv("BACKENDS");
+ if (available_backends)
+ NNPR_ENSURE_STATUS(nnfw_set_available_backends(session, available_backends));
+ NNPR_ENSURE_STATUS(resolve_op_backend(session));
+
+ NNPR_ENSURE_STATUS(nnfw_load_model_from_file(session, nnpackage_path.c_str()));
+
+ uint32_t num_inputs;
+ NNPR_ENSURE_STATUS(nnfw_input_size(session, &num_inputs));
+
+ // verify input and output
+
+ if (num_inputs == 0)
+ {
+ std::cerr << "[ ERROR ] "
+ << "No inputs in model => execution is not possible" << std::endl;
+ exit(1);
+ }
+
+ auto verifyInputTypes = [session]() {
+ uint32_t sz;
+ NNPR_ENSURE_STATUS(nnfw_input_size(session, &sz));
+ for (uint32_t i = 0; i < sz; ++i)
+ {
+ nnfw_tensorinfo ti;
+ NNPR_ENSURE_STATUS(nnfw_input_tensorinfo(session, i, &ti));
+ if (ti.dtype != NNFW_TYPE_TENSOR_FLOAT32)
+ {
+ std::cerr << "Only float 32bit is supported." << std::endl;
+ exit(-1);
+ }
+ }
+ };
+
+ auto verifyOutputTypes = [session]() {
+ uint32_t sz;
+ NNPR_ENSURE_STATUS(nnfw_output_size(session, &sz));
+
+ for (uint32_t i = 0; i < sz; ++i)
+ {
+ nnfw_tensorinfo ti;
+ NNPR_ENSURE_STATUS(nnfw_output_tensorinfo(session, i, &ti));
+ if (ti.dtype != NNFW_TYPE_TENSOR_FLOAT32)
+ {
+ std::cerr << "Only float 32bit is supported." << std::endl;
+ exit(-1);
+ }
+ }
+ };
+
+ verifyInputTypes();
+ verifyOutputTypes();
+
+ // prepare execution
+
+ uint64_t prepare_us = NowMicros();
+ NNPR_ENSURE_STATUS(nnfw_prepare(session));
+ prepare_us = NowMicros() - prepare_us;
+
+ // prepare input
+
+ std::vector<std::vector<float>> inputs(num_inputs);
+
+ auto loadInputs = [session, num_inputs, &inputs](const std::string &filename) {
+ for (uint32_t i = 0; i < num_inputs; ++i)
+ {
+ nnfw_tensorinfo ti;
+ NNPR_ENSURE_STATUS(nnfw_input_tensorinfo(session, i, &ti));
+
+ ImageFormat format = get_image_format(filename);
+ switch (format)
+ {
+ case ImageFormat::JPEG:
+ {
+#ifdef NNFW_ST_APP_JPEG_SUPPORTED
+ StyleTransferApp::JpegHelper jpeg_helper;
+ jpeg_helper.readJpeg(filename, inputs[i], ti.dims[2], ti.dims[1]);
+#else
+ std::cerr << "JPEG format not supported. Install libjpeg to read/write jpeg images."
+ << std::endl;
+ exit(-1);
+#endif
+ break;
+ }
+ case ImageFormat::BMP:
+ {
+ StyleTransferApp::BitmapHelper bitmap_helper;
+ bitmap_helper.read_bmp(filename, inputs[i], ti.dims[2], ti.dims[1]);
+ break;
+ }
+ default:
+ std::cerr << "Unsupported image format." << std::endl;
+ exit(-1);
+ break;
+ }
+
+ NNPR_ENSURE_STATUS(nnfw_set_input(session, i, NNFW_TYPE_TENSOR_FLOAT32, inputs[i].data(),
+ sizeof(float) * num_elems(&ti)));
+ NNPR_ENSURE_STATUS(nnfw_set_input_layout(session, i, NNFW_LAYOUT_CHANNELS_LAST));
+ }
+ };
+
+ if (!args.getInputFilename().empty())
+ loadInputs(args.getInputFilename());
+ else
+ std::exit(-1);
+
+ // prepare output
+
+ uint32_t num_outputs = 0;
+ NNPR_ENSURE_STATUS(nnfw_output_size(session, &num_outputs));
+ std::vector<std::vector<float>> outputs(num_outputs);
+
+ for (uint32_t i = 0; i < num_outputs; i++)
+ {
+ nnfw_tensorinfo ti;
+ NNPR_ENSURE_STATUS(nnfw_output_tensorinfo(session, i, &ti));
+ auto output_num_elements = num_elems(&ti);
+ outputs[i].resize(output_num_elements);
+ NNPR_ENSURE_STATUS(nnfw_set_output(session, i, NNFW_TYPE_TENSOR_FLOAT32, outputs[i].data(),
+ sizeof(float) * output_num_elements));
+ NNPR_ENSURE_STATUS(nnfw_set_output_layout(session, i, NNFW_LAYOUT_CHANNELS_LAST));
+ }
+
+ uint64_t run_us = NowMicros();
+ NNPR_ENSURE_STATUS(nnfw_run(session));
+ run_us = NowMicros() - run_us;
+
+ // dump output tensors
+
+ auto dumpOutputs = [session, num_outputs, &outputs](const std::string &filename) {
+ for (uint32_t i = 0; i < num_outputs; ++i)
+ {
+ nnfw_tensorinfo ti;
+ NNPR_ENSURE_STATUS(nnfw_output_tensorinfo(session, i, &ti));
+
+ vector_tanh(outputs[i]);
+
+ ImageFormat format = get_image_format(filename);
+ switch (format)
+ {
+ case ImageFormat::JPEG:
+ {
+#ifdef NNFW_ST_APP_JPEG_SUPPORTED
+ StyleTransferApp::JpegHelper jpeg_helper;
+ jpeg_helper.writeJpeg(filename, outputs[i], ti.dims[2], ti.dims[1]);
+#else
+ std::cerr << "JPEG format not supported. Install libjpeg to read/write jpeg images."
+ << std::endl;
+ exit(-1);
+#endif
+ break;
+ }
+ case ImageFormat::BMP:
+ {
+ StyleTransferApp::BitmapHelper bitmap_helper;
+ bitmap_helper.write_bmp(filename, outputs[i], ti.dims[2], ti.dims[1], ti.dims[3]);
+ break;
+ }
+ default:
+ std::cerr << "Unsupported image format." << std::endl;
+ exit(-1);
+ break;
+ }
+ }
+ };
+
+ if (!args.getOutputFilename().empty())
+ dumpOutputs(args.getOutputFilename());
+
+ std::cout << "nnfw_prepare takes " << prepare_us / 1e3 << " ms" << std::endl;
+ std::cout << "nnfw_run takes " << run_us / 1e3 << " ms" << std::endl;
+
+ NNPR_ENSURE_STATUS(nnfw_close_session(session));
+
+ return 0;
+}
diff --git a/runtime/contrib/tflite_classify/CMakeLists.txt b/runtime/contrib/tflite_classify/CMakeLists.txt
new file mode 100644
index 000000000..c0bf62738
--- /dev/null
+++ b/runtime/contrib/tflite_classify/CMakeLists.txt
@@ -0,0 +1,22 @@
+if(NOT BUILD_TFLITE_CLASSIFY_APP)
+ return()
+endif(NOT BUILD_TFLITE_CLASSIFY_APP)
+
+list(APPEND SOURCES "src/tflite_classify.cc")
+list(APPEND SOURCES "src/ImageClassifier.cc")
+list(APPEND SOURCES "src/InferenceInterface.cc")
+
+## Required package
+find_package(OpenCV REQUIRED)
+find_package(Boost REQUIRED COMPONENTS system filesystem)
+
+# Without this line, this appliation couldn't search the opencv library that were already installed in ${ROOTFS_DIR}/usr/lib/arm-linux-gnueabihf directory
+set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${ROOTFS_DIR}/usr/lib/arm-linux-gnueabihf -Wl,--rpath=${ROOTFS_DIR}/lib/arm-linux-gnueabihf")
+
+add_executable(tflite_classify ${SOURCES})
+target_include_directories(tflite_classify PRIVATE src)
+target_link_libraries(tflite_classify tensorflow-lite ${LIB_PTHREAD} dl nnfw_lib_tflite)
+target_link_libraries(tflite_classify ${Boost_LIBRARIES})
+target_link_libraries(tflite_classify ${OpenCV_LIBRARIES})
+
+install(TARGETS tflite_classify DESTINATION bin)
diff --git a/runtime/contrib/tflite_classify/src/ImageClassifier.cc b/runtime/contrib/tflite_classify/src/ImageClassifier.cc
new file mode 100644
index 000000000..fae4f066c
--- /dev/null
+++ b/runtime/contrib/tflite_classify/src/ImageClassifier.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ImageClassifier.h"
+
+#include <fstream>
+#include <queue>
+#include <algorithm>
+
+ImageClassifier::ImageClassifier(const std::string &model_file, const std::string &label_file,
+ const int input_size, const int image_mean, const int image_std,
+ const std::string &input_name, const std::string &output_name,
+ const bool use_nnapi)
+ : _inference(new InferenceInterface(model_file, use_nnapi)), _input_size(input_size),
+ _image_mean(image_mean), _image_std(image_std), _input_name(input_name),
+ _output_name(output_name)
+{
+ // Load label
+ std::ifstream label_stream(label_file.c_str());
+ assert(label_stream);
+
+ std::string line;
+ while (std::getline(label_stream, line))
+ {
+ _labels.push_back(line);
+ }
+ _num_classes = _inference->getTensorSize(_output_name);
+ std::cout << "Output tensor size is " << _num_classes << ", label size is " << _labels.size()
+ << std::endl;
+
+ // Pre-allocate buffers
+ _fdata.reserve(_input_size * _input_size * 3);
+ _outputs.reserve(_num_classes);
+}
+
+std::vector<Recognition> ImageClassifier::recognizeImage(const cv::Mat &image)
+{
+ // Resize image
+ cv::Mat cropped;
+ cv::resize(image, cropped, cv::Size(_input_size, _input_size), 0, 0, cv::INTER_AREA);
+
+ // Preprocess the image data from 0~255 int to normalized float based
+ // on the provided parameters
+ _fdata.clear();
+ for (int y = 0; y < cropped.rows; ++y)
+ {
+ for (int x = 0; x < cropped.cols; ++x)
+ {
+ cv::Vec3b color = cropped.at<cv::Vec3b>(y, x);
+ color[0] = color[0] - (float)_image_mean / _image_std;
+ color[1] = color[1] - (float)_image_mean / _image_std;
+ color[2] = color[2] - (float)_image_mean / _image_std;
+
+ _fdata.push_back(color[0]);
+ _fdata.push_back(color[1]);
+ _fdata.push_back(color[2]);
+
+ cropped.at<cv::Vec3b>(y, x) = color;
+ }
+ }
+
+ // Copy the input data into model
+ _inference->feed(_input_name, _fdata, 1, _input_size, _input_size, 3);
+
+ // Run the inference call
+ _inference->run(_output_name);
+
+ // Copy the output tensor back into the output array
+ _inference->fetch(_output_name, _outputs);
+
+ // Find the best classifications
+ auto compare = [](const Recognition &lhs, const Recognition &rhs) {
+ return lhs.confidence < rhs.confidence;
+ };
+
+ std::priority_queue<Recognition, std::vector<Recognition>, decltype(compare)> pq(compare);
+ for (int i = 0; i < _num_classes; ++i)
+ {
+ if (_outputs[i] > _threshold)
+ {
+ pq.push(Recognition(_outputs[i], _labels[i]));
+ }
+ }
+
+ std::vector<Recognition> results;
+ int min = std::min(pq.size(), _max_results);
+ for (int i = 0; i < min; ++i)
+ {
+ results.push_back(pq.top());
+ pq.pop();
+ }
+
+ return results;
+}
diff --git a/runtime/contrib/tflite_classify/src/ImageClassifier.h b/runtime/contrib/tflite_classify/src/ImageClassifier.h
new file mode 100644
index 000000000..1ba19afb0
--- /dev/null
+++ b/runtime/contrib/tflite_classify/src/ImageClassifier.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ImageClassifier.h
+ * @brief This file contains ImageClassifier class and Recognition structure
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __TFLITE_CLASSIFY_IMAGE_CLASSIFIER_H__
+#define __TFLITE_CLASSIFY_IMAGE_CLASSIFIER_H__
+
+#include "InferenceInterface.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <opencv2/opencv.hpp>
+
+/**
+ * @brief struct to define an immutable result returned by a Classifier
+ */
+struct Recognition
+{
+public:
+ /**
+ * @brief Construct a new Recognition object with confidence and title
+ * @param[in] _confidence A sortable score for how good the recognition is relative to others.
+ * Higher should be better.
+ * @param[in] _title Display name for the recognition
+ */
+ Recognition(float _confidence, std::string _title) : confidence(_confidence), title(_title) {}
+
+ float confidence; /** A sortable score for how good the recognition is relative to others. Higher
+ should be better. */
+ std::string title; /** Display name for the recognition */
+};
+
+/**
+ * @brief Class to define a classifier specialized to label images
+ */
+class ImageClassifier
+{
+public:
+ /**
+ * @brief Construct a new ImageClassifier object with parameters
+ * @param[in] model_file The filepath of the model FlatBuffer protocol buffer
+ * @param[in] label_file The filepath of label file for classes
+ * @param[in] input_size The input size. A square image of input_size x input_size is assumed
+ * @param[in] image_mean The assumed mean of the image values
+ * @param[in] image_std The assumed std of the image values
+ * @param[in] input_name The label of the image input node
+ * @param[in] output_name The label of the output node
+ * @param[in] use_nnapi The flag to distinguish between TfLite interpreter and NNFW runtime
+ */
+ ImageClassifier(const std::string &model_file, const std::string &label_file,
+ const int input_size, const int image_mean, const int image_std,
+ const std::string &input_name, const std::string &output_name,
+ const bool use_nnapi);
+
+ /**
+ * @brief Recognize the given image data
+ * @param[in] image The image data to recognize
+ * @return An immutable result vector array
+ */
+ std::vector<Recognition> recognizeImage(const cv::Mat &image);
+
+private:
+ const float _threshold = 0.1f;
+ const unsigned int _max_results = 3;
+
+ std::unique_ptr<InferenceInterface> _inference;
+ int _input_size;
+ int _image_mean;
+ int _image_std;
+ std::string _input_name;
+ std::string _output_name;
+
+ std::vector<std::string> _labels;
+ std::vector<float> _fdata;
+ std::vector<float> _outputs;
+ int _num_classes;
+};
+
+#endif // __TFLITE_CLASSIFY_IMAGE_CLASSIFIER_H__
diff --git a/runtime/contrib/tflite_classify/src/InferenceInterface.cc b/runtime/contrib/tflite_classify/src/InferenceInterface.cc
new file mode 100644
index 000000000..160943477
--- /dev/null
+++ b/runtime/contrib/tflite_classify/src/InferenceInterface.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InferenceInterface.h"
+
+using namespace tflite;
+using namespace tflite::ops::builtin;
+
+InferenceInterface::InferenceInterface(const std::string &model_file, const bool use_nnapi)
+ : _interpreter(nullptr), _model(nullptr), _sess(nullptr)
+{
+ // Load model
+ StderrReporter error_reporter;
+ _model = FlatBufferModel::BuildFromFile(model_file.c_str(), &error_reporter);
+ BuiltinOpResolver resolver;
+ InterpreterBuilder builder(*_model, resolver);
+ builder(&_interpreter);
+
+ if (use_nnapi)
+ {
+ _sess = std::make_shared<nnfw::tflite::NNAPISession>(_interpreter.get());
+ }
+ else
+ {
+ _sess = std::make_shared<nnfw::tflite::InterpreterSession>(_interpreter.get());
+ }
+
+ _sess->prepare();
+}
+
+InferenceInterface::~InferenceInterface() { _sess->teardown(); }
+
+void InferenceInterface::feed(const std::string &input_name, const std::vector<float> &data,
+ const int batch, const int height, const int width, const int channel)
+{
+ // Set input tensor
+ for (const auto &id : _interpreter->inputs())
+ {
+ if (_interpreter->tensor(id)->name == input_name)
+ {
+ assert(_interpreter->tensor(id)->type == kTfLiteFloat32);
+ float *p = _interpreter->tensor(id)->data.f;
+
+ // TODO consider batch
+ for (int y = 0; y < height; ++y)
+ {
+ for (int x = 0; x < width; ++x)
+ {
+ for (int c = 0; c < channel; ++c)
+ {
+ *p++ = data[y * width * channel + x * channel + c];
+ }
+ }
+ }
+ }
+ }
+}
+
+void InferenceInterface::run(const std::string &output_name)
+{
+ // Run model
+ _sess->run();
+}
+
+void InferenceInterface::fetch(const std::string &output_name, std::vector<float> &outputs)
+{
+ // Get output tensor
+ for (const auto &id : _interpreter->outputs())
+ {
+ if (_interpreter->tensor(id)->name == output_name)
+ {
+ assert(_interpreter->tensor(id)->type == kTfLiteFloat32);
+ assert(getTensorSize(output_name) == outputs.capacity());
+ float *p = _interpreter->tensor(id)->data.f;
+
+ outputs.clear();
+ for (int i = 0; i < outputs.capacity(); ++i)
+ {
+ outputs.push_back(p[i]);
+ }
+ }
+ }
+}
+
+int InferenceInterface::getTensorSize(const std::string &name)
+{
+ for (const auto &id : _interpreter->outputs())
+ {
+ if (_interpreter->tensor(id)->name == name)
+ {
+ TfLiteTensor *t = _interpreter->tensor(id);
+ int v = 1;
+ for (int i = 0; i < t->dims->size; ++i)
+ {
+ v *= t->dims->data[i];
+ }
+ return v;
+ }
+ }
+ return -1;
+}
diff --git a/runtime/contrib/tflite_classify/src/InferenceInterface.h b/runtime/contrib/tflite_classify/src/InferenceInterface.h
new file mode 100644
index 000000000..fe2c1aa6c
--- /dev/null
+++ b/runtime/contrib/tflite_classify/src/InferenceInterface.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file InferenceInterface.h
+ * @brief This file contains class for running the actual inference model
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __TFLITE_CLASSIFY_INFERENCE_INTERFACE_H__
+#define __TFLITE_CLASSIFY_INFERENCE_INTERFACE_H__
+
+#include "tflite/ext/kernels/register.h"
+#include "tensorflow/lite/model.h"
+
+#include "tflite/InterpreterSession.h"
+#include "tflite/NNAPISession.h"
+
+#include <iostream>
+#include <string>
+
+/**
+ * @brief Class to define a inference interface for recognizing data
+ */
+class InferenceInterface
+{
+public:
+ /**
+ * @brief Construct a new InferenceInterface object with parameters
+ * @param[in] model_file The filepath of the model FlatBuffer protocol buffer
+ * @param[in] use_nnapi The flag to distinguish between TfLite interpreter and NNFW runtime
+ */
+ InferenceInterface(const std::string &model_file, const bool use_nnapi);
+
+ /**
+ * @brief Destructor an InferenceInterface object
+ */
+ ~InferenceInterface();
+
+ /**
+ * @brief Copy the input data into model
+ * @param[in] input_name The label of the image input node
+ * @param[in] data The actual data to be copied into input tensor
+ * @param[in] batch The number of batch size
+ * @param[in] height The number of height size
+ * @param[in] width The number of width size
+ * @param[in] channel The number of channel size
+ * @return N/A
+ */
+ void feed(const std::string &input_name, const std::vector<float> &data, const int batch,
+ const int height, const int width, const int channel);
+ /**
+ * @brief Run the inference call
+ * @param[in] output_name The label of the output node
+ * @return N/A
+ */
+ void run(const std::string &output_name);
+
+ /**
+ * @brief Copy the output tensor back into the output array
+ * @param[in] output_node The label of the output node
+ * @param[in] outputs The output data array
+ * @return N/A
+ */
+ void fetch(const std::string &output_name, std::vector<float> &outputs);
+
+ /**
+ * @brief Get tensor size
+ * @param[in] name The label of the node
+ * @result The size of tensor
+ */
+ int getTensorSize(const std::string &name);
+
+private:
+ std::unique_ptr<tflite::Interpreter> _interpreter;
+ std::unique_ptr<tflite::FlatBufferModel> _model;
+ std::shared_ptr<nnfw::tflite::Session> _sess;
+};
+
+#endif // __TFLITE_CLASSIFY_INFERENCE_INTERFACE_H__
diff --git a/runtime/contrib/tflite_classify/src/tflite_classify.cc b/runtime/contrib/tflite_classify/src/tflite_classify.cc
new file mode 100644
index 000000000..51758e2a6
--- /dev/null
+++ b/runtime/contrib/tflite_classify/src/tflite_classify.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ImageClassifier.h"
+
+#include <iostream>
+
+#include <boost/filesystem.hpp>
+#include <opencv2/opencv.hpp>
+
+namespace fs = boost::filesystem;
+
+int main(const int argc, char **argv)
+{
+ const std::string MODEL_FILE = "tensorflow_inception_graph.tflite";
+ const std::string LABEL_FILE = "imagenet_comp_graph_label_strings.txt";
+
+ const std::string INPUT_NAME = "input";
+ const std::string OUTPUT_NAME = "output";
+ const int INPUT_SIZE = 224;
+ const int IMAGE_MEAN = 117;
+ const int IMAGE_STD = 1;
+ const int OUTPUT_SIZE = 1008;
+
+ const int FRAME_WIDTH = 640;
+ const int FRAME_HEIGHT = 480;
+
+ const bool use_nnapi = nnfw::misc::EnvVar("USE_NNAPI").asBool(false);
+ const bool debug_mode = nnfw::misc::EnvVar("DEBUG_MODE").asBool(false);
+
+ std::cout << "USE_NNAPI : " << use_nnapi << std::endl;
+ std::cout << "DEBUG_MODE : " << debug_mode << std::endl;
+
+ std::cout << "Model : " << MODEL_FILE << std::endl;
+ std::cout << "Label : " << LABEL_FILE << std::endl;
+
+ if (!fs::exists(MODEL_FILE))
+ {
+ std::cerr << "model file not found: " << MODEL_FILE << std::endl;
+ exit(1);
+ }
+
+ if (!fs::exists(LABEL_FILE))
+ {
+ std::cerr << "label file not found: " << LABEL_FILE << std::endl;
+ exit(1);
+ }
+
+ // Create ImageClassifier
+ std::unique_ptr<ImageClassifier> classifier(
+ new ImageClassifier(MODEL_FILE, LABEL_FILE, INPUT_SIZE, IMAGE_MEAN, IMAGE_STD, INPUT_NAME,
+ OUTPUT_NAME, use_nnapi));
+
+ // Cam setting
+ cv::VideoCapture cap(0);
+ cv::Mat frame;
+
+ // Initialize camera
+ cap.set(CV_CAP_PROP_FRAME_WIDTH, FRAME_WIDTH);
+ cap.set(CV_CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT);
+ cap.set(CV_CAP_PROP_FPS, 5);
+
+ std::vector<Recognition> results;
+ clock_t begin, end;
+ while (cap.isOpened())
+ {
+ // Get image data
+ if (!cap.read(frame))
+ {
+ std::cout << "Frame is null..." << std::endl;
+ break;
+ }
+
+ if (debug_mode)
+ {
+ begin = clock();
+ }
+ // Recognize image
+ results = classifier->recognizeImage(frame);
+ if (debug_mode)
+ {
+ end = clock();
+ }
+
+ // Show result data
+ std::cout << std::endl;
+ if (results.size() > 0)
+ {
+ for (int i = 0; i < results.size(); ++i)
+ {
+ std::cout << results[i].title << ": " << results[i].confidence << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << "." << std::endl;
+ }
+ if (debug_mode)
+ {
+ std::cout << "Frame: " << FRAME_WIDTH << "x" << FRAME_HEIGHT << std::endl;
+ std::cout << "Crop: " << INPUT_SIZE << "x" << INPUT_SIZE << std::endl;
+ std::cout << "Inference time(ms): " << ((end - begin) / (CLOCKS_PER_SEC / 1000)) << std::endl;
+ }
+ }
+
+ cap.release();
+
+ return 0;
+}
diff --git a/runtime/contrib/tflite_test/CMakeLists.txt b/runtime/contrib/tflite_test/CMakeLists.txt
new file mode 100644
index 000000000..760952a84
--- /dev/null
+++ b/runtime/contrib/tflite_test/CMakeLists.txt
@@ -0,0 +1,16 @@
+if(NOT BUILD_TFLITE_TEST)
+ return()
+endif(NOT BUILD_TFLITE_TEST)
+
+nnfw_find_package(Tensorflow QUIET)
+
+if(NOT Tensorflow_FOUND)
+ return()
+endif(NOT Tensorflow_FOUND)
+
+list(APPEND SOURCES tflite_test.cpp)
+
+add_executable(tflite_test ${SOURCES})
+target_link_libraries(tflite_test PRIVATE nnfw_lib_tflite)
+target_link_libraries(tflite_test PRIVATE tensorflow-lite)
+target_link_libraries(tflite_test PRIVATE tensorflow-core)
diff --git a/runtime/contrib/tflite_test/tflite_test.cpp b/runtime/contrib/tflite_test/tflite_test.cpp
new file mode 100644
index 000000000..9b6f07717
--- /dev/null
+++ b/runtime/contrib/tflite_test/tflite_test.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <tensorflow/lite/model.h>
+#include <tensorflow/core/public/session.h>
+
+#include "tflite/Assert.h"
+#include "tflite/Session.h"
+#include "tflite/InterpreterSession.h"
+#include "tflite/NNAPISession.h"
+#include "tflite/ext/kernels/register.h"
+
+#include "misc/fp32.h"
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+
+#define TF_ENSURE(e) \
+ { \
+ if (!(e).ok()) \
+ { \
+ throw std::runtime_error{"'" #e "' FAILED"}; \
+ } \
+ }
+
+using namespace tflite;
+using namespace tflite::ops::builtin;
+
+std::unique_ptr<FlatBufferModel> BuildModelFromFile(const std::string &path)
+{
+ static StderrReporter reporter;
+ return FlatBufferModel::BuildFromFile(path.c_str(), &reporter);
+}
+
+std::unique_ptr<Interpreter> BuildInterpFromModel(const std::unique_ptr<FlatBufferModel> &model)
+{
+ std::unique_ptr<Interpreter> interp;
+
+ BuiltinOpResolver resolver;
+ InterpreterBuilder builder(*model, resolver);
+
+ TFLITE_ENSURE(builder(&interp));
+
+ return std::move(interp);
+}
+
+tensorflow::TensorShape asTensorflowShape(const TfLiteTensor *tensor)
+{
+ tensorflow::TensorShape shape;
+
+ const int rank = tensor->dims->size;
+
+ for (int axis = 0; axis < rank; ++axis)
+ {
+ shape.AddDim(tensor->dims->data[axis]);
+ }
+
+ return shape;
+}
+
+uint32_t count_elements(const TfLiteTensor *tensor)
+{
+ const int rank = tensor->dims->size;
+
+ if (rank == 0)
+ {
+ return 0;
+ }
+
+ uint32_t res = 1;
+
+ for (int axis = 0; axis < rank; ++axis)
+ {
+ res *= tensor->dims->data[axis];
+ }
+
+ return res;
+}
+
+int main(int argc, char **argv)
+{
+ const bool use_nnapi = nnfw::misc::EnvVar("USE_NNAPI").asBool(false);
+
+ if (argc < 3)
+ {
+ std::cerr << "USAGE: " << argv[0] << " [T/F lite model] [T/F model]" << std::endl;
+ return 255;
+ }
+
+ //
+ // Prepare Tensorflow Lite session
+ //
+ const std::string lite_model_path{argv[1]};
+
+ auto lite_model = BuildModelFromFile(lite_model_path);
+ auto lite_interp = BuildInterpFromModel(lite_model);
+
+ std::shared_ptr<nnfw::tflite::Session> lite_sess;
+
+ if (use_nnapi)
+ {
+ lite_sess = std::make_shared<nnfw::tflite::NNAPISession>(lite_interp.get());
+ }
+ else
+ {
+ lite_sess = std::make_shared<nnfw::tflite::InterpreterSession>(lite_interp.get());
+ }
+
+ //
+ // Prepare Tensorflow session
+ //
+ const std::string full_model_path{argv[2]};
+
+ tensorflow::Session *full_sess;
+ tensorflow::GraphDef full_model;
+
+ TF_ENSURE(tensorflow::NewSession(tensorflow::SessionOptions(), &full_sess));
+ TF_ENSURE(ReadBinaryProto(tensorflow::Env::Default(), full_model_path, &full_model));
+ TF_ENSURE(full_sess->Create(full_model));
+
+ //
+ //
+ //
+ std::vector<tensorflow::Tensor> input_nodes;
+ std::vector<std::string> input_names;
+
+ for (uint32_t n = 0; n < lite_interp->inputs().size(); ++n)
+ {
+ const TfLiteTensor *tensor = lite_interp->tensor(lite_interp->inputs().at(n));
+
+ input_nodes.emplace_back(tensorflow::DT_FLOAT, asTensorflowShape(tensor));
+ input_names.emplace_back(tensor->name);
+ }
+
+ assert(input_nodes.size() == input_names.size());
+ assert(input_nodes.size() == lite_interp->inputs().size());
+
+ std::vector<std::string> output_names;
+ std::vector<tensorflow::Tensor> output_nodes;
+
+ for (uint32_t n = 0; n < lite_interp->outputs().size(); ++n)
+ {
+ const TfLiteTensor *tensor = lite_interp->tensor(lite_interp->outputs().at(n));
+
+ output_names.emplace_back(tensor->name);
+ }
+
+ assert(output_names.size() == lite_interp->outputs().size());
+ // output_nodes will be initialized after Tensorflow Session run
+ assert(output_nodes.size() == 0);
+
+ //
+ // Prepare inference
+ //
+ lite_sess->prepare();
+
+ // TODO Feed Inputs (for both Tensorflow and Tensorflow Lite)
+ std::vector<std::pair<std::string, tensorflow::Tensor>> inputs;
+
+ for (uint32_t n = 0; n < input_nodes.size(); ++n)
+ {
+ inputs.emplace_back(input_names.at(0), input_nodes.at(0));
+ }
+
+ //
+ // Run inference
+ //
+ TF_ENSURE(full_sess->Run(inputs, output_names, {}, &output_nodes));
+
+ lite_sess->run();
+
+ //
+ // Compare Output
+ //
+ auto equals = [](float lhs, float rhs) {
+ // TODO Allow users to set tolerance
+ if (nnfw::misc::fp32::absolute_epsilon_equal(lhs, rhs))
+ {
+ return true;
+ }
+
+ return nnfw::misc::fp32::epsilon_equal(lhs, rhs);
+ };
+
+ const uint32_t output_count = output_names.size();
+
+ bool matched = true;
+
+ for (uint32_t n = 0; n < output_count; ++n)
+ {
+ const TfLiteTensor *tensor = lite_interp->tensor(lite_interp->outputs().at(n));
+
+ // TODO Compare shape
+
+ const auto element_count = count_elements(tensor);
+
+ std::cout << "Compare output #" << n << "(" << tensor->name << ", " << element_count
+ << " elements)" << std::endl;
+ for (uint32_t index = 0; index < element_count; ++index)
+ {
+ const auto full_value = output_nodes.at(n).flat<float>().data()[index];
+ const auto lite_value = lite_sess->interp()->typed_output_tensor<float>(n)[index];
+
+ if (!equals(full_value, lite_value))
+ {
+ std::cerr << full_value << " is expected, but " << lite_value << " is obtaeind (at " << n
+ << ":" << index << ")" << std::endl;
+ matched = false;
+ }
+ }
+ }
+
+ //
+ // Cleanup
+ //
+ lite_sess->teardown();
+
+ return matched ? 0 : 255;
+}
diff --git a/runtime/contrib/uben/CMakeLists.txt b/runtime/contrib/uben/CMakeLists.txt
new file mode 100644
index 000000000..9d21610d9
--- /dev/null
+++ b/runtime/contrib/uben/CMakeLists.txt
@@ -0,0 +1,29 @@
+if(NOT BUILD_UBEN)
+ return()
+endif(NOT BUILD_UBEN)
+
+nnfw_find_package(ARMCompute QUIET)
+nnas_find_package(Nonius QUIET)
+
+if(NOT ARMCompute_FOUND)
+ return()
+endif(NOT ARMCompute_FOUND)
+
+if(NOT Nonius_FOUND)
+ return()
+endif(NOT Nonius_FOUND)
+
+# 3x3 Convolution with unit stride
+add_executable(uben_conv_3x3 Convolution.cpp)
+target_compile_definitions(uben_conv_3x3 PRIVATE KER_H=3 KER_W=3 STRIDE_H=1 STRIDE_W=1)
+target_compile_definitions(uben_conv_3x3 PRIVATE CL_DIRECT_CONVOLUTION=1)
+target_compile_definitions(uben_conv_3x3 PRIVATE CL_GEMM_CONVOLUTION=1)
+target_compile_definitions(uben_conv_3x3 PRIVATE CL_WINOGRAD_CONVOLUTION=1)
+target_link_libraries(uben_conv_3x3 PRIVATE nonius)
+target_link_libraries(uben_conv_3x3 PRIVATE arm_compute)
+target_link_libraries(uben_conv_3x3 PRIVATE pthread)
+
+add_executable(uben_softmax Softmax.cpp)
+target_link_libraries(uben_softmax PRIVATE nonius)
+target_link_libraries(uben_softmax PRIVATE nnfw_lib_cker)
+target_link_libraries(uben_softmax PRIVATE pthread)
diff --git a/runtime/contrib/uben/Convolution.cpp b/runtime/contrib/uben/Convolution.cpp
new file mode 100644
index 000000000..ad69f1cec
--- /dev/null
+++ b/runtime/contrib/uben/Convolution.cpp
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Conv2D (with SAME padding) benchmark with various algorithms
+ */
+
+#ifndef KER_H
+#error "KER_H is undefined"
+#endif // KER_H
+#ifndef KER_W
+#error "KER_W is undefined"
+#endif // KER_W
+#ifndef STRIDE_H
+#error "STRIDE_H is undefined"
+#endif // STRIDE_H
+#ifndef STRIDE_W
+#error "STRIDE_W is undefined"
+#endif // STRIDE_W
+
+#define NONIUS_RUNNER
+#include <nonius/nonius_single.h++>
+
+#include <arm_compute/core/Types.h>
+#include <arm_compute/runtime/CL/CLScheduler.h>
+#include <arm_compute/runtime/CL/CLFunctions.h>
+
+#include <cstdint>
+#include <cassert>
+#include <stdexcept>
+
+using namespace arm_compute;
+
+//
+// Helpers
+//
+namespace
+{
+
+enum Layout
+{
+ NCHW,
+ NHWC
+};
+
+struct Initializer
+{
+ Initializer() { CLScheduler::get().default_init(); }
+};
+
+Initializer initializer;
+
+TensorInfo make_info(uint32_t N)
+{
+ TensorShape shape{N};
+ return TensorInfo{shape, 1, DataType::F32};
+}
+
+template <enum Layout> TensorInfo make_info(uint32_t N, uint32_t C, uint32_t H, uint32_t W);
+
+template <> TensorInfo make_info<NCHW>(uint32_t N, uint32_t C, uint32_t H, uint32_t W)
+{
+ TensorShape shape{W, H, C, N};
+ TensorInfo info{shape, 1, DataType::F32};
+ info.set_data_layout(DataLayout::NCHW);
+ return info;
+}
+
+template <> TensorInfo make_info<NHWC>(uint32_t N, uint32_t C, uint32_t H, uint32_t W)
+{
+ TensorShape shape{C, W, H, N};
+ TensorInfo info{shape, 1, DataType::F32};
+ info.set_data_layout(DataLayout::NHWC);
+ return info;
+}
+
+inline void check(const Status &status)
+{
+ if (!status)
+ {
+ std::cerr << status.error_description() << std::endl;
+ throw std::runtime_error{"ERROR"};
+ }
+}
+
+inline bool is_odd(uint32_t n) { return (n % 2 != 0) ? true : false; }
+
+} // namespace
+
+//
+// Benchmark Parameters
+//
+NONIUS_PARAM(BATCH, 1);
+
+NONIUS_PARAM(IFM_C, 3);
+NONIUS_PARAM(IFM_H, 244);
+NONIUS_PARAM(IFM_W, 244);
+
+NONIUS_PARAM(OFM_C, 3);
+NONIUS_PARAM(OFM_H, 244);
+NONIUS_PARAM(OFM_W, 244);
+
+//
+// Configuration Helpers
+//
+namespace
+{
+
+struct Configuration
+{
+ uint32_t ifm_N;
+ uint32_t ifm_C;
+ uint32_t ifm_H;
+ uint32_t ifm_W;
+
+ uint32_t ofm_N;
+ uint32_t ofm_C;
+ uint32_t ofm_H;
+ uint32_t ofm_W;
+
+ uint32_t ker_N;
+ uint32_t ker_C;
+ uint32_t ker_H;
+ uint32_t ker_W;
+
+ uint32_t vertical_stride;
+ uint32_t horizontal_stride;
+
+ uint32_t top_padding;
+ uint32_t bottom_padding;
+ uint32_t left_padding;
+ uint32_t right_padding;
+
+ Configuration(nonius::chronometer meter)
+ {
+ ifm_N = meter.param<BATCH>();
+ ifm_C = meter.param<IFM_C>();
+ ifm_H = meter.param<IFM_H>();
+ ifm_W = meter.param<IFM_W>();
+
+ ofm_N = meter.param<BATCH>();
+ ofm_C = meter.param<OFM_C>();
+ ofm_H = meter.param<OFM_H>();
+ ofm_W = meter.param<OFM_W>();
+
+ ker_N = meter.param<OFM_C>();
+ ker_C = meter.param<IFM_C>();
+ ker_H = KER_H;
+ ker_W = KER_W;
+
+ vertical_stride = STRIDE_H;
+ horizontal_stride = STRIDE_W;
+
+ assert((ifm_H - ker_H) % vertical_stride == 0);
+ assert((ifm_W - ker_H) % horizontal_stride == 0);
+
+ uint32_t const effective_ofm_H = (ifm_H - ker_H) / vertical_stride + 1;
+ uint32_t const effective_ofm_W = (ifm_W - ker_H) / horizontal_stride + 1;
+
+ assert(ofm_H >= effective_ofm_H);
+ assert(ofm_W >= effective_ofm_W);
+
+ uint32_t const pad_H = ofm_H - effective_ofm_H;
+ uint32_t const pad_W = ofm_W - effective_ofm_W;
+
+ top_padding = pad_H / 2;
+ bottom_padding = pad_H / 2;
+ left_padding = pad_W / 2;
+ right_padding = pad_W / 2;
+
+ if (is_odd(pad_H))
+ top_padding += 1;
+ if (is_odd(pad_W))
+ left_padding += 1;
+ }
+
+ template <Layout L> TensorInfo src_info() const
+ {
+ return make_info<L>(ifm_N, ifm_C, ifm_H, ifm_W);
+ }
+ template <Layout L> TensorInfo dst_info() const
+ {
+ return make_info<L>(ofm_N, ofm_C, ofm_H, ofm_W);
+ }
+ template <Layout L> TensorInfo ker_info() const
+ {
+ return make_info<L>(ker_N, ker_C, ker_H, ker_W);
+ }
+ TensorInfo bias_info(void) const { return make_info(ker_N); }
+
+ PadStrideInfo pad_stride_info(void) const
+ {
+ return PadStrideInfo{horizontal_stride,
+ vertical_stride,
+ left_padding,
+ right_padding,
+ top_padding,
+ bottom_padding,
+ DimensionRoundingType::FLOOR};
+ }
+};
+
+} // namespace
+
+//
+// Benchmakr Implementations
+//
+#ifndef CL_DIRECT_CONVOLUTION
+#error "CL_DIRECT_CONVOLUTION is undefined"
+#endif // CL_DIRECT_CONVOLUTION
+
+#if CL_DIRECT_CONVOLUTION
+NONIUS_BENCHMARK("CLDirectConvolutionLayer(NCHW)", [](nonius::chronometer meter) {
+ CLDirectConvolutionLayer conv;
+
+ // Configure
+ Configuration p{meter};
+
+ CLTensor src_tensor{};
+ CLTensor dst_tensor{};
+ CLTensor ker_tensor{};
+ CLTensor bias_tensor{};
+
+ src_tensor.allocator()->init(p.src_info<NCHW>());
+ dst_tensor.allocator()->init(p.dst_info<NCHW>());
+ ker_tensor.allocator()->init(p.ker_info<NCHW>());
+ bias_tensor.allocator()->init(p.bias_info());
+
+ check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
+ p.pad_stride_info()));
+ conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
+
+ src_tensor.allocator()->allocate();
+ ker_tensor.allocator()->allocate();
+ bias_tensor.allocator()->allocate();
+ dst_tensor.allocator()->allocate();
+
+ // Run!
+ meter.measure([&](int) {
+ conv.run();
+ CLScheduler::get().sync();
+ });
+})
+
+NONIUS_BENCHMARK("CLDirectConvolutionLayer(NHWC)", [](nonius::chronometer meter) {
+ CLDirectConvolutionLayer conv;
+
+ // Configure
+ Configuration p{meter};
+
+ CLTensor src_tensor{};
+ CLTensor dst_tensor{};
+ CLTensor ker_tensor{};
+ CLTensor bias_tensor{};
+
+ src_tensor.allocator()->init(p.src_info<NHWC>());
+ dst_tensor.allocator()->init(p.dst_info<NHWC>());
+ ker_tensor.allocator()->init(p.ker_info<NHWC>());
+ bias_tensor.allocator()->init(p.bias_info());
+
+ check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
+ p.pad_stride_info()));
+ conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
+
+ src_tensor.allocator()->allocate();
+ ker_tensor.allocator()->allocate();
+ bias_tensor.allocator()->allocate();
+ dst_tensor.allocator()->allocate();
+
+ // Run!
+ meter.measure([&](int) {
+ conv.run();
+ CLScheduler::get().sync();
+ });
+})
+#endif // CL_DIRECT_CONVOLUTION
+
+#ifndef CL_GEMM_CONVOLUTION
+#error "CL_GEMM_CONVOLUTION is undefined"
+#endif // CL_GEMM_CONVOLUTION
+
+#if CL_GEMM_CONVOLUTION
+NONIUS_BENCHMARK("CLGEMMConvolutionLayer(NCHW)", [](nonius::chronometer meter) {
+ CLGEMMConvolutionLayer conv;
+
+ // Configure
+ Configuration p{meter};
+
+ CLTensor src_tensor{};
+ CLTensor dst_tensor{};
+ CLTensor ker_tensor{};
+ CLTensor bias_tensor{};
+
+ src_tensor.allocator()->init(p.src_info<NCHW>());
+ dst_tensor.allocator()->init(p.dst_info<NCHW>());
+ ker_tensor.allocator()->init(p.ker_info<NCHW>());
+ bias_tensor.allocator()->init(p.bias_info());
+
+ check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
+ p.pad_stride_info()));
+ conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
+
+ src_tensor.allocator()->allocate();
+ ker_tensor.allocator()->allocate();
+ bias_tensor.allocator()->allocate();
+ dst_tensor.allocator()->allocate();
+
+ // Run
+ meter.measure([&](int) {
+ conv.run();
+ CLScheduler::get().sync();
+ });
+})
+
+NONIUS_BENCHMARK("CLGEMMConvolutionLayer(NHWC)", [](nonius::chronometer meter) {
+ CLGEMMConvolutionLayer conv;
+
+ // Configure
+ Configuration p{meter};
+
+ CLTensor src_tensor{};
+ CLTensor dst_tensor{};
+ CLTensor ker_tensor{};
+ CLTensor bias_tensor{};
+
+ src_tensor.allocator()->init(p.src_info<NHWC>());
+ dst_tensor.allocator()->init(p.dst_info<NHWC>());
+ ker_tensor.allocator()->init(p.ker_info<NHWC>());
+ bias_tensor.allocator()->init(p.bias_info());
+
+ check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
+ p.pad_stride_info()));
+ conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
+
+ src_tensor.allocator()->allocate();
+ ker_tensor.allocator()->allocate();
+ bias_tensor.allocator()->allocate();
+ dst_tensor.allocator()->allocate();
+
+ // Run
+ meter.measure([&](int) {
+ conv.run();
+ CLScheduler::get().sync();
+ });
+})
+#endif // CL_GEMM_CONVOLUTION
+
+#ifndef CL_WINOGRAD_CONVOLUTION
+#error "CL_WINOGRAD_CONVOLUTION is undefined"
+#endif // CL_WINOGRAD_CONVOLUTION
+
+#if CL_WINOGRAD_CONVOLUTION
+NONIUS_BENCHMARK("CLWinogradConvolutionLayer(NCHW)", [](nonius::chronometer meter) {
+ CLWinogradConvolutionLayer conv;
+
+ // Configure
+ Configuration p{meter};
+
+ CLTensor src_tensor{};
+ CLTensor dst_tensor{};
+ CLTensor ker_tensor{};
+ CLTensor bias_tensor{};
+
+ src_tensor.allocator()->init(p.src_info<NCHW>());
+ dst_tensor.allocator()->init(p.dst_info<NCHW>());
+ ker_tensor.allocator()->init(p.ker_info<NCHW>());
+ bias_tensor.allocator()->init(p.bias_info());
+
+ check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
+ p.pad_stride_info()));
+ conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
+
+ src_tensor.allocator()->allocate();
+ ker_tensor.allocator()->allocate();
+ bias_tensor.allocator()->allocate();
+ dst_tensor.allocator()->allocate();
+
+ // Run
+ meter.measure([&](int) {
+ conv.run();
+ CLScheduler::get().sync();
+ });
+})
+
+NONIUS_BENCHMARK("CLWinogradConvolutionLayer(NHWC)", [](nonius::chronometer meter) {
+ CLWinogradConvolutionLayer conv;
+
+ // Configure
+ Configuration p{meter};
+
+ CLTensor src_tensor{};
+ CLTensor dst_tensor{};
+ CLTensor ker_tensor{};
+ CLTensor bias_tensor{};
+
+ src_tensor.allocator()->init(p.src_info<NHWC>());
+ dst_tensor.allocator()->init(p.dst_info<NHWC>());
+ ker_tensor.allocator()->init(p.ker_info<NHWC>());
+ bias_tensor.allocator()->init(p.bias_info());
+
+ check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
+ p.pad_stride_info()));
+ conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
+
+ src_tensor.allocator()->allocate();
+ ker_tensor.allocator()->allocate();
+ bias_tensor.allocator()->allocate();
+ dst_tensor.allocator()->allocate();
+
+ // Run
+ meter.measure([&](int) {
+ conv.run();
+ CLScheduler::get().sync();
+ });
+})
+#endif // CL_WINOGRAD_CONVOLUTION
diff --git a/runtime/contrib/uben/Softmax.cpp b/runtime/contrib/uben/Softmax.cpp
new file mode 100644
index 000000000..1c4a6b197
--- /dev/null
+++ b/runtime/contrib/uben/Softmax.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Softmax benchmark
+ */
+
+#define NONIUS_RUNNER
+#include <nonius/nonius_single.h++>
+
+#include <cker/operation/SoftMax.h>
+
+#include <vector>
+
+//
+// Parameters
+//
+NONIUS_PARAM(LEN, 1000);
+
+//
+// Implementations
+//
+NONIUS_BENCHMARK("cker::Softmax(float)", [](nonius::chronometer meter) {
+ auto len = meter.param<LEN>();
+
+ nnfw::cker::SoftmaxParams params;
+ nnfw::cker::Shape shape{1, len};
+
+ params.beta = 1.0;
+
+ std::vector<float> input;
+ std::vector<float> output;
+
+ input.resize(len);
+ output.resize(len);
+
+ meter.measure([&](int) {
+ // Run!
+ nnfw::cker::Softmax(params, shape, input.data(), shape, output.data());
+ });
+})
diff --git a/runtime/libs/CMakeLists.txt b/runtime/libs/CMakeLists.txt
new file mode 100644
index 000000000..99d2028f4
--- /dev/null
+++ b/runtime/libs/CMakeLists.txt
@@ -0,0 +1,4 @@
+# Add all subdirectories.
+# Each library in sub-directory must have it's own CMakeLists.txt
+# to build library's binaries or to support interface.
+add_subdirectories()
diff --git a/runtime/libs/benchmark/CMakeLists.txt b/runtime/libs/benchmark/CMakeLists.txt
new file mode 100644
index 000000000..748b2d13f
--- /dev/null
+++ b/runtime/libs/benchmark/CMakeLists.txt
@@ -0,0 +1,5 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(nnfw_lib_benchmark STATIC ${SOURCES})
+target_include_directories(nnfw_lib_benchmark PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(nnfw_lib_benchmark PRIVATE ${LIB_PTHREAD})
diff --git a/runtime/libs/benchmark/include/benchmark.h b/runtime/libs/benchmark/include/benchmark.h
new file mode 100644
index 000000000..68feabb01
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_BENCHMARK_H__
+#define __NNFW_BENCHMARK_H__
+
+#include "benchmark/Phases.h"
+#include "benchmark/Result.h"
+
+#endif // __NNFW_BENCHMARK_H__
diff --git a/runtime/libs/benchmark/include/benchmark/CsvHeader.lst b/runtime/libs/benchmark/include/benchmark/CsvHeader.lst
new file mode 100644
index 000000000..a94fa14d3
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark/CsvHeader.lst
@@ -0,0 +1,19 @@
+"Model",
+"Backend",
+"ModelLoad_Time",
+"Prepare_Time",
+"Execute_Time_Min",
+"Execute_Time_Max",
+"Execute_Time_Mean",
+"ModelLoad_RSS",
+"Prepare_RSS",
+"Execute_RSS",
+"Peak_RSS",
+"ModelLoad_HWM",
+"Prepare_HWM",
+"Execute_HWM",
+"Peak_HWM",
+"ModelLoad_PSS",
+"Prepare_PSS",
+"Execute_PSS",
+"Peak_PSS",
diff --git a/runtime/libs/benchmark/include/benchmark/CsvWriter.h b/runtime/libs/benchmark/include/benchmark/CsvWriter.h
new file mode 100644
index 000000000..5c259d7ed
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark/CsvWriter.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_BENCHMARK_CSV_WRITER_H__
+#define __NNFW_BENCHMARK_CSV_WRITER_H__
+
+#include <vector>
+#include <string>
+#include <fstream>
+
+namespace benchmark
+{
+
+class CsvWriter
+{
+public:
+ CsvWriter(const std::string &csv_filename);
+ CsvWriter(const std::string &csv_filename, const std::vector<std::string> &header);
+ virtual ~CsvWriter();
+
+ void write(const std::string &val);
+ void write(double val);
+ void write(uint32_t val);
+ void write(char val);
+ bool done();
+
+public:
+ static const char delimiter = ',';
+ static const char newline = '\n';
+
+ friend CsvWriter &operator<<(CsvWriter &csvw, const std::string &val);
+ friend CsvWriter &operator<<(CsvWriter &csvw, double val);
+ friend CsvWriter &operator<<(CsvWriter &csvw, uint32_t val);
+ friend CsvWriter &operator<<(CsvWriter &csvw, char val);
+
+private:
+ void writeHeader(const std::vector<std::string> &header);
+ inline void postWrite();
+
+private:
+ std::ofstream _ofs;
+ uint32_t _header_size;
+ uint32_t _col_idx;
+ uint32_t _row_idx;
+};
+
+} // namespace benchmark
+
+#endif // __NNFW_BENCHMARK_CSV_WRITER_H__
diff --git a/runtime/libs/benchmark/include/benchmark/MemoryInfo.h b/runtime/libs/benchmark/include/benchmark/MemoryInfo.h
new file mode 100644
index 000000000..6e8e12ba4
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark/MemoryInfo.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_BENCHMARK_MEMORY_INFO_H__
+#define __NNFW_BENCHMARK_MEMORY_INFO_H__
+
+#include <cstdint>
+#include <string>
+
+namespace benchmark
+{
+
+bool prepareVmRSS();
+bool prepareVmHWM();
+bool prepareGpuMemory();
+bool preparePssSum();
+
+uint32_t getVmRSS();
+uint32_t getVmHWM();
+uint32_t getGpuMemory(const std::string &process_name);
+uint32_t getPssSum();
+
+std::string getProcessName();
+
+} // namespace benchmark
+
+#endif // __NNFW_BENCHMARK_MEMORY_INFO_H__
diff --git a/runtime/libs/benchmark/include/benchmark/MemoryPoller.h b/runtime/libs/benchmark/include/benchmark/MemoryPoller.h
new file mode 100644
index 000000000..47db3fd77
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark/MemoryPoller.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_BENCHMARK_MEMORY_POLLER_H__
+#define __NNFW_BENCHMARK_MEMORY_POLLER_H__
+
+#include <cstdint>
+#include <algorithm>
+#include <unordered_map>
+#include <string>
+#include <chrono>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <list>
+
+#include "Types.h"
+
+namespace benchmark
+{
+
+// NOTE. gpu_poll is not necessary on general targets. This is used on the only tv targets.
+// TODO finally should be separated from data
+// TODO Use ctor() and dtor() instead of start() and end()
+class MemoryPoller
+{
+public:
+ MemoryPoller(std::chrono::milliseconds duration = std::chrono::milliseconds(5),
+ bool gpu_poll = false);
+
+ virtual ~MemoryPoller()
+ {
+ _term = true;
+ _cond_var_started.notify_all();
+ _thread.join();
+ }
+
+ bool start(PhaseEnum phase);
+ bool end(PhaseEnum phase);
+ const std::unordered_map<PhaseEnum, uint32_t> &getRssMap() const { return _rss_map; }
+ const std::unordered_map<PhaseEnum, uint32_t> &getHwmMap() const { return _hwm_map; }
+ const std::unordered_map<PhaseEnum, uint32_t> &getPssMap() const { return _pss_map; }
+
+private:
+ void process();
+ bool prepareMemoryPolling();
+
+private:
+ std::chrono::milliseconds _duration;
+ std::thread _thread;
+ std::list<PhaseEnum> _phases;
+ std::unordered_map<PhaseEnum, uint32_t> _rss_map;
+ std::unordered_map<PhaseEnum, uint32_t> _hwm_map;
+ std::unordered_map<PhaseEnum, uint32_t> _pss_map;
+
+ std::mutex _mutex;
+ std::mutex _mutex_started;
+ std::condition_variable _cond_var_started;
+
+ bool _term;
+ bool _run;
+ bool _gpu_poll;
+ std::string _process_name;
+};
+
+} // namespace benchmark
+
+#endif // __NNFW_BENCHMARK_MEMORY_POLLER_H__
diff --git a/runtime/libs/benchmark/include/benchmark/Phase.h b/runtime/libs/benchmark/include/benchmark/Phase.h
new file mode 100644
index 000000000..5eceb04c5
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark/Phase.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_BENCHMARK_PHASE_H__
+#define __NNFW_BENCHMARK_PHASE_H__
+
+#include "Types.h"
+
+#include <string>
+#include <vector>
+
+namespace benchmark
+{
+
+struct Phase
+{
+ Phase(const std::string &t, uint32_t c) : tag(t), count(c) { time.reserve(count); }
+
+ const std::string tag;
+ uint32_t count;
+ std::vector<uint64_t> time; // us
+ std::vector<uint32_t> memory[MemoryType::END_OF_MEM_TYPE]; // kB
+};
+
+struct PhaseOption
+{
+ bool memory = false;
+ bool memory_gpu = false; // very specific...
+ int run_delay = -1; // ms
+ int memory_interval = 5; // ms
+};
+
+} // namespace benchmark
+
+namespace std
+{
+
+template <> struct hash<benchmark::PhaseEnum>
+{
+ size_t operator()(benchmark::PhaseEnum value) const noexcept
+ {
+ using type = typename std::underlying_type<benchmark::PhaseEnum>::type;
+ return hash<type>()(static_cast<type>(value));
+ }
+};
+
+} // namespace std
+
+#endif // __NNFW_BENCHMARK_PHASE_H__
diff --git a/runtime/libs/benchmark/include/benchmark/Phases.h b/runtime/libs/benchmark/include/benchmark/Phases.h
new file mode 100644
index 000000000..7d642782a
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark/Phases.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_BENCHMARK_PHASES_H__
+#define __NNFW_BENCHMARK_PHASES_H__
+
+#include "Phase.h"
+#include "MemoryPoller.h"
+
+#include <string>
+#include <functional>
+#include <unordered_map>
+
+namespace benchmark
+{
+
+class Phases
+{
+public:
+ Phases(const PhaseOption &option);
+
+ using PhaseFunc = std::function<void(const Phase &, uint32_t)>;
+
+ void run(const std::string &tag, const PhaseFunc &exec, uint32_t loop_num = 1,
+ bool option_disable = false)
+ {
+ run(tag, exec, nullptr, loop_num, option_disable);
+ }
+
+ void run(const std::string &tag, const PhaseFunc &exec, const PhaseFunc &post,
+ uint32_t loop_num = 1, bool option_disable = false)
+ {
+ run(tag, exec, &post, loop_num, option_disable);
+ }
+
+ const PhaseOption &option() const { return _option; }
+ const MemoryPoller &mem_poll() const { return *_mem_poll; }
+ const Phase &at(const std::string &tag) const { return _phases.at(tag); }
+
+ uint32_t mem_before_init() const { return _mem_before_init; }
+ uint32_t mem_after_run() const { return _mem_after_run; }
+
+private:
+ void run(const std::string &tag, const PhaseFunc &exec, const PhaseFunc *post, uint32_t loop_num,
+ bool option_disable);
+
+private:
+ const PhaseOption _option;
+ std::unordered_map<std::string, Phase> _phases;
+ std::unique_ptr<MemoryPoller> _mem_poll;
+ uint32_t _mem_before_init;
+ uint32_t _mem_after_run;
+};
+
+} // namespace benchmark
+
+#endif // __NNFW_BENCHMARK_PHASES_H__
diff --git a/runtime/libs/benchmark/include/benchmark/Result.h b/runtime/libs/benchmark/include/benchmark/Result.h
new file mode 100644
index 000000000..7604aa904
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark/Result.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_BENCHMARK_RESULT_H__
+#define __NNFW_BENCHMARK_RESULT_H__
+
+#include "Types.h"
+#include "Phases.h"
+
+#include <string>
+
+namespace benchmark
+{
+
+// Data class between runner(nnpackage_run and tflite_run) and libbenchmark
+class Result
+{
+public:
+ Result(const Phases &phases);
+
+ double time[PhaseEnum::END_OF_PHASE][FigureType::END_OF_FIG_TYPE];
+ uint32_t memory[PhaseEnum::END_OF_PHASE][MemoryType::END_OF_MEM_TYPE];
+ bool print_memory = false;
+ uint32_t init_memory = 0;
+ uint32_t peak_memory = 0;
+};
+
+// TODO Support not only stdout but also ostream
+void printResult(const Result &result);
+
+// TODO Support not only csv but also other datafile format such as xml, json, ...
+void writeResult(const Result &result, const std::string &exec, const std::string &model,
+ const std::string &backend);
+
+} // namespace benchmark
+
+#endif // __NNFW_BENCHMARK_RESULT_H__
diff --git a/runtime/libs/benchmark/include/benchmark/Types.h b/runtime/libs/benchmark/include/benchmark/Types.h
new file mode 100644
index 000000000..76479d1b8
--- /dev/null
+++ b/runtime/libs/benchmark/include/benchmark/Types.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <vector>
+
+#ifndef __NNFW_BENCHMARK_TYPES_H__
+#define __NNFW_BENCHMARK_TYPES_H__
+
+namespace benchmark
+{
+
+enum MemoryType
+{
+ RSS,
+ HWM,
+ PSS,
+ END_OF_MEM_TYPE
+};
+
+inline std::string getMemoryTypeString(MemoryType type)
+{
+ switch (type)
+ {
+ case MemoryType::RSS:
+ return "RSS";
+ case MemoryType::HWM:
+ return "HWM";
+ case MemoryType::PSS:
+ return "PSS";
+ default:
+ return "END_OF_MEM_TYPE";
+ }
+}
+
+inline std::string getMemoryTypeString(int type)
+{
+ return getMemoryTypeString(static_cast<MemoryType>(type));
+}
+
+enum PhaseEnum
+{
+ MODEL_LOAD,
+ PREPARE,
+ WARMUP,
+ EXECUTE,
+ END_OF_PHASE,
+};
+
+inline std::string getPhaseString(PhaseEnum phase)
+{
+ switch (phase)
+ {
+ case PhaseEnum::MODEL_LOAD:
+ return "MODEL_LOAD";
+ case PhaseEnum::PREPARE:
+ return "PREPARE";
+ case PhaseEnum::WARMUP:
+ return "WARMUP";
+ case PhaseEnum::EXECUTE:
+ return "EXECUTE";
+ default:
+ return "END_OF_PHASE";
+ }
+}
+
+inline std::string getPhaseString(int phase)
+{
+ return getPhaseString(static_cast<PhaseEnum>(phase));
+}
+
+inline PhaseEnum getPhaseEnum(const std::string &phase)
+{
+ if (phase.compare("MODEL_LOAD") == 0)
+ return PhaseEnum::MODEL_LOAD;
+ if (phase.compare("PREPARE") == 0)
+ return PhaseEnum::PREPARE;
+ if (phase.compare("WARMUP") == 0)
+ return PhaseEnum::WARMUP;
+ if (phase.compare("EXECUTE") == 0)
+ return PhaseEnum::EXECUTE;
+ return PhaseEnum::END_OF_PHASE;
+}
+
+const std::vector<std::string> gPhaseStrings{"MODEL_LOAD", "PREPARE", "WARMUP", "EXECUTE"};
+
+enum FigureType
+{
+ MEAN,
+ MAX,
+ MIN,
+ GEOMEAN,
+ END_OF_FIG_TYPE
+};
+
+inline std::string getFigureTypeString(FigureType type)
+{
+ switch (type)
+ {
+ case MEAN:
+ return "MEAN";
+ case MAX:
+ return "MAX";
+ case MIN:
+ return "MIN";
+ case GEOMEAN:
+ return "GEOMEAN";
+ default:
+ return "END_OF_FIG_TYPE";
+ }
+}
+
+inline std::string getFigureTypeString(int type)
+{
+ return getFigureTypeString(static_cast<FigureType>(type));
+}
+
+} // namespace benchmark
+
+#endif // __NNFW_BENCHMARK_TYPES_H__
diff --git a/runtime/libs/benchmark/src/CsvWriter.cpp b/runtime/libs/benchmark/src/CsvWriter.cpp
new file mode 100644
index 000000000..5f47c6511
--- /dev/null
+++ b/runtime/libs/benchmark/src/CsvWriter.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "benchmark/CsvWriter.h"
+#include <cassert>
+
+namespace
+{
+
+const std::vector<std::string> csv_header{
+#include "benchmark/CsvHeader.lst"
+};
+
+} // namespace
+
+namespace benchmark
+{
+
+CsvWriter::CsvWriter(const std::string &csv_filename) : CsvWriter(csv_filename, csv_header)
+{
+ // DO NOTHING
+}
+
+CsvWriter::CsvWriter(const std::string &csv_filename, const std::vector<std::string> &header)
+ : _ofs(csv_filename), _header_size(header.size()), _col_idx(0), _row_idx(0)
+{
+ assert(csv_filename.empty() == false);
+ assert(header.size() != 0);
+ assert(_ofs.is_open());
+
+ writeHeader(header);
+}
+
+CsvWriter::~CsvWriter()
+{
+ if (_ofs.is_open())
+ _ofs.close();
+}
+
+void CsvWriter::writeHeader(const std::vector<std::string> &header)
+{
+ for (const auto &col : header)
+ write(col);
+}
+
+void CsvWriter::postWrite()
+{
+ if (++_col_idx == _header_size)
+ {
+ _ofs << newline;
+ _row_idx += 1;
+ _col_idx = 0;
+ }
+ else
+ {
+ _ofs << delimiter;
+ }
+}
+
+void CsvWriter::write(const std::string &val)
+{
+ _ofs << val;
+ postWrite();
+}
+
+void CsvWriter::write(double val)
+{
+ _ofs << val;
+ postWrite();
+}
+
+void CsvWriter::write(uint32_t val)
+{
+ _ofs << val;
+ postWrite();
+}
+
+void CsvWriter::write(char val)
+{
+ _ofs << val;
+ postWrite();
+}
+
+bool CsvWriter::done() { return (_col_idx == 0) && (_row_idx == 2); }
+
+CsvWriter &operator<<(CsvWriter &csvw, const std::string &val)
+{
+ csvw.write(val);
+ return csvw;
+}
+
+CsvWriter &operator<<(CsvWriter &csvw, double val)
+{
+ csvw.write(val);
+ return csvw;
+}
+
+CsvWriter &operator<<(CsvWriter &csvw, uint32_t val)
+{
+ csvw.write(val);
+ return csvw;
+}
+
+CsvWriter &operator<<(CsvWriter &csvw, char val)
+{
+ csvw.write(val);
+ return csvw;
+}
+
+} // namespace benchmark
diff --git a/runtime/libs/benchmark/src/MemoryInfo.cpp b/runtime/libs/benchmark/src/MemoryInfo.cpp
new file mode 100644
index 000000000..20d262961
--- /dev/null
+++ b/runtime/libs/benchmark/src/MemoryInfo.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "benchmark/MemoryInfo.h"
+
+#include <vector>
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <cassert>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+namespace
+{
+
+const std::string proc_status_path("/proc/self/status");
+const std::string gpu_memory_path("/sys/kernel/debug/mali0/gpu_memory");
+const std::string proc_smaps_path("/proc/self/smaps");
+
+bool isStrNumber(const std::string &s)
+{
+ return !s.empty() &&
+ std::find_if(s.begin(), s.end(), [](char c) { return !std::isdigit(c); }) == s.end();
+}
+
+std::vector<std::string> splitLine(std::string line, std::string delimiters = " \n\t")
+{
+ std::vector<std::string> words;
+ size_t prev = 0, pos;
+
+ while ((pos = line.find_first_of(delimiters, prev)) != std::string::npos)
+ {
+ if (pos > prev)
+ words.emplace_back(line.substr(prev, pos - prev));
+ prev = pos + 1;
+ }
+
+ if (prev < line.length())
+ words.emplace_back(line.substr(prev, std::string::npos));
+
+ return words;
+}
+
+std::vector<std::string> getValueFromFileStatus(const std::string &file, const std::string &key)
+{
+ std::ifstream ifs(file);
+ assert(ifs.is_open());
+
+ std::string line;
+ std::vector<std::string> val;
+
+ bool found = false;
+ while (std::getline(ifs, line))
+ {
+ if (line.find(key) != std::string::npos)
+ {
+ found = true;
+ break;
+ }
+ }
+ ifs.close();
+
+ if (!found)
+ {
+ // NOTE. the process which uses gpu resources cannot be there yet at the model-load phase.
+ // At that time, just return empty.
+ return val;
+ }
+
+ val = splitLine(line);
+ return val;
+}
+
+// Because of smaps' structure, returns sum value as uint32_t
+uint32_t getSumValueFromFileSmaps(const std::string &file, const std::string &key)
+{
+ std::ifstream ifs(file);
+ assert(ifs.is_open());
+
+ std::string line;
+ uint32_t sum = 0;
+ while (std::getline(ifs, line))
+ {
+ if (line.find(key) != std::string::npos)
+ {
+ // an example by splitLine()
+ // `Pss: 0 kB`
+ // val[0]: "Pss:", val[1]: "0" val[2]: "kB"
+ auto val = splitLine(line);
+ assert(val.size() != 0);
+ // SwapPss could show so that check where Pss is at the beginning
+ if (val[0].find("Pss") != 0)
+ {
+ continue;
+ }
+ sum += std::stoul(val[1]);
+ }
+ }
+
+ return sum;
+}
+
+} // namespace
+
+namespace benchmark
+{
+
+bool prepareVmRSS() { return std::ifstream(proc_status_path).is_open(); }
+
+bool prepareVmHWM() { return std::ifstream(proc_status_path).is_open(); }
+
+bool prepareGpuMemory() { return std::ifstream(gpu_memory_path).is_open(); }
+
+bool preparePssSum() { return std::ifstream(proc_smaps_path).is_open(); }
+
+uint32_t getVmRSS()
+{
+ auto val = getValueFromFileStatus(proc_status_path, "VmRSS");
+ if (val.size() == 0)
+ return 0;
+ assert(isStrNumber(val[1]));
+ return std::stoul(val[1]);
+}
+
+uint32_t getVmHWM()
+{
+ auto val = getValueFromFileStatus(proc_status_path, "VmHWM");
+ if (val.size() == 0)
+ return 0;
+ // key: value
+ assert(isStrNumber(val[1]));
+ return std::stoul(val[1]);
+}
+
+uint32_t getGpuMemory(const std::string &process_name)
+{
+ assert(!process_name.empty());
+ auto val = getValueFromFileStatus(gpu_memory_path, process_name);
+ if (val.size() == 0)
+ return 0;
+ // process_name -> pid -> gpu_mem -> max_gpu_mem
+ assert(isStrNumber(val[2]));
+ return std::stoul(val[2]);
+}
+
+uint32_t getPssSum() { return getSumValueFromFileSmaps(proc_smaps_path, "Pss"); }
+
+std::string getProcessName()
+{
+ auto val = getValueFromFileStatus(proc_status_path, "Name");
+ assert(val.size() >= 2);
+ return val[1];
+}
+
+} // namespace benchmark
diff --git a/runtime/libs/benchmark/src/MemoryPoller.cpp b/runtime/libs/benchmark/src/MemoryPoller.cpp
new file mode 100644
index 000000000..050b5b163
--- /dev/null
+++ b/runtime/libs/benchmark/src/MemoryPoller.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "benchmark/MemoryPoller.h"
+#include "benchmark/Types.h"
+#include "benchmark/MemoryInfo.h"
+
+#include <vector>
+#include <stdexcept>
+#include <cassert>
+#include <iostream>
+
+namespace benchmark
+{
+
+MemoryPoller::MemoryPoller(std::chrono::milliseconds duration, bool gpu_poll)
+ : _duration(duration), _run(false), _term(false), _gpu_poll(gpu_poll)
+{
+ if (prepareMemoryPolling() == false)
+ throw std::runtime_error("failed to prepare memory pooling");
+
+ _thread = std::thread{&MemoryPoller::process, this};
+}
+
+bool MemoryPoller::start(PhaseEnum phase)
+{
+ if (std::find(_phases.begin(), _phases.end(), phase) != _phases.end())
+ {
+ std::cerr << getPhaseString(phase) << " is already processing/processed..." << std::endl;
+ return false;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _phases.emplace_back(phase);
+ _rss_map[phase] = 0;
+ _hwm_map[phase] = 0;
+ _pss_map[phase] = 0;
+ }
+
+ _run = true;
+ _cond_var_started.notify_all();
+ return true;
+}
+
+bool MemoryPoller::end(PhaseEnum phase)
+{
+ if (std::find(_phases.begin(), _phases.end(), phase) == _phases.end())
+ {
+ std::cerr << getPhaseString(phase) << " is not started..." << std::endl;
+ return false;
+ }
+
+ uint32_t mem = 0;
+ bool stop = false;
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _phases.remove(phase);
+ stop = (_phases.size() == 0);
+ }
+
+ mem = getVmRSS();
+ if (_gpu_poll)
+ {
+ mem += getGpuMemory(_process_name);
+ }
+ if (mem > _rss_map[phase])
+ _rss_map[phase] = mem;
+
+ mem = getVmHWM();
+ if (_gpu_poll)
+ {
+ mem += getGpuMemory(_process_name);
+ }
+ _hwm_map[phase] = mem;
+
+ mem = getPssSum();
+ if (mem > _pss_map[phase])
+ _pss_map[phase] = mem;
+
+ if (stop)
+ {
+ _run = false;
+ _cond_var_started.notify_all();
+ }
+
+ return true;
+}
+
+void MemoryPoller::process()
+{
+ std::unique_lock<std::mutex> lock_started(_mutex_started);
+ while (true)
+ {
+ _cond_var_started.wait(lock_started, [&]() { return _run || _term; });
+ if (_term)
+ break;
+
+ std::unique_lock<std::mutex> lock(_mutex);
+
+ uint32_t cur_rss = getVmRSS();
+ uint32_t cur_hwm = getVmHWM();
+ if (_gpu_poll)
+ {
+ auto gpu_mem = getGpuMemory(_process_name);
+ cur_rss += gpu_mem;
+ cur_hwm += gpu_mem;
+ }
+ uint32_t cur_pss = getPssSum();
+
+ for (auto &phase : _phases)
+ {
+ auto &rss = _rss_map.at(phase);
+ if (rss < cur_rss)
+ rss = cur_rss;
+ // hwm is gradually increasing
+ auto &hwm = _hwm_map.at(phase);
+ hwm = cur_hwm;
+ auto &pss = _pss_map.at(phase);
+ if (pss < cur_pss)
+ pss = cur_pss;
+ }
+
+ lock.unlock();
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(_duration));
+ }
+}
+
+bool MemoryPoller::prepareMemoryPolling()
+{
+ // VmRSS
+ if (!prepareVmRSS())
+ {
+ std::cerr << "failed to prepare parsing vmrss" << std::endl;
+ return false;
+ }
+
+ // (Additionally) GpuMemory
+ if (_gpu_poll)
+ {
+ if (!prepareGpuMemory())
+ {
+ std::cerr << "failed to prepare parsing gpu memory" << std::endl;
+ return false;
+ }
+
+ // Needs process name
+ _process_name = getProcessName();
+ }
+
+ // PSS
+ if (!preparePssSum())
+ {
+ std::cerr << "failed to prepare parsing pss sum" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace benchmark
diff --git a/runtime/libs/benchmark/src/Phases.cpp b/runtime/libs/benchmark/src/Phases.cpp
new file mode 100644
index 000000000..897b943d3
--- /dev/null
+++ b/runtime/libs/benchmark/src/Phases.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "benchmark/Phases.h"
+#include "benchmark/Types.h"
+#include "benchmark/MemoryInfo.h"
+
+#include <cassert>
+#include <chrono>
+#include <iostream>
+#include <sys/time.h>
+
+namespace
+{
+
+uint64_t nowMicros()
+{
+ struct timeval tv;
+ gettimeofday(&tv, nullptr);
+ return static_cast<uint64_t>(tv.tv_sec) * 1e6 + tv.tv_usec;
+}
+
+void SleepForMicros(uint64_t micros)
+{
+ timespec sleep_time;
+ sleep_time.tv_sec = micros / 1e6;
+ micros -= sleep_time.tv_sec * 1e6;
+ sleep_time.tv_nsec = micros * 1e3;
+ nanosleep(&sleep_time, nullptr);
+}
+}
+
+namespace benchmark
+{
+
+Phases::Phases(const PhaseOption &option) : _option(option), _mem_before_init(0), _mem_after_run(0)
+{
+ assert(prepareVmRSS());
+ _mem_before_init = getVmHWM();
+
+ if (_option.memory)
+ {
+ _mem_poll = std::make_unique<MemoryPoller>(std::chrono::milliseconds(option.memory_interval),
+ option.memory_gpu);
+ }
+}
+
+void Phases::run(const std::string &tag, const PhaseFunc &exec, const PhaseFunc *post,
+ uint32_t loop_num, bool option_disable)
+{
+ Phase phase{tag, loop_num};
+ PhaseEnum p = getPhaseEnum(tag);
+ for (uint32_t i = 0; i < loop_num; ++i)
+ {
+ if (!option_disable && _option.memory)
+ _mem_poll->start(p);
+
+ uint64_t t = 0u;
+ t = nowMicros();
+
+ exec(phase, i);
+
+ t = nowMicros() - t;
+
+ if (!option_disable && _option.memory)
+ _mem_poll->end(p);
+
+ phase.time.emplace_back(t);
+
+ if (!option_disable && _option.memory)
+ {
+ phase.memory[MemoryType::RSS].emplace_back(_mem_poll->getRssMap().at(p));
+ phase.memory[MemoryType::HWM].emplace_back(_mem_poll->getHwmMap().at(p));
+ phase.memory[MemoryType::PSS].emplace_back(_mem_poll->getPssMap().at(p));
+ }
+
+ if (post)
+ (*post)(phase, i);
+
+ if (_option.run_delay > 0 && p == PhaseEnum::EXECUTE && i != loop_num - 1)
+ {
+ SleepForMicros(_option.run_delay);
+ }
+ }
+
+ _mem_after_run = getVmHWM();
+
+ if (p == PhaseEnum::END_OF_PHASE)
+ {
+ return;
+ }
+
+ assert(_phases.find(tag) == _phases.end());
+ _phases.emplace(tag, phase);
+}
+
+} // namespace benchmark
diff --git a/runtime/libs/benchmark/src/Result.cpp b/runtime/libs/benchmark/src/Result.cpp
new file mode 100644
index 000000000..e6cafb91c
--- /dev/null
+++ b/runtime/libs/benchmark/src/Result.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "benchmark/Result.h"
+#include "benchmark/Phases.h"
+#include "benchmark/CsvWriter.h"
+
+#include <string>
+#include <numeric>
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include <iomanip>
+
+namespace
+{
+
+template <class T, class R> R average(const std::vector<T> &v)
+{
+ T sum = std::accumulate(v.begin(), v.end(), 0);
+ R avg = sum / static_cast<R>(v.size());
+ return avg;
+}
+
+double averageTimeMs(const benchmark::Phase &phase)
+{
+ double avg_us = average<uint64_t, double>(phase.time);
+ return avg_us / 1e3;
+}
+
+double maxTimeMs(const benchmark::Phase &phase)
+{
+ auto it = max_element(std::begin(phase.time), std::end(phase.time));
+ return *it / 1e3;
+}
+
+double minTimeMs(const benchmark::Phase &phase)
+{
+ auto it = min_element(std::begin(phase.time), std::end(phase.time));
+ return *it / 1e3;
+}
+
+double geomeanTimeMs(const benchmark::Phase &phase)
+{
+ double log_sum = 0.0;
+ for (auto t_us : phase.time)
+ {
+ log_sum += std::log(t_us / 1e3);
+ }
+
+ // Calculating geometric mean with logs
+ // "Geometric Mean of (V1, V2, ... Vn)"
+ // = (V1*V2*...*Vn)^(1/n)
+ // = exp(log((V1*V2*...*Vn)^(1/n)))
+ // = exp(log((V1*V2*...*Vn)/n)))
+ // = exp((log(V1) + log(V2) + ... + log(Vn))/n)
+ // = exp(_log_sum/num)
+ return std::exp(log_sum / static_cast<double>(phase.time.size()));
+}
+
+uint32_t averageMemoryKb(const benchmark::Phase &phase, int type)
+{
+ return average<uint32_t, uint32_t>(phase.memory[type]);
+}
+
+uint32_t peakMemory(const uint32_t memory[benchmark::PhaseEnum::END_OF_PHASE]
+ [benchmark::MemoryType::END_OF_MEM_TYPE],
+ int type)
+{
+ using namespace benchmark;
+ // tricky. handle WARMUP as EXECUTE
+ return std::max({memory[PhaseEnum::MODEL_LOAD][type], memory[PhaseEnum::PREPARE][type],
+ memory[PhaseEnum::WARMUP][type]});
+}
+
+void printResultTime(
+ const double time[benchmark::PhaseEnum::END_OF_PHASE][benchmark::FigureType::END_OF_FIG_TYPE])
+{
+ using namespace benchmark;
+
+ std::cout << "===================================" << std::endl;
+
+ std::streamsize ss_precision = std::cout.precision();
+ std::cout << std::setprecision(3);
+ std::cout << std::fixed;
+
+ for (int i = PhaseEnum::MODEL_LOAD; i <= PhaseEnum::EXECUTE; ++i)
+ {
+ // Note. Tricky. Ignore WARMUP
+ if (i == PhaseEnum::WARMUP)
+ continue;
+ std::cout << std::setw(12) << std::left << getPhaseString(i) << " takes "
+ << time[i][FigureType::MEAN] << " ms" << std::endl;
+ }
+
+ for (int j = FigureType::MEAN; j <= FigureType::GEOMEAN; ++j)
+ {
+ std::cout << "- " << std::setw(9) << std::left << getFigureTypeString(j) << ": "
+ << time[PhaseEnum::EXECUTE][j] << " ms" << std::endl;
+ }
+
+ std::cout << std::setprecision(ss_precision);
+ std::cout << std::defaultfloat;
+
+ std::cout << "===================================" << std::endl;
+}
+
+void printResultMemory(const uint32_t memory[benchmark::PhaseEnum::END_OF_PHASE]
+ [benchmark::MemoryType::END_OF_MEM_TYPE])
+{
+ using namespace benchmark;
+
+ for (int j = MemoryType::RSS; j <= MemoryType::PSS; ++j)
+ {
+ std::cout << getMemoryTypeString(j) << std::endl;
+ for (int i = PhaseEnum::MODEL_LOAD; i <= PhaseEnum::PREPARE; ++i)
+ {
+ std::cout << "- " << std::setw(12) << std::left << getPhaseString(i) << " takes "
+ << memory[i][j] << " kb" << std::endl;
+ }
+ // Tricky. Handle WARMUP as EXECUTE
+ std::cout << "- " << std::setw(12) << std::left << getPhaseString(PhaseEnum::EXECUTE)
+ << " takes " << memory[PhaseEnum::WARMUP][j] << " kb" << std::endl;
+ std::cout << "- " << std::setw(12) << std::left << "PEAK"
+ << " takes " << peakMemory(memory, j) << " kb" << std::endl;
+ std::cout << "===================================" << std::endl;
+ }
+}
+
+void printUsedPeakMemory(uint32_t init_memory, uint32_t peak_memory)
+{
+ uint32_t used_peak_memory = peak_memory - init_memory;
+ std::cout << "Used Peak Memory : " << used_peak_memory << " kb" << std::endl;
+ std::cout << "- HWM after run : " << peak_memory << " kb" << std::endl;
+ std::cout << "- HWM before init: " << init_memory << " kb" << std::endl;
+ std::cout << "===================================" << std::endl;
+}
+
+} // namespace
+
+namespace benchmark
+{
+
+Result::Result(const Phases &phases)
+{
+ const auto option = phases.option();
+ {
+ for (int i = PhaseEnum::MODEL_LOAD; i <= PhaseEnum::PREPARE; ++i)
+ {
+ auto phase = phases.at(gPhaseStrings[i]);
+ time[i][FigureType::MEAN] = averageTimeMs(phase);
+ }
+
+ int i = PhaseEnum::EXECUTE;
+ auto exec_phase = phases.at(gPhaseStrings[i]);
+ time[i][FigureType::MEAN] = averageTimeMs(exec_phase);
+ time[i][FigureType::MAX] = maxTimeMs(exec_phase);
+ time[i][FigureType::MIN] = minTimeMs(exec_phase);
+ time[i][FigureType::GEOMEAN] = geomeanTimeMs(exec_phase);
+ }
+ if (option.memory)
+ {
+ print_memory = true;
+ for (int i = PhaseEnum::MODEL_LOAD; i < PhaseEnum::EXECUTE; ++i)
+ {
+ auto phase = phases.at(gPhaseStrings[i]);
+ for (int j = MemoryType::RSS; j <= MemoryType::PSS; ++j)
+ {
+ memory[i][j] = averageMemoryKb(phase, j);
+ }
+ }
+ }
+ init_memory = phases.mem_before_init();
+ peak_memory = phases.mem_after_run();
+}
+
+void printResult(const Result &result)
+{
+ printResultTime(result.time);
+
+ if (result.print_memory == false)
+ return;
+
+ printResultMemory(result.memory);
+ printUsedPeakMemory(result.init_memory, result.peak_memory);
+}
+
+// TODO There are necessary for a kind of output data file so that it doesn't have to be csv file
+// format.
+void writeResult(const Result &result, const std::string &exec, const std::string &model,
+ const std::string &backend)
+{
+ std::string csv_filename = exec + "-" + model + "-" + backend + ".csv";
+
+ // write to csv
+ CsvWriter writer(csv_filename);
+ writer << model << backend;
+
+ // TODO Add GEOMEAN
+ // time
+ auto time = result.time;
+ writer << time[PhaseEnum::MODEL_LOAD][FigureType::MEAN]
+ << time[PhaseEnum::PREPARE][FigureType::MEAN] << time[PhaseEnum::EXECUTE][FigureType::MIN]
+ << time[PhaseEnum::EXECUTE][FigureType::MAX] << time[PhaseEnum::EXECUTE][FigureType::MEAN];
+
+ // memory
+ auto memory = result.memory;
+ for (int j = MemoryType::RSS; j <= MemoryType::PSS; ++j)
+ {
+ // Tricky. Handle WARMUP as EXECUTE
+ for (int i = PhaseEnum::MODEL_LOAD; i <= PhaseEnum::WARMUP; ++i)
+ {
+ writer << memory[i][j];
+ }
+ writer << peakMemory(memory, j);
+ }
+
+ bool done = writer.done();
+
+ if (!done)
+ {
+ std::cerr << "Writing to " << csv_filename << " is failed" << std::endl;
+ }
+}
+
+} // namespace benchmark
diff --git a/runtime/libs/misc/CMakeLists.txt b/runtime/libs/misc/CMakeLists.txt
new file mode 100644
index 000000000..557d403ec
--- /dev/null
+++ b/runtime/libs/misc/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Library `nnfw_lib_misc`
+file(GLOB_RECURSE NNFW_UTILITY_SRCS "src/*.cpp")
+
+add_library(nnfw_lib_misc STATIC ${NNFW_UTILITY_SRCS})
+target_include_directories(nnfw_lib_misc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+set_target_properties(nnfw_lib_misc PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_link_libraries(nnfw_lib_misc PRIVATE nnfw_common)
+target_link_libraries(nnfw_lib_misc PRIVATE nnfw_coverage)
+
+add_executable(nnfw_tensor_index_iterator "examples/tensor_index_iterator.cpp")
+target_link_libraries(nnfw_tensor_index_iterator nnfw_lib_misc)
diff --git a/runtime/libs/misc/examples/tensor_index_iterator.cpp b/runtime/libs/misc/examples/tensor_index_iterator.cpp
new file mode 100644
index 000000000..590b433df
--- /dev/null
+++ b/runtime/libs/misc/examples/tensor_index_iterator.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "misc/tensor/IndexIterator.h"
+
+#include <array>
+
+#include <iostream>
+#include <algorithm>
+
+#include <cassert>
+
+void test_iterate(void)
+{
+ const nnfw::misc::tensor::Shape shape{3, 4, 7};
+
+ std::array<int, 3 * 4 * 7> array;
+
+ array.fill(0);
+
+ using nnfw::misc::tensor::Index;
+ using nnfw::misc::tensor::iterate;
+
+ iterate(shape) << [&](const Index &index) {
+ assert(index.rank() == shape.rank());
+
+ const uint32_t rank = index.rank();
+
+ uint32_t offset = index.at(0);
+
+ for (uint32_t axis = 1; axis < rank; ++axis)
+ {
+ offset *= shape.dim(axis);
+ offset += index.at(axis);
+ }
+
+ array[offset] += 1;
+ };
+
+ assert(std::all_of(array.begin(), array.end(), [](int num) { return num == 1; }));
+}
+
+int main(int argc, char **argv)
+{
+ test_iterate();
+
+ nnfw::misc::tensor::Shape shape{3, 4, 3, 4};
+
+ std::cout << "Iterate over tensor{3, 4, 3, 4}" << std::endl;
+
+ nnfw::misc::tensor::iterate(shape) << [](const nnfw::misc::tensor::Index &index) {
+ std::cout << "rank: " << index.rank() << std::endl;
+
+ for (uint32_t d = 0; d < index.rank(); ++d)
+ {
+ std::cout << " offset(" << d << ") = " << index.at(d) << std::endl;
+ }
+ };
+
+ return 0;
+}
diff --git a/runtime/libs/misc/include/misc/EnvVar.h b/runtime/libs/misc/include/misc/EnvVar.h
new file mode 100644
index 000000000..db28a3c7d
--- /dev/null
+++ b/runtime/libs/misc/include/misc/EnvVar.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file EnvVar.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::EnvVar class
+ */
+
+#ifndef __NNFW_MISC_ENV_VAR__
+#define __NNFW_MISC_ENV_VAR__
+
+#include <algorithm>
+#include <array>
+#include <cstdlib>
+#include <string>
+
+namespace nnfw
+{
+namespace misc
+{
+/**
+ * @brief Class to access environment variable
+ */
+class EnvVar
+{
+public:
+ /**
+ * @brief Construct a new EnvVar object
+ * @param[in] key environment variable
+ */
+ EnvVar(const std::string &key)
+ {
+ const char *value = std::getenv(key.c_str());
+ if (value == nullptr)
+ {
+ // An empty string is considered as an empty value
+ _value = "";
+ }
+ else
+ {
+ _value = value;
+ }
+ }
+
+ /**
+ * @brief Get environment variable of string type
+ * @param[in] def Default value of environment variable
+ * @return Defaut value passed as a parameter when there is no environment variable,
+ * otherwise the value of environment variable passed into constructor
+ */
+ std::string asString(const std::string &def) const
+ {
+ if (_value.empty())
+ return def;
+ return _value;
+ }
+
+ /**
+ * @brief Get environment variable of boolean type
+ * @param[in] def Default value of environment variable
+ * @return Defaut value passed as a parameter when there is no environment variable,
+ * otherwise the value of environment variable passed into constructor
+ */
+ bool asBool(bool def) const
+ {
+ if (_value.empty())
+ return def;
+ static const std::array<std::string, 5> false_list{"0", "OFF", "FALSE", "N", "NO"};
+ auto false_found = std::find(false_list.begin(), false_list.end(), _value);
+ return (false_found == false_list.end());
+ }
+
+ /**
+ * @brief Get environment variable of int type
+ * @param[in] def Default value of environment variable
+ * @return Defaut value passed as a parameter when there is no environment variable,
+ * otherwise the value of environment variable passed into constructor
+ */
+ int asInt(int def) const
+ {
+ if (_value.empty())
+ return def;
+ return std::stoi(_value);
+ }
+
+ /**
+ * @brief Get environment variable of float type
+ * @param[in] def Default value of environment variable
+ * @return Defaut value passed as a parameter when there is no environment variable,
+ * otherwise the value of environment variable passed into constructor
+ */
+ float asFloat(float def) const
+ {
+ if (_value.empty())
+ return def;
+ return std::stof(_value);
+ }
+
+private:
+ std::string _value;
+};
+
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_ENV_VAR__
diff --git a/runtime/libs/misc/include/misc/RandomGenerator.h b/runtime/libs/misc/include/misc/RandomGenerator.h
new file mode 100644
index 000000000..8d26b8c74
--- /dev/null
+++ b/runtime/libs/misc/include/misc/RandomGenerator.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file RandomGenerator.h
+ * @brief This file contains classes for random value generation
+ */
+
+#ifndef __NNFW_MISC_RANDOM_GENERATOR_H__
+#define __NNFW_MISC_RANDOM_GENERATOR_H__
+
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Index.h"
+
+#include <random>
+
+namespace nnfw
+{
+namespace misc
+{
+
+/**
+ * @brief Class to generate random values
+ */
+class RandomGenerator
+{
+public:
+ /**
+ * @brief Construct a new RandomGenerator object
+ * @param[in] seed Random seed value
+ * @param[in] mean Mean value of normal random number generation
+ * @param[in] stddev Standard deviation of random number generation
+ * @param[in] quantization TfLiteQuantizationParams type to represent quantization value
+ * (not used yet)
+ */
+ RandomGenerator(uint32_t seed, float mean, float stddev) : _rand{seed}, _dist{mean, stddev}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Generate random numbers for type T
+ * @param[in] s Shape value
+ * @param[in] i Index value
+ * @return Random generated value
+ * @note This is same as T generate(void) as two input parameters are not used
+ */
+ template <typename T>
+ T generate(const ::nnfw::misc::tensor::Shape &, const ::nnfw::misc::tensor::Index &)
+ {
+ return generate<T>();
+ }
+
+ /**
+ * @brief Generate random numbers for type T
+ * @return Random generated value
+ */
+ template <typename T> T generate(void) { return _dist(_rand); }
+
+private:
+ std::minstd_rand _rand;
+ std::normal_distribution<float> _dist;
+};
+
+template <> uint8_t RandomGenerator::generate<uint8_t>(void);
+template <> bool RandomGenerator::generate<bool>(void);
+template <> int32_t RandomGenerator::generate<int32_t>(void);
+template <> int64_t RandomGenerator::generate<int64_t>(void);
+
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_RANDOM_GENERATOR_H__
diff --git a/runtime/libs/misc/include/misc/benchmark.h b/runtime/libs/misc/include/misc/benchmark.h
new file mode 100644
index 000000000..aa487aca9
--- /dev/null
+++ b/runtime/libs/misc/include/misc/benchmark.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file benchmark.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::benchmark::Accumulator class
+ */
+#ifndef __NNFW_MISC_BENCHMARK_H__
+#define __NNFW_MISC_BENCHMARK_H__
+
+#include <chrono>
+
+namespace nnfw
+{
+namespace misc
+{
+// Benckmark support
+namespace benchmark
+{
+
+/**
+ * @brief Class to accumulate time during benchmark
+ */
+template <typename T> class Accumulator
+{
+public:
+ /**
+ * @brief Construct a new Accumulator object
+ * @param[in] ref Object to keep time duration
+ */
+ Accumulator(T &ref) : _ref(ref)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return the reference of @c ref passed to constructor
+ * @return Reference of @c ref
+ */
+ T &operator()(void) { return _ref; }
+
+private:
+ T &_ref;
+};
+
+/**
+ * @brief Run passed function and returns accumulated time
+ * @tparam T Period used by @c std::chrono::duration_cast
+ * @tparam Callable Function type to benchmark
+ * @param[in] acc Accumulated time after running @cb
+ * @param[in] cb Function to run and benchmark
+ * @return Accumulated time
+ */
+template <typename T, typename Callable>
+Accumulator<T> &operator<<(Accumulator<T> &&acc, Callable cb)
+{
+ auto begin = std::chrono::high_resolution_clock::now();
+ cb();
+ auto end = std::chrono::high_resolution_clock::now();
+
+ acc() += std::chrono::duration_cast<T>(end - begin);
+
+ return acc;
+}
+
+template <typename T> Accumulator<T> measure(T &out) { return Accumulator<T>(out); }
+
+} // namespace benchmark
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_BENCHMARK_H__
diff --git a/runtime/libs/misc/include/misc/feature/Index.h b/runtime/libs/misc/include/misc/feature/Index.h
new file mode 100644
index 000000000..a361d8dd2
--- /dev/null
+++ b/runtime/libs/misc/include/misc/feature/Index.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Index.h
+ * @brief This file contains Index class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_FEATURE_INDEX_H__
+#define __NNFW_MISC_FEATURE_INDEX_H__
+
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace feature
+{
+
+/**
+ * @brief Class to have the index information for calculating the offset.
+ */
+class Index
+{
+public:
+ /**
+ * @brief Construct Index object using default constrcutor
+ */
+ Index() = default;
+
+public:
+ /**
+ * @brief Construct Index object with three indexes of dimensions
+ * @param[in] ch The depth index
+ * @param[in] row The heigth index
+ * @param[in] col The width index
+ */
+ Index(int32_t ch, int32_t row, int32_t col) : _batch{1}, _ch{ch}, _row{row}, _col{col}
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct Index object with four indexes of dimensions
+ * @param[in] batch The batch index
+ * @param[in] ch The depth index
+ * @param[in] row The height index
+ * @param[in] col The width index
+ */
+ Index(int32_t batch, int32_t ch, int32_t row, int32_t col)
+ : _batch{batch}, _ch{ch}, _row{row}, _col{col}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get the batch index
+ * @return The batch index
+ */
+ int32_t batch(void) const { return _batch; }
+ /**
+ * @brief Get the depth index
+ * @return The depth index
+ */
+ int32_t ch(void) const { return _ch; }
+ /**
+ * @brief Get the height index
+ * @return The height index
+ */
+ int32_t row(void) const { return _row; }
+ /**
+ * @brief Get the width index
+ * @return The width index
+ */
+ int32_t col(void) const { return _col; }
+
+public:
+ /**
+ * @brief Get the batch index as the lvalue reference
+ * @return The reference of the batch value
+ */
+ int32_t &batch(void) { return _batch; }
+ /**
+ * @brief Get the depth index as the lvalue reference
+ * @return The reference of the depth value
+ */
+ int32_t &ch(void) { return _ch; }
+ /**
+ * @brief Get the height index as the lvalue reference
+ * @return The reference of the height value
+ */
+ int32_t &row(void) { return _row; }
+ /**
+ * @brief Get the width index as the lvalue reference
+ * @return The reference of the width value
+ */
+ int32_t &col(void) { return _col; }
+
+private:
+ /**
+ * @brief The batch index
+ */
+ int32_t _batch;
+ /**
+ * @brief The depth index
+ */
+ int32_t _ch;
+ /**
+ * @brief The height index
+ */
+ int32_t _row;
+ /**
+ * @brief The width index
+ */
+ int32_t _col;
+};
+
+} // namespace feature
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FEATURE_INDEX_H__
diff --git a/runtime/libs/misc/include/misc/feature/IndexIterator.h b/runtime/libs/misc/include/misc/feature/IndexIterator.h
new file mode 100644
index 000000000..1cf675526
--- /dev/null
+++ b/runtime/libs/misc/include/misc/feature/IndexIterator.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IndexIterator.h
+ * @brief This file contains IndexIterator class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_FEATURE_INDEX_ITERATOR_H__
+#define __NNFW_MISC_FEATURE_INDEX_ITERATOR_H__
+
+#include "misc/feature/Shape.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace feature
+{
+
+/**
+ * @brief Class to iterate Callable with Index of feature
+ */
+class IndexIterator
+{
+public:
+ /**
+ * @brief Construct IndexIterator object with Shape of feature
+ * @param[in] shape Shape reference of feature
+ */
+ IndexIterator(const Shape &shape) : _shape{shape}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Call a function iterated
+ * @param[in] cb A callback function
+ * @return Current IndexIterator object
+ */
+ template <typename Callable> IndexIterator &iter(Callable cb)
+ {
+ for (int32_t batch = 0; batch < _shape.N; ++batch)
+ {
+ for (int32_t ch = 0; ch < _shape.C; ++ch)
+ {
+ for (int32_t row = 0; row < _shape.H; ++row)
+ {
+ for (int32_t col = 0; col < _shape.W; ++col)
+ {
+ cb(batch, ch, row, col);
+ }
+ }
+ }
+ }
+
+ return (*this);
+ }
+
+private:
+ /**
+ * @brief Shape for feature
+ */
+ const Shape _shape;
+};
+
+/**
+ * @brief Create an object of IndexIterator for feature
+ * @param[in] Shape reference of feature
+ * @return Created IndexIterator object
+ */
+static inline IndexIterator iterate(const Shape &shape) { return IndexIterator{shape}; }
+
+/**
+ * @brief Call a function iterated using IndexIterator of feature
+ * Overloaded operator<<
+ * @param[in] it An IndexIterator reference
+ * @param[in] cb A callback function
+ * @return created IndexIterator object
+ */
+template <typename Callable> IndexIterator &operator<<(IndexIterator &&it, Callable cb)
+{
+ return it.iter(cb);
+}
+
+} // namespace feature
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FEATURE_INDEX_ITERATOR_H__
diff --git a/runtime/libs/misc/include/misc/feature/Object.h b/runtime/libs/misc/include/misc/feature/Object.h
new file mode 100644
index 000000000..7af0e28f4
--- /dev/null
+++ b/runtime/libs/misc/include/misc/feature/Object.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Object.h
+ * @brief This file contains Object class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_FEATURE_OBJECT_H__
+#define __NNFW_MISC_FEATURE_OBJECT_H__
+
+#include "misc/feature/Shape.h"
+#include "misc/feature/Index.h"
+#include "misc/feature/Reader.h"
+
+#include <vector>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace feature
+{
+
+/**
+ * @brief Class to have information of the operand for feature
+ */
+template <typename T> class Object final : public Reader<T>
+{
+public:
+ using Generator = std::function<T(const Shape &shape, const Index &index)>;
+
+public:
+ /**
+ * @brief Construct Object object with Shape of feature and set value used by Generator
+ * @param[in] shape Reference of Shape for feature
+ * @param[in] fn A function to set values of operand tensor
+ */
+ Object(const Shape &shape, const Generator &fn) : _shape{shape}
+ {
+ _value.resize(_shape.C * _shape.H * _shape.W);
+
+ for (int32_t ch = 0; ch < _shape.C; ++ch)
+ {
+ for (int32_t row = 0; row < _shape.H; ++row)
+ {
+ for (int32_t col = 0; col < _shape.W; ++col)
+ {
+ _value.at(offsetOf(ch, row, col)) = fn(_shape, Index{ch, row, col});
+ }
+ }
+ }
+ }
+
+public:
+ /**
+ * @brief Get Shape of feature as the reference
+ * @return The reference of the width value
+ */
+ const Shape &shape(void) const { return _shape; }
+
+public:
+ /**
+ * @brief Get the value used by three indexes
+ * @param[in] ch The depth index
+ * @param[in] row The height index
+ * @param[in] col The width index
+ * @return The value at the offset
+ */
+ T at(uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ return _value.at(offsetOf(ch, row, col));
+ }
+
+private:
+ /**
+ * @brief Get the offset value at three indexes
+ * @param[in] ch The depth index
+ * @param[in] row The height index
+ * @param[in] col The width index
+ * @return The offset value
+ */
+ uint32_t offsetOf(uint32_t ch, uint32_t row, uint32_t col) const
+ {
+ return ch * _shape.H * _shape.W + row * _shape.W + col;
+ }
+
+private:
+ /**
+ * @brief Shape of operand
+ */
+ Shape _shape;
+ /**
+ * @brief The tensor vector of operand
+ */
+ std::vector<T> _value;
+};
+
+} // namespace feature
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FEATURE_OBJECT_H__
diff --git a/runtime/libs/misc/include/misc/feature/Reader.h b/runtime/libs/misc/include/misc/feature/Reader.h
new file mode 100644
index 000000000..b09209789
--- /dev/null
+++ b/runtime/libs/misc/include/misc/feature/Reader.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @brief This file contains Reader class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_FEATURE_READER_H__
+#define __NNFW_MISC_FEATURE_READER_H__
+
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace feature
+{
+
+/**
+ * @brief Class reads values of feature
+ * The interface class
+ */
+template <typename T> struct Reader
+{
+ /**
+ * @brief Destruct Reader object using default destructor
+ */
+ virtual ~Reader() = default;
+
+ /**
+ * @brief Get the value used by three indexes
+ * @param[in] ch The depth index
+ * @param[in] row The height index
+ * @param[in] col The width index
+ * @return The value at the offset
+ */
+ virtual T at(uint32_t ch, uint32_t row, uint32_t col) const = 0;
+ /**
+ * @brief Get the value used by four indexes
+ * @param[in] batch The batch index
+ * @param[in] ch The depth index
+ * @param[in] row The height index
+ * @param[in] col The width index
+ * @return The value at the offset
+ */
+ virtual T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const = 0;
+};
+
+} // namespace feature
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FEATURE_READER_H__
diff --git a/runtime/libs/misc/include/misc/feature/Shape.h b/runtime/libs/misc/include/misc/feature/Shape.h
new file mode 100644
index 000000000..09881f58b
--- /dev/null
+++ b/runtime/libs/misc/include/misc/feature/Shape.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Shape.h
+ * @brief This file contains Shape class for feature
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_FEATURE_SHAPE_H__
+#define __NNFW_MISC_FEATURE_SHAPE_H__
+
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace feature
+{
+
+/**
+ * @brief Structure to have values of dimensions for feature
+ */
+struct Shape
+{
+ int32_t N; /**< The batch value */
+ int32_t C; /**< The depth value */
+ int32_t H; /**< The height value */
+ int32_t W; /**< The width value */
+
+ /**
+ * @brief Construct Shape object using default constrcutor
+ */
+ Shape() = default;
+ /**
+ * @brief Construct Shape object with three values of dimensions
+ * @param[in] depth The depth value
+ * @param[in] height The height value
+ * @param[in] width The width value
+ */
+ Shape(int32_t depth, int32_t height, int32_t width) : N{1}, C{depth}, H{height}, W{width}
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct Shape object with four values of dimensions
+ * @param[in] batch The batch value
+ * @param[in] depth The depth value
+ * @param[in] height The height value
+ * @param[in] width The width value
+ */
+ Shape(int32_t batch, int32_t depth, int32_t height, int32_t width)
+ : N{batch}, C{depth}, H{height}, W{width}
+ {
+ // DO NOTHING
+ }
+};
+
+} // namespace feature
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FEATURE_H__
diff --git a/runtime/libs/misc/include/misc/feature/TextFormatter.h b/runtime/libs/misc/include/misc/feature/TextFormatter.h
new file mode 100644
index 000000000..e053f1c61
--- /dev/null
+++ b/runtime/libs/misc/include/misc/feature/TextFormatter.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file TextFormatter.h
+ * @brief This file contains TextFormatter class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_FEATURE_TEXT_FORMATTER_H__
+#define __NNFW_MISC_FEATURE_TEXT_FORMATTER_H__
+
+#include "misc/feature/Shape.h"
+#include "misc/feature/Reader.h"
+
+#include <ostream>
+#include <iomanip>
+#include <limits>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace feature
+{
+
+/**
+ * @brief Class to print operand of feature to ostream in the given string format
+ */
+template <typename T> class TextFormatter
+{
+public:
+ /**
+ * @brief Construct TextFormatter object with an operand's information.
+ * @param[in] shape The shape of an operand
+ * @param[in] data The data of an operand
+ */
+ TextFormatter(const Shape &shape, const Reader<T> &data) : _shape(shape), _data(data)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get Shape of feature as the lvalue reference
+ * @return Shape of feature
+ */
+ const Shape &shape(void) const { return _shape; }
+ /**
+ * @brief Get Reader<T> that can read the data of an operand
+ * @return Reader<T>
+ */
+ const Reader<T> &data(void) const { return _data; }
+
+private:
+ /**
+ * @brief Shape of feature
+ */
+ const Shape &_shape;
+ /**
+ * @brief Reader<T> that can read the data of an operand
+ */
+ const Reader<T> &_data;
+};
+
+/**
+ * @brief Print operand of feature
+ * @param[in] os Standard output stream
+ * @param[in] fmt TextFormatter to print information of an operand
+ * @return Standard output stream
+ */
+template <typename T> std::ostream &operator<<(std::ostream &os, const TextFormatter<T> &fmt)
+{
+ const auto &shape = fmt.shape();
+
+ for (uint32_t ch = 0; ch < shape.C; ++ch)
+ {
+ os << " Channel " << ch << ":" << std::endl;
+ for (uint32_t row = 0; row < shape.H; ++row)
+ {
+ os << " ";
+ for (uint32_t col = 0; col < shape.W; ++col)
+ {
+ const auto value = fmt.data().at(ch, row, col);
+ os << std::right;
+ os << std::fixed;
+ os << std::setw(std::numeric_limits<T>::digits10 + 2);
+ os << std::setprecision(5);
+ os << value;
+ os << " ";
+ }
+ os << std::endl;
+ }
+ }
+
+ return os;
+}
+
+} // namespace feature
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FEATURE_TEXT_FORMATTER_H__
diff --git a/runtime/libs/misc/include/misc/fp32.h b/runtime/libs/misc/include/misc/fp32.h
new file mode 100644
index 000000000..c310402ba
--- /dev/null
+++ b/runtime/libs/misc/include/misc/fp32.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file fp32.h
+ * @brief This file contains functions to compare float values
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_FP32_H__
+#define __NNFW_MISC_FP32_H__
+
+#include <cmath>
+#include <cfloat>
+#include <algorithm>
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace fp32
+{
+
+/**
+ * @brief Get the difference between two float values as a relative value.
+ * @param[in] lhs A float value to be compared
+ * @param[in] rhs A float value to be compared
+ * @return A relative value of difference between two float values.
+ */
+inline float relative_diff(float lhs, float rhs)
+{
+ const auto diff = std::fabs(lhs - rhs);
+ const auto base = std::max(std::fabs(lhs), std::fabs(rhs));
+
+ return diff / base;
+}
+
+/**
+ * @brief Verify that an obtained float value is equal to the expected float value
+ * by using FLT_EPSILON
+ * @param[in] expected An expected float value to be compared
+ * @param[in] obtained An obtained float value to be compared
+ * @param[in] tolerance A tolerance value
+ * @return @c true if both values are equal, otherwise @c false
+ */
+inline bool epsilon_equal(float expected, float obtained, uint32_t tolerance = 1)
+{
+ if (std::isnan(expected) && std::isnan(obtained))
+ {
+ return true;
+ }
+
+ // Let's use relative epsilon comparision
+ const auto diff = std::fabs(expected - obtained);
+ const auto max = std::max(std::fabs(expected), std::fabs(obtained));
+
+ return diff <= (max * FLT_EPSILON * tolerance);
+}
+
+/**
+ * @brief Verify that an obtained float value is equal to the expected float value
+ * by comparing absolute tolerance value
+ * @param[in] expected An expected float value to be compared
+ * @param[in] obtained An obtained float value to be compared
+ * @param[in] tolerance A tolerance value
+ * @return @c true if both values are equal, otherwise @c false
+ */
+inline bool absolute_epsilon_equal(float expected, float obtained, float tolerance = 0.001)
+{
+ if (std::isnan(expected) && std::isnan(obtained))
+ {
+ return true;
+ }
+
+ // Let's use absolute epsilon comparision
+ const auto diff = std::fabs(expected - obtained);
+
+ return diff <= tolerance;
+}
+
+} // namespace fp32
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FP32_H__
diff --git a/runtime/libs/misc/include/misc/kernel/IndexIterator.h b/runtime/libs/misc/include/misc/kernel/IndexIterator.h
new file mode 100644
index 000000000..59e0f0095
--- /dev/null
+++ b/runtime/libs/misc/include/misc/kernel/IndexIterator.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IndexIterator.h
+ * @brief This file contains IndexIterator class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_KERNEL_INDEX_ITERATOR_H__
+#define __NNFW_MISC_KERNEL_INDEX_ITERATOR_H__
+
+#include "misc/kernel/Shape.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace kernel
+{
+
+/**
+ * @brief Class to iterate Callable with Index of kernel
+ */
+class IndexIterator
+{
+public:
+ /**
+ * @brief Construct IndexIterator object with Shape of kernel
+ * @param[in] shape Shape reference of feature
+ */
+ IndexIterator(const Shape &shape) : _shape{shape}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Call a function iterated
+ * @param[in] cb A callback function
+ * @return Current IndexIterator object
+ */
+ template <typename Callable> IndexIterator &iter(Callable cb)
+ {
+ for (int32_t nth = 0; nth < _shape.N; ++nth)
+ {
+ for (int32_t ch = 0; ch < _shape.C; ++ch)
+ {
+ for (int32_t row = 0; row < _shape.H; ++row)
+ {
+ for (int32_t col = 0; col < _shape.W; ++col)
+ {
+ cb(nth, ch, row, col);
+ }
+ }
+ }
+ }
+
+ return (*this);
+ }
+
+private:
+ const Shape _shape; /**< Shape for kernel */
+};
+
+/**
+ * @brief Create an object of IndexIterator for kernel
+ * @param[in] shape reference of feature
+ * @return Created IndexIterator object
+ */
+inline IndexIterator iterate(const Shape &shape) { return IndexIterator{shape}; }
+
+/**
+ * @brief Call a function iterated using IndexIterator of kernel
+ * Overloaded operator<<
+ * @param[in] it An IndexIterator reference
+ * @param[in] cb A callback function
+ * @return Created IndexIterator object
+ */
+template <typename Callable> IndexIterator &operator<<(IndexIterator &&it, Callable cb)
+{
+ return it.iter(cb);
+}
+
+} // namespace kernel
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FEATURE_INDEX_ITERATOR_H__
diff --git a/runtime/libs/misc/include/misc/kernel/Reader.h b/runtime/libs/misc/include/misc/kernel/Reader.h
new file mode 100644
index 000000000..019c809ee
--- /dev/null
+++ b/runtime/libs/misc/include/misc/kernel/Reader.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @brief This file contains Reader structure
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_KERNEL_READER_H__
+#define __NNFW_MISC_KERNEL_READER_H__
+
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace kernel
+{
+
+/**
+ * @brief Structure to Reader
+ */
+template <typename T> struct Reader
+{
+ /**
+ * @brief Destroy the Reader object as default
+ */
+ virtual ~Reader() = default;
+
+ /**
+ * @brief Get the value used by four indexes
+ * @param[in] nth The kernel index
+ * @param[in] ch The channel index
+ * @param[in] row The row index
+ * @param[in] col The column index
+ * @return The value at the offset
+ */
+ virtual T at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const = 0;
+};
+
+} // namespace kernel
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_KERNEL_READER_H__
diff --git a/runtime/libs/misc/include/misc/kernel/Shape.h b/runtime/libs/misc/include/misc/kernel/Shape.h
new file mode 100644
index 000000000..27d6a8bf0
--- /dev/null
+++ b/runtime/libs/misc/include/misc/kernel/Shape.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Shape.h
+ * @brief This file contains Shape structure
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_KERNEL_SHAPE_H__
+#define __NNFW_MISC_KERNEL_SHAPE_H__
+
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace kernel
+{
+
+/**
+ * @brief Structure to Shape
+ */
+struct Shape
+{
+ int32_t N; /**< The kernel index */
+ int32_t C; /**< The channel index */
+ int32_t H; /**< The height index */
+ int32_t W; /**< The width index */
+
+ /**
+ * @brief Construct a new Shape object as default
+ */
+ Shape() = default;
+
+ /**
+ * @brief Construct a new Shape object with parameters
+ * @param[in] count The kernel index
+ * @param[in] depth The channel index
+ * @param[in] height The height index
+ * @param[in] width The width index
+ */
+ Shape(int32_t count, int32_t depth, int32_t height, int32_t width)
+ : N{count}, C{depth}, H{height}, W{width}
+ {
+ // DO NOTHING
+ }
+};
+
+} // namespace kernel
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_KERNEL_SHAPE_H__
diff --git a/runtime/libs/misc/include/misc/matrix/IndexIterator.h b/runtime/libs/misc/include/misc/matrix/IndexIterator.h
new file mode 100644
index 000000000..742ed3a65
--- /dev/null
+++ b/runtime/libs/misc/include/misc/matrix/IndexIterator.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IndexIterator.h
+ * @brief This file contains IndexIterator class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_MATRIX_INDEX_ITERATOR_H__
+#define __NNFW_MISC_MATRIX_INDEX_ITERATOR_H__
+
+#include "misc/matrix/Shape.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace matrix
+{
+
+/**
+ * @brief Class to iterate Callable with Index of matrix
+ */
+class IndexIterator
+{
+public:
+ /**
+ * @brief Construct IndexIterator object with Shape of matrix
+ * @param[in] shape Shape reference of matrix
+ */
+ IndexIterator(const Shape &shape) : _shape{shape}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Call a function iterated
+ * @param[in] cb A callback function
+ * @return Current IndexIterator object
+ */
+ template <typename Callable> IndexIterator &iter(Callable cb)
+ {
+ for (uint32_t row = 0; row < _shape.H; ++row)
+ {
+ for (uint32_t col = 0; col < _shape.W; ++col)
+ {
+ cb(row, col);
+ }
+ }
+
+ return (*this);
+ }
+
+private:
+ /**
+ * @brief Shape for matrix
+ */
+ const Shape _shape;
+};
+
+/**
+ * @brief Create an object of IndexIterator for matrix
+ * @param[in] Shape reference of matrix
+ * @return Created IndexIterator object
+ */
+inline IndexIterator iterate(const Shape &shape) { return IndexIterator{shape}; }
+
+/**
+ * @brief Call a function iterated using IndexIterator of matrix
+ * Overloaded operator<<
+ * @param[in] it An IndexIterator reference
+ * @param[in] cb A callback function
+ * @return created IndexIterator object
+ */
+template <typename Callable> IndexIterator &operator<<(IndexIterator &&it, Callable cb)
+{
+ return it.iter(cb);
+}
+
+} // namespace matrix
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_MATRIX_INDEX_ITERATOR_H__
diff --git a/runtime/libs/misc/include/misc/matrix/Reader.h b/runtime/libs/misc/include/misc/matrix/Reader.h
new file mode 100644
index 000000000..ea222c9d1
--- /dev/null
+++ b/runtime/libs/misc/include/misc/matrix/Reader.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @brief This file contains Reader class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_MATRIX_READER_H__
+#define __NNFW_MISC_MATRIX_READER_H__
+
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace matrix
+{
+
+/**
+ * @brief Class reads values of matrix
+ * The interface class
+ */
+template <typename T> struct Reader
+{
+ /**
+ * @brief Destruct Reader object using default destructor
+ */
+ virtual ~Reader() = default;
+
+ /**
+ * @brief Get the value used by two indexes
+ * @param[in] row The height index
+ * @param[in] col The width index
+ * @return The value at the offset
+ */
+ virtual T at(uint32_t row, uint32_t col) const = 0;
+};
+
+} // namespace matrix
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_MATRIX_READER_H__
diff --git a/runtime/libs/misc/include/misc/matrix/Shape.h b/runtime/libs/misc/include/misc/matrix/Shape.h
new file mode 100644
index 000000000..8cbcc1e12
--- /dev/null
+++ b/runtime/libs/misc/include/misc/matrix/Shape.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Shape.h
+ * @brief This file contains Shape class for matrix
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_MATRIX_SHAPE_H__
+#define __NNFW_MISC_MATRIX_SHAPE_H__
+
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace matrix
+{
+
+/**
+ * @brief Structure to have values of dimensions for matrix
+ */
+struct Shape
+{
+ int32_t H; /**< The height value */
+ int32_t W; /**< The width value */
+
+ /**
+ * @brief Construct Shape object using default constrcutor
+ */
+ Shape() = default;
+
+ /**
+ * @brief Construct Shape object with two values of dimensions
+ * @param[in] height The height value
+ * @param[in] width The width value
+ */
+ Shape(int32_t height, int32_t width) : H{height}, W{width}
+ {
+ // DO NOTHING
+ }
+};
+
+} // namespace matrix
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_MATRIX_SHAPE_H__
diff --git a/runtime/libs/misc/include/misc/polymorphic_downcast.h b/runtime/libs/misc/include/misc/polymorphic_downcast.h
new file mode 100644
index 000000000..ee885eb70
--- /dev/null
+++ b/runtime/libs/misc/include/misc/polymorphic_downcast.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_MISC_POLYMORPHIC_DOWNCAST_H__
+#define __NNFW_MISC_POLYMORPHIC_DOWNCAST_H__
+
+#include <cassert>
+#include <memory>
+
+namespace nnfw
+{
+namespace misc
+{
+
+template <typename DstType, typename SrcType> inline DstType polymorphic_downcast(SrcType *x)
+{
+ assert(dynamic_cast<DstType>(x) == x);
+ return static_cast<DstType>(x);
+}
+
+template <typename DstType, typename SrcType> inline DstType polymorphic_downcast(SrcType &x)
+{
+ assert(std::addressof(dynamic_cast<DstType>(x)) == std::addressof(x));
+ return static_cast<DstType>(x);
+}
+
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_POLYMORPHIC_DOWNCAST_H__
diff --git a/runtime/libs/misc/include/misc/string_helpers.h b/runtime/libs/misc/include/misc/string_helpers.h
new file mode 100644
index 000000000..46fecca71
--- /dev/null
+++ b/runtime/libs/misc/include/misc/string_helpers.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file string_helpers.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains helper functions for std::string
+ */
+
+#include <ostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+namespace
+{
+
+template <typename Arg> void _str(std::ostream &os, Arg &&arg) { os << std::forward<Arg>(arg); }
+
+template <typename Arg, typename... Args> void _str(std::ostream &os, Arg &&arg, Args &&... args)
+{
+ _str(os, std::forward<Arg>(arg));
+ _str(os, std::forward<Args>(args)...);
+}
+
+} // namespace
+
+namespace nnfw
+{
+namespace misc
+{
+
+inline std::vector<std::string> split(const std::string &s, char delim)
+{
+ std::stringstream ss(s);
+ std::string item;
+ std::vector<std::string> elems;
+ while (std::getline(ss, item, delim))
+ {
+ elems.push_back(std::move(item));
+ }
+ return elems;
+}
+
+template <typename... Args> std::string str(Args &&... args)
+{
+ std::stringstream ss;
+ _str(ss, std::forward<Args>(args)...);
+ return ss.str();
+}
+
+template <typename InputIt> std::string join(InputIt first, InputIt last, const std::string &concat)
+{
+ std::string ret;
+ if (first == last)
+ return ret;
+
+ ret += *first;
+ for (++first; first != last; ++first)
+ {
+ ret += concat;
+ ret += *first;
+ }
+ return ret;
+}
+
+} // namespace misc
+} // namespace nnfw
diff --git a/runtime/libs/misc/include/misc/tensor/Comparator.h b/runtime/libs/misc/include/misc/tensor/Comparator.h
new file mode 100644
index 000000000..80f53043c
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/Comparator.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Comparator.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::Comparator class
+ */
+
+#ifndef __NNFW_MISC_TENSOR_COMPARATOR_H__
+#define __NNFW_MISC_TENSOR_COMPARATOR_H__
+
+#include "misc/tensor/Index.h"
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Reader.h"
+#include "misc/tensor/Diff.h"
+
+#include <functional>
+
+#include <vector>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to compare two tensors (expected and obtained to compare)
+ */
+class Comparator
+{
+public:
+ /**
+ * @brief Construct a new @c Comparator object
+ * @param[in] fn Function that compares two float values
+ */
+ Comparator(const std::function<bool(float lhs, float rhs)> &fn) : _compare_fn{fn}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Struct to observe comparison results
+ */
+ struct Observer
+ {
+ /**
+ * @brief Get notification of comparison result at every index of two tensors
+ * @param[in] index Index of tensors compared
+ * @param[in] expected Expected value of element at @c index
+ * @param[in] obtained Obtained value of element at @c index
+ * @return N/A
+ */
+ virtual void notify(const Index &index, float expected, float obtained) = 0;
+ };
+
+public:
+ /**
+ * @brief Compare two tensors
+ * @param[in] shape Shape of two tensors
+ * @param[in] expected @c Reader<float> object that accesses expected tensor
+ * @param[in] obtained @c Reader<float> object that accesses obtained tensor
+ * @param[in] observer @c Observer notified of expected value and obtained value at every index
+ * @return @c std::vector<Diff<float>> containing information of failed comparison
+ */
+ // NOTE Observer should live longer than comparator
+ std::vector<Diff<float>> compare(const Shape &shape, const Reader<float> &expected,
+ const Reader<float> &obtained,
+ Observer *observer = nullptr) const;
+
+private:
+ std::function<bool(float lhs, float rhs)> _compare_fn;
+};
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_COMPARATOR_H__
diff --git a/runtime/libs/misc/include/misc/tensor/Diff.h b/runtime/libs/misc/include/misc/tensor/Diff.h
new file mode 100644
index 000000000..c41a97987
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/Diff.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Diff.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::Diff struct
+ */
+
+#ifndef __NNFW_MISC_TENSOR_DIFF_H__
+#define __NNFW_MISC_TENSOR_DIFF_H__
+
+#include "misc/tensor/Index.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Struct to have information after comparing two elements of two tensors
+ */
+template <typename T> struct Diff
+{
+ Index index; /**< Index of elements in two tensors, which turn out to be different */
+
+ T expected; /**< Expected value of element of first tensor */
+ T obtained; /**< Obtained value of element of second tensor */
+
+ /**
+ * @brief Construct a new @c Diff object
+ * @param[in] i Initial value of index
+ */
+ Diff(const Index &i) : index(i)
+ {
+ // DO NOTHING
+ }
+
+ /**
+ * @brief Construct a new @c Diff object
+ * @param[in] i Index value
+ * @param[in] e Expected value of element of first tensor
+ * @param[in] o Obtained value of element of second tensor
+ */
+ Diff(const Index &i, const T &e, const T &o) : index(i), expected{e}, obtained{o}
+ {
+ // DO NOTHING
+ }
+};
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_DIFF_H__
diff --git a/runtime/libs/misc/include/misc/tensor/Index.h b/runtime/libs/misc/include/misc/tensor/Index.h
new file mode 100644
index 000000000..a633b4ce0
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/Index.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Index.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::Index struct
+ */
+#ifndef __NNFW_MISC_TENSOR_INDEX_H__
+#define __NNFW_MISC_TENSOR_INDEX_H__
+
+#include <cstdint>
+#include <cstddef>
+
+#include <vector>
+#include <initializer_list>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Struct to represent index of each dimension of a tensor
+ */
+struct Index
+{
+public:
+ /**
+ * @brief Construct a new @c Index object
+ * @param[in] rank Rank of a tensor
+ */
+ Index(uint32_t rank) { _offsets.resize(rank); }
+
+public:
+ /**
+ * @brief Construct a new @c Index object
+ * @param[in] offsets Rank of a tensor of @c std::initializer_list<int32_t> type
+ */
+ Index(std::initializer_list<int32_t> offsets) : _offsets{offsets}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get the rank
+ * @return Rank that this @c Index object can handle
+ * @note We can use static_cast\n
+ * because size of _offsets is decieded by constructor's uintt_32 type argument
+ */
+ uint32_t rank(void) const { return static_cast<uint32_t>(_offsets.size()); }
+
+public:
+ /**
+ * @brief Get the index n'th dimension
+ * @param[in] n Dimension
+ * @return index of n'th dimension
+ */
+ int32_t at(uint32_t n) const { return _offsets.at(n); }
+
+ /**
+ * @brief Get the reference of the index n'th dimension
+ * @param[in] n Dimension
+ * @return reference of index of n'th dimension
+ */
+ int32_t &at(uint32_t n) { return _offsets.at(n); }
+
+private:
+ std::vector<int32_t> _offsets;
+};
+
+/**
+ * @brief Copy an @c Index with reversed order
+ * @param[in] origin @c Index object to copy
+ * @return an @c Index object with reversed order
+ * @note This is used to convert NNAPI tensor index to ARM tensor index or vice versa
+ */
+inline static Index copy_reverse(const Index &origin)
+{
+ uint32_t rank = origin.rank();
+ Index target(rank);
+ for (uint32_t i = 0; i < rank; i++)
+ target.at(i) = origin.at(rank - 1 - i);
+ return target;
+}
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_INDEX_H__
diff --git a/runtime/libs/misc/include/misc/tensor/IndexEnumerator.h b/runtime/libs/misc/include/misc/tensor/IndexEnumerator.h
new file mode 100644
index 000000000..6ce3add77
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/IndexEnumerator.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IndexEnumerator.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::IndexEnumerator class
+ */
+
+#ifndef __NNFW_MISC_TENSOR_INDEX_ENUMERATOR_H__
+#define __NNFW_MISC_TENSOR_INDEX_ENUMERATOR_H__
+
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Index.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+/**
+ * @brief Class to enumerate index of a tensor
+ *
+ */
+class IndexEnumerator
+{
+public:
+ /**
+ * @brief Construct a new @c IndexEnumerator object
+ * @param[in] shape Shape of tensor of which index will be enumerate
+ */
+ explicit IndexEnumerator(const Shape &shape) : _shape(shape), _cursor(0), _index(shape.rank())
+ {
+ const uint32_t rank = _shape.rank();
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ _index.at(axis) = 0;
+ }
+
+ for (_cursor = 0; _cursor < rank; ++_cursor)
+ {
+ if (_index.at(_cursor) < _shape.dim(_cursor))
+ {
+ break;
+ }
+ }
+ }
+
+public:
+ /**
+ * @brief Prevent constructing @c IndexEnumerator object by using R-value reference
+ */
+ IndexEnumerator(IndexEnumerator &&) = delete;
+ /**
+ * @brief Prevent copy constructor
+ */
+ IndexEnumerator(const IndexEnumerator &) = delete;
+
+public:
+ /**
+ * @brief Check if more enumeration is available
+ * @return @c true if more @c advance() is available, otherwise @c false
+ */
+ bool valid(void) const { return _cursor < _shape.rank(); }
+
+public:
+ /**
+ * @brief Get the current index to enumerate
+ * @return Current index
+ */
+ const Index &curr(void) const { return _index; }
+
+public:
+ /**
+ * @brief Advance index by +1
+ */
+ void advance(void)
+ {
+ const uint32_t rank = _shape.rank();
+
+ // Find axis to be updated
+ while ((_cursor < rank) && !(_index.at(_cursor) + 1 < _shape.dim(_cursor)))
+ {
+ ++_cursor;
+ }
+
+ if (_cursor == rank)
+ {
+ return;
+ }
+
+ // Update index
+ _index.at(_cursor) += 1;
+
+ for (uint32_t axis = 0; axis < _cursor; ++axis)
+ {
+ _index.at(axis) = 0;
+ }
+
+ // Update cursor
+ _cursor = 0;
+ }
+
+public:
+ const Shape _shape; //!< Shape to enumerate
+
+private:
+ uint32_t _cursor;
+ Index _index;
+};
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_INDEX_ENUMERATOR_H__
diff --git a/runtime/libs/misc/include/misc/tensor/IndexFormatter.h b/runtime/libs/misc/include/misc/tensor/IndexFormatter.h
new file mode 100644
index 000000000..7ae34eec1
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/IndexFormatter.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IndexFormatter.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::IndexFormatter class
+ */
+
+#ifndef __NNFW_MISC_TENSOR_INDEX_FORMATTER_H__
+#define __NNFW_MISC_TENSOR_INDEX_FORMATTER_H__
+
+#include "misc/tensor/Index.h"
+
+#include <ostream>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to send @c Index object to output stream
+ */
+class IndexFormatter
+{
+public:
+ /**
+ * @brief Construct a new @c IndexFormatter object
+ * @param[in] index index to be sent to output stream
+ */
+ IndexFormatter(const nnfw::misc::tensor::Index &index) : _index(index)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get an @c Index object
+ * @return @c Index object previously passed to the constructor
+ */
+ const nnfw::misc::tensor::Index &index(void) const { return _index; }
+
+private:
+ const nnfw::misc::tensor::Index &_index;
+};
+
+/**
+ * @brief Send @c IndexFormatter object to output stream
+ * @param[in] os Output stream
+ * @param[in] fmt @c IndexFormatter object that is sent to output stream
+ * @return Output stream
+ */
+std::ostream &operator<<(std::ostream &os, const IndexFormatter &fmt);
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_INDEX_FORMATTER_H__
diff --git a/runtime/libs/misc/include/misc/tensor/IndexIterator.h b/runtime/libs/misc/include/misc/tensor/IndexIterator.h
new file mode 100644
index 000000000..f6428e19e
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/IndexIterator.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IndexIterator.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::IndexIterator class and
+ * helper function and operator
+ */
+#ifndef __NNFW_MISC_TENSOR_INDEX_ITERATOR_H__
+#define __NNFW_MISC_TENSOR_INDEX_ITERATOR_H__
+
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Index.h"
+#include "misc/tensor/IndexEnumerator.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to iterate indexes available for given shape
+ */
+class IndexIterator
+{
+public:
+ /**
+ * @brief Construct a new @c IndexIterator object
+ * @param[in] shape Shape of tensor of which index will be iterated
+ */
+ IndexIterator(const Shape &shape) : _shape(shape)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Construct a new IndexIterator object using reference
+ * @param[in] IndexIterator @c IndexIterator object to move
+ */
+ IndexIterator(IndexIterator &&) = default;
+
+ /**
+ * @brief Prevent copy constructor
+ */
+ IndexIterator(const IndexIterator &) = delete;
+
+public:
+ /**
+ * @brief Iterate all available indexes and run a function for each index
+ * @param[in] fn Function that requires an index as a parameter.
+ * @return @c IndexIterator object
+ */
+ template <typename Callable> IndexIterator &iter(Callable fn)
+ {
+ for (IndexEnumerator e{_shape}; e.valid(); e.advance())
+ {
+ fn(e.curr());
+ }
+
+ return (*this);
+ }
+
+private:
+ const Shape &_shape;
+};
+
+/**
+ * @brief Get an @c IndexItator object
+ * @param[in] shape Shape of tensor of which index will be iterated
+ * @return @c IndexIterator object
+ */
+inline IndexIterator iterate(const Shape &shape) { return IndexIterator{shape}; }
+
+/**
+ * @brief Iterate all indexes and apply a function
+ * @param[in] it @c IndexIterator object that is constructed with a tensor shape
+ * @param[in] cb A function that will receive a specific index.
+ * Inside the function, the index is used to manipulate tensor element.
+ * @return @c IndexIterator object
+ */
+template <typename Callable> IndexIterator &operator<<(IndexIterator &&it, Callable cb)
+{
+ return it.iter(cb);
+}
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_INDEX_ITERATOR_H__
diff --git a/runtime/libs/misc/include/misc/tensor/NonIncreasingStride.h b/runtime/libs/misc/include/misc/tensor/NonIncreasingStride.h
new file mode 100644
index 000000000..3bc0c115c
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/NonIncreasingStride.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file NonIncreasingStride.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::NonIncreasingStride class
+ */
+#ifndef __NNFW_MISC_TENSOR_NON_INCREASING_STRIDE_H__
+#define __NNFW_MISC_TENSOR_NON_INCREASING_STRIDE_H__
+
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Index.h"
+
+#include <vector>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to represent strides where stride[N-1] >= stride[N] holds for all N < rank
+ */
+class NonIncreasingStride
+{
+public:
+ /**
+ * @brief Initialize the stride data using @c Shape
+ * @param[in] shape to build stride info
+ * @return N/A
+ */
+ void init(const Shape &shape)
+ {
+ _stride.resize(shape.rank());
+
+ // Scalar
+ if (shape.rank() == 0)
+ return;
+
+ _stride.at(shape.rank() - 1) = 1;
+
+ for (uint32_t axis = shape.rank() - 1; axis > 0; --axis)
+ {
+ _stride.at(axis - 1) = _stride.at(axis) * shape.dim(axis);
+ }
+ }
+
+public:
+ /**
+ * @brief Get an stride value for specific axis
+ * @param[in] axis Axis of stride
+ * @return The value of stride
+ */
+ uint32_t at(uint32_t axis) const { return _stride.at(axis); }
+
+public:
+ /**
+ * @brief Get the 1-D offset of specified index for n-D tensor
+ * @param index @c Index object
+ * @return 1-D offset of index
+ */
+ uint32_t offset(const Index &index) const;
+
+private:
+ std::vector<uint32_t> _stride;
+};
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_NON_INCREASING_STRIDE_H__
diff --git a/runtime/libs/misc/include/misc/tensor/Object.h b/runtime/libs/misc/include/misc/tensor/Object.h
new file mode 100644
index 000000000..cba4f1baf
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/Object.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Object.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::Object class
+ */
+
+#ifndef __NNFW_MISC_TENSOR_OBJECT_H__
+#define __NNFW_MISC_TENSOR_OBJECT_H__
+
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Index.h"
+#include "misc/tensor/IndexIterator.h"
+#include "misc/tensor/NonIncreasingStride.h"
+#include "misc/tensor/Reader.h"
+
+#include <vector>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to build a tensor using specific generator
+ * @tparam T Type of tensor element
+ */
+
+template <typename T> class Object final : public Reader<T>
+{
+public:
+ /**
+ * @brief Function to generate tensor element
+ */
+ using Generator = std::function<T(const Shape &shape, const Index &index)>;
+
+public:
+ /**
+ * @brief Construct a new @c Object object
+ * @param[in] shape Tensor shape
+ * @param[in] fn Function to generate tensor elements
+ */
+ Object(const Shape &shape, const Generator &fn) : _shape{shape}
+ {
+ // Set 'stride'
+ _stride.init(shape);
+
+ // Handle scalar object
+ if (shape.rank() == 0)
+ {
+ _values.resize(1);
+ _values.at(0) = fn(_shape, 0);
+ }
+ else
+ {
+ // Pre-allocate buffer
+ _values.resize(_shape.dim(0) * _stride.at(0));
+
+ // Set 'value'
+ iterate(_shape) << [this, &fn](const Index &index) {
+ _values.at(_stride.offset(index)) = fn(_shape, index);
+ };
+ }
+ }
+
+public:
+ /**
+ * @brief Get reference of shape
+ * @return Reference of shape
+ */
+ const Shape &shape(void) const { return _shape; }
+
+public:
+ /**
+ * @brief Get and element of tensor
+ * @param[in] index Index of a tensor element
+ * @return Value of tensor element
+ */
+ T at(const Index &index) const override { return _values.at(_stride.offset(index)); }
+
+private:
+ Shape _shape;
+ NonIncreasingStride _stride;
+
+private:
+ std::vector<T> _values;
+};
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_FEATURE_OBJECT_H__
diff --git a/runtime/libs/misc/include/misc/tensor/Reader.h b/runtime/libs/misc/include/misc/tensor/Reader.h
new file mode 100644
index 000000000..9175a913e
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/Reader.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::Reader struct
+ */
+
+#ifndef __NNFW_MISC_TENSOR_READER_H__
+#define __NNFW_MISC_TENSOR_READER_H__
+
+#include "misc/tensor/Index.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Struct to read element of tensor
+ * @tparam T Type of elements in tensor
+ */
+template <typename T> struct Reader
+{
+ /**
+ * @brief Destroy the Reader object
+ */
+ virtual ~Reader() = default;
+
+ /**
+ * @brief Get an element of tensor
+ * @param[in] index Index specifying indexes of tensor element
+ * @return The value of specificed element
+ */
+ virtual T at(const Index &index) const = 0;
+};
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_READER_H__
diff --git a/runtime/libs/misc/include/misc/tensor/Shape.h b/runtime/libs/misc/include/misc/tensor/Shape.h
new file mode 100644
index 000000000..bd0eac0a5
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/Shape.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Shape.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::Shape class
+ */
+
+#ifndef __NNFW_MISC_TENSOR_SHAPE_H__
+#define __NNFW_MISC_TENSOR_SHAPE_H__
+
+#include <cstdint>
+#include <cstddef>
+#include <deque>
+#include <initializer_list>
+#include <ostream>
+#include <string>
+#include <cassert>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to represent shape of a tensor
+ */
+class Shape
+{
+public:
+ /**
+ * @brief Construct a new Shape object
+ * @param[in] rank Rank of a tensor
+ */
+ Shape(uint32_t rank) { _dimensions.resize(rank); }
+
+public:
+ /**
+ * @brief Construct a new Shape object
+ * @param[in] dimensions @c initializer_list<int32_t> of dimensions of tensor
+ */
+ Shape(const std::initializer_list<int32_t> &dimensions) : _dimensions{dimensions}
+ {
+ // Check overflow because initializer_list type can be larger size than max of uint32_t
+ assert(dimensions.size() <= 0xFFFFFFFF);
+ }
+
+ /**
+ * @brief Construct a new Shape object
+ * @param[in] origin @c Shape object to copy
+ */
+ Shape(const Shape &origin) = default;
+
+public:
+ /**
+ * @brief Add dimension to the beginning
+ * @param[in] d dimension to add to the beginning
+ * @return N/A
+ */
+ void prepend(int32_t d) { _dimensions.emplace_front(d); }
+
+ /**
+ * @brief Add dimension to the back
+ * @param[in] d dimension to add to the back
+ * @return N/A
+ */
+ void append(int32_t d) { _dimensions.emplace_back(d); }
+
+public:
+ /**
+ * @brief Get the rank of this shape
+ * @return rank
+ * @note We can use static_cast\n
+ * because we don't support larger than max of uint32_t on constructor
+ */
+ uint32_t rank(void) const { return static_cast<uint32_t>(_dimensions.size()); }
+
+public:
+ /**
+ * @brief Get specific dimension
+ * @param[in] n Index of dimension
+ * @return n'th dimension
+ */
+ int32_t dim(uint32_t n) const { return _dimensions.at(n); }
+
+ /**
+ * @brief Get the reference of specific dimension
+ * @param[in] n Index of dimension
+ * @return Reference of n'th dimension
+ */
+ int32_t &dim(uint32_t n) { return _dimensions.at(n); }
+
+ const std::deque<int32_t> &dims() const { return _dimensions; }
+
+public:
+ /**
+ * @brief Get the number of elements specified by this shape
+ * @return The number of elements
+ */
+ uint64_t num_elements() const;
+
+private:
+ std::deque<int32_t> _dimensions;
+
+public:
+ /**
+ * @brief Get a @c Shape object after parsing string
+ * @param[in] s String of dimension list. Accepted format is numbers separated by comma.
+ * @return @c Shape object
+ */
+ static Shape from(const std::string &s);
+};
+
+/**
+ * @brief Check equality of two @c Shape
+ * @param[in] Shape First shape to compare
+ * @param[in] Shape Second shape to compare
+ * @return @c true if both shapes are equal, otherwise @c false
+ */
+bool operator==(const Shape &, const Shape &);
+
+/**
+ * @brief Send @c Shape to @c std::ostream
+ * @param[in] os @c std::ostream to process this @c Shape
+ * @param[in] shape @c Shape to send to @c ostream
+ * @return Reference of @c std::ostream
+ */
+std::ostream &operator<<(std::ostream &os, const Shape &shape);
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_SHAPE_H__
diff --git a/runtime/libs/misc/include/misc/tensor/Zipper.h b/runtime/libs/misc/include/misc/tensor/Zipper.h
new file mode 100644
index 000000000..8f0ec4ab6
--- /dev/null
+++ b/runtime/libs/misc/include/misc/tensor/Zipper.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Zipper.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains nnfw::misc::tensor::Zipper class
+ */
+
+#ifndef __NNFW_MISC_TENSOR_ZIPPER_H__
+#define __NNFW_MISC_TENSOR_ZIPPER_H__
+
+#include "misc/tensor/Index.h"
+#include "misc/tensor/IndexIterator.h"
+#include "misc/tensor/Reader.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to apply a function with three params: @c Index, elements of a tensor
+ * at passed index read by @c Reader objects
+ */
+template <typename T> class Zipper
+{
+public:
+ /**
+ * @brief Construct a new @c Zipper object
+ * @param[in] shape Shape of @c lhs and @c rhs
+ * @param[in] lhs @c Reader object of a tensor
+ * @param[in] rhs @c Reader object of a tensor
+ */
+ Zipper(const Shape &shape, const Reader<T> &lhs, const Reader<T> &rhs)
+ : _shape{shape}, _lhs{lhs}, _rhs{rhs}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Apply @c cb to all elements of tensors. Elements of two tensors
+ * at passed @c index are read by @c lhs and @c rhs
+ * @param[in] cb Function to apply
+ * @return N/A
+ */
+ template <typename Callable> void zip(Callable cb) const
+ {
+ iterate(_shape) <<
+ [this, &cb](const Index &index) { cb(index, _lhs.at(index), _rhs.at(index)); };
+ }
+
+private:
+ const Shape &_shape;
+ const Reader<T> &_lhs;
+ const Reader<T> &_rhs;
+};
+
+/**
+ * @brief Apply @c cb by using @c lhs and @c rhs passed to the constructor of @c zipper
+ * @param[in] zipper @c Zipper object
+ * @param[in] cb Function to zpply using @c zip function
+ * @return @c zipper object after applying @c cb to @c zipper
+ */
+template <typename T, typename Callable>
+const Zipper<T> &operator<<(const Zipper<T> &zipper, Callable cb)
+{
+ zipper.zip(cb);
+ return zipper;
+}
+
+/**
+ * @brief Get @c Zipper object constructed using passed params
+ * @param shape Shape of @c lhs and @c rhs
+ * @param lhs @c Reader object of a tensor
+ * @param rhs @c Reader object of a tensor
+ * @return @c Zipper object
+ */
+template <typename T> Zipper<T> zip(const Shape &shape, const Reader<T> &lhs, const Reader<T> &rhs)
+{
+ return Zipper<T>{shape, lhs, rhs};
+}
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_TENSOR_ZIPPER_H__
diff --git a/runtime/libs/misc/include/misc/vector.h b/runtime/libs/misc/include/misc/vector.h
new file mode 100644
index 000000000..395b08912
--- /dev/null
+++ b/runtime/libs/misc/include/misc/vector.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file vector.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file contains @c == operator to check equality of elements in two vectors
+ */
+#ifndef __NNFW_MISC_VECTOR_H__
+#define __NNFW_MISC_VECTOR_H__
+
+#include <vector>
+
+/**
+ * @brief Compare elements of two vectors
+ * @tparam T Type of elements in vectors
+ * @param[in] lhs First vector to compare
+ * @param[in] rhs Second vector to compare
+ * @return @c true if all elements are equal, otherwise @c false.
+ */
+template <typename T> bool operator==(const std::vector<T> &lhs, const std::vector<T> &rhs)
+{
+ if (lhs.size() != rhs.size())
+ {
+ return false;
+ }
+
+ for (size_t ind = 0; ind < lhs.size(); ++ind)
+ {
+ if (lhs.at(ind) != rhs.at(ind))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#endif // __NNFW_MISC_VECTOR_H__
diff --git a/runtime/libs/misc/include/misc/vector/Object.h b/runtime/libs/misc/include/misc/vector/Object.h
new file mode 100644
index 000000000..65d4bc613
--- /dev/null
+++ b/runtime/libs/misc/include/misc/vector/Object.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Object.h
+ * @brief This file contains Object class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_VECTOR_OBJECT_H__
+#define __NNFW_MISC_VECTOR_OBJECT_H__
+
+#include "misc/vector/Reader.h"
+
+#include <vector>
+#include <functional>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace vector
+{
+
+/**
+ * @brief Class to have information of the operand for vector
+ */
+template <typename T> class Object final : public Reader<T>
+{
+public:
+ using Generator = std::function<T(int32_t size, int32_t offset)>;
+
+public:
+ /**
+ * @brief Construct Object object with size of vector and set value used by Generator
+ * @param[in] size The size of vector
+ * @param[in] gen A function to set values of operand tensor
+ */
+ Object(int32_t size, const Generator &gen) : _size{size}
+ {
+ _value.resize(_size);
+
+ for (int32_t offset = 0; offset < size; ++offset)
+ {
+ _value.at(offset) = gen(size, offset);
+ }
+ }
+
+public:
+ /**
+ * @brief Get size of vector
+ * @return Size of vector
+ */
+ int32_t size(void) const { return _size; }
+
+public:
+ /**
+ * @brief Get the value used by index
+ * @param[in] nth The vector index
+ * @return The value at the offset
+ */
+ T at(uint32_t nth) const override { return _value.at(nth); }
+
+private:
+ /**
+ * @brief Size of vector
+ */
+ const int32_t _size;
+ /**
+ * @brief The tensor vector of operand
+ */
+ std::vector<T> _value;
+};
+
+} // namespace vector
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_VECTOR_OBJECT_H__
diff --git a/runtime/libs/misc/include/misc/vector/Reader.h b/runtime/libs/misc/include/misc/vector/Reader.h
new file mode 100644
index 000000000..eab4c427b
--- /dev/null
+++ b/runtime/libs/misc/include/misc/vector/Reader.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @brief This file contains Reader class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_MISC_VECTOR_READER_H__
+#define __NNFW_MISC_VECTOR_READER_H__
+
+#include <cstdint>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace vector
+{
+
+/**
+ * @brief Class reads values of vector
+ * The interface class
+ */
+template <typename T> struct Reader
+{
+ /**
+ * @brief Destruct Reader object using default destructor
+ */
+ virtual ~Reader() = default;
+
+ /**
+ * @brief Get the value used by the index
+ * @param[in] nth The vector index
+ * @return The value at the offset
+ */
+ virtual T at(uint32_t nth) const = 0;
+};
+
+} // namespace vector
+} // namespace misc
+} // namespace nnfw
+
+#endif // __NNFW_MISC_VECTOR_READER_H__
diff --git a/runtime/libs/misc/src/RandomGenerator.cpp b/runtime/libs/misc/src/RandomGenerator.cpp
new file mode 100644
index 000000000..e7fbc10ca
--- /dev/null
+++ b/runtime/libs/misc/src/RandomGenerator.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "misc/RandomGenerator.h"
+
+namespace nnfw
+{
+namespace misc
+{
+
+template <> uint8_t RandomGenerator::generate<uint8_t>(void)
+{
+ // The value of type_range is 255.
+ float type_range = static_cast<float>(std::numeric_limits<uint8_t>::max()) -
+ static_cast<float>(std::numeric_limits<uint8_t>::min());
+ // Most _dist values range from -5.0 to 5.0.
+ float min_range = -5.0f;
+ float max_range = 5.0f;
+ // NOTE shifted_relative_val has Gaussian distribution that origin mean was 0 and standard
+ // deviation was 2. And then its values are distributed and shift to that mean is 127.5 and range
+ // is about [0, 255].
+ float shifted_relative_val = (_dist(_rand) - min_range) * type_range / (max_range - min_range);
+
+ // shifted_relative_val is adjusted to be mapped to end points of the range, if it is out of range
+ // values.
+ if (shifted_relative_val < 0.0f)
+ {
+ return 0;
+ }
+ else if (shifted_relative_val > type_range)
+ {
+ return 255;
+ }
+
+ // Convert shifted_relative_val from float to uint8
+ return static_cast<uint8_t>(shifted_relative_val);
+}
+
+template <> bool RandomGenerator::generate<bool>(void)
+{
+ std::uniform_int_distribution<> dist(0, 1); // [0, 1]
+ return dist(_rand);
+}
+
+template <> int32_t RandomGenerator::generate<int32_t>(void)
+{
+ // Instead of INT_MAX, 99 is chosen because int32_t input does not mean
+ // that the model can have any value in int32_t can hold.
+ // For example, one_hot operation gets indices as int32_t tensor.
+ // However, we usually expect it would hold a value in [0..depth).
+ // In our given model, depth was 10137.
+ const int int32_random_max = 99;
+ std::uniform_int_distribution<> dist(0, int32_random_max);
+ return dist(_rand);
+}
+
+template <> int64_t RandomGenerator::generate<int64_t>(void)
+{
+ // Instead of INT_MAX, 99 is chosen because int64_t input does not mean
+ // that the model can have any value in int64_t can hold.
+ // For example, one_hot operation gets indices as int64_t tensor.
+ // However, we usually expect it would hold a value in [0..depth).
+ // In our given model, depth was 10137.
+ const int64_t int64_random_max = 99;
+ std::uniform_int_distribution<> dist(0, int64_random_max);
+ return dist(_rand);
+}
+
+} // namespace misc
+} // namespace nnfw
diff --git a/runtime/libs/misc/src/tensor/Comparator.cpp b/runtime/libs/misc/src/tensor/Comparator.cpp
new file mode 100644
index 000000000..80a18c11a
--- /dev/null
+++ b/runtime/libs/misc/src/tensor/Comparator.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "misc/tensor/Comparator.h"
+#include "misc/tensor/Zipper.h"
+
+#include "misc/fp32.h"
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+std::vector<Diff<float>> Comparator::compare(const Shape &shape, const Reader<float> &expected,
+ const Reader<float> &obtained,
+ Observer *observer) const
+{
+ std::vector<Diff<float>> res;
+
+ zip(shape, expected, obtained) <<
+ [&](const Index &index, float expected_value, float obtained_value) {
+ if (!_compare_fn(expected_value, obtained_value))
+ {
+ res.emplace_back(index, expected_value, obtained_value);
+ }
+
+ // Update max_diff_index, if necessary
+ if (observer != nullptr)
+ {
+ observer->notify(index, expected_value, obtained_value);
+ }
+ };
+
+ return res;
+}
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
diff --git a/runtime/libs/misc/src/tensor/IndexFormatter.cpp b/runtime/libs/misc/src/tensor/IndexFormatter.cpp
new file mode 100644
index 000000000..c949db7a8
--- /dev/null
+++ b/runtime/libs/misc/src/tensor/IndexFormatter.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "misc/tensor/IndexFormatter.h"
+
+#include <cassert>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+std::ostream &operator<<(std::ostream &os, const IndexFormatter &fmt)
+{
+ const auto rank = fmt.index().rank();
+
+ assert(rank > 0);
+
+ os << fmt.index().at(0);
+
+ if (rank > 1)
+ {
+ for (uint32_t axis = 1; axis < rank; ++axis)
+ {
+ os << ", " << fmt.index().at(axis);
+ }
+ }
+
+ return os;
+}
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
diff --git a/runtime/libs/misc/src/tensor/NonIncreasingStride.cpp b/runtime/libs/misc/src/tensor/NonIncreasingStride.cpp
new file mode 100644
index 000000000..c51ad0324
--- /dev/null
+++ b/runtime/libs/misc/src/tensor/NonIncreasingStride.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "misc/tensor/NonIncreasingStride.h"
+
+#include <cassert>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+uint32_t NonIncreasingStride::offset(const Index &index) const
+{
+ const size_t rank = _stride.size();
+
+ assert(index.rank() == rank);
+
+ uint32_t offset = 0;
+
+ for (size_t axis = 0; axis < rank; ++axis)
+ {
+ offset += _stride.at(axis) * index.at(axis);
+ }
+
+ return offset;
+}
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
diff --git a/runtime/libs/misc/src/tensor/Shape.cpp b/runtime/libs/misc/src/tensor/Shape.cpp
new file mode 100644
index 000000000..70d3bdfdb
--- /dev/null
+++ b/runtime/libs/misc/src/tensor/Shape.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "misc/tensor/Shape.h"
+
+#include <cassert>
+#include <functional>
+#include <numeric>
+
+namespace nnfw
+{
+namespace misc
+{
+namespace tensor
+{
+
+bool operator==(const Shape &lhs, const Shape &rhs)
+{
+ if (lhs.rank() != rhs.rank())
+ {
+ return false;
+ }
+
+ for (uint32_t axis = 0; axis < lhs.rank(); ++axis)
+ {
+ if (lhs.dim(axis) != rhs.dim(axis))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+Shape Shape::from(const std::string &str)
+{
+ Shape shape(0);
+
+ bool pending = false;
+ int value = 0;
+
+ for (const char *cur = str.c_str(); true; ++cur)
+ {
+ if (*cur == ',' || *cur == '\0')
+ {
+ if (pending)
+ {
+ shape.append(value);
+ }
+
+ if (*cur == '\0')
+ {
+ break;
+ }
+
+ pending = false;
+ value = 0;
+ continue;
+ }
+
+ assert(*cur >= '0' && *cur <= '9');
+
+ pending = true;
+ value *= 10;
+ value += *cur - '0';
+ }
+
+ return shape;
+}
+
+uint64_t Shape::num_elements() const
+{
+ return std::accumulate(_dimensions.cbegin(), _dimensions.cend(), UINT64_C(1),
+ std::multiplies<uint64_t>());
+}
+
+std::ostream &operator<<(std::ostream &os, const Shape &shape)
+{
+ if (shape.rank() > 0)
+ {
+ os << shape.dim(0);
+
+ for (uint32_t axis = 1; axis < shape.rank(); ++axis)
+ {
+ os << "," << shape.dim(axis);
+ }
+ }
+
+ return os;
+}
+
+} // namespace tensor
+} // namespace misc
+} // namespace nnfw
diff --git a/runtime/libs/nnapi/CMakeLists.txt b/runtime/libs/nnapi/CMakeLists.txt
new file mode 100644
index 000000000..73f82b909
--- /dev/null
+++ b/runtime/libs/nnapi/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(nnfw_lib_nnapi INTERFACE)
+
+target_include_directories(nnfw_lib_nnapi INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(nnfw_lib_nnapi INTERFACE nnfw-nnapi-header)
diff --git a/runtime/libs/nnapi/include/NeuralNetworksExShim.h b/runtime/libs/nnapi/include/NeuralNetworksExShim.h
new file mode 100644
index 000000000..855613241
--- /dev/null
+++ b/runtime/libs/nnapi/include/NeuralNetworksExShim.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file NeuralNetworksExShim.h
+ * @brief This file contains an actual implementation of
+ * ANeuralNetworksModel_addOperationEx function
+ */
+
+#ifndef __NEURAL_NETWORKS_EX_SHIM_H__
+#define __NEURAL_NETWORKS_EX_SHIM_H__
+
+#include "NeuralNetworks.h"
+#include "NeuralNetworksEx.h"
+#include "NeuralNetworksLoadHelpers.h"
+
+typedef int (*ANeuralNetworksModel_addOperationEx_fn)(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationTypeEx type,
+ uint32_t inputCount, const uint32_t *inputs,
+ uint32_t outputCount,
+ const uint32_t *outputs);
+
+/**
+ * @brief Add an extended operation to a model.
+ *
+ * @param[in] model The model to be modified.
+ * @param[in] type The type of extended operation.
+ * @param[in] inputCount The number of entries in the inputs array.
+ * @param[in] inputs An array of indexes identifying each operand.
+ * @param[in] outputCount The number of entries in the outputs array.
+ * @param[in] outputs An array of indexes identifying each operand.
+ *
+ * @note The operands specified by inputs and outputs must have been
+ * previously added by calls to {@link ANeuralNetworksModel_addOperand}.\n
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish}
+ * has been called will return an error.\n
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+
+inline int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationTypeEx type,
+ uint32_t inputCount, const uint32_t *inputs,
+ uint32_t outputCount, const uint32_t *outputs)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_addOperationEx);
+ EXECUTE_FUNCTION_RETURN(model, type, inputCount, inputs, outputCount, outputs);
+}
+
+#endif // __NEURAL_NETWORKS_EX_SHIM_H__
diff --git a/runtime/libs/nnapi/include/NeuralNetworksLoadHelpers.h b/runtime/libs/nnapi/include/NeuralNetworksLoadHelpers.h
new file mode 100644
index 000000000..1c482b54c
--- /dev/null
+++ b/runtime/libs/nnapi/include/NeuralNetworksLoadHelpers.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This header is derived from part of the following file (in TensorFlow v1.12)
+// 'externals/tensorflow/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h'
+
+/**
+ * @file NeuralNetworksLoadHelpers.h
+ * @brief This file contains functions to load NN API runtime library
+ */
+
+#ifndef __NEURAL_NETWORKS_LOAD_HELPER_H__
+#define __NEURAL_NETWORKS_LOAD_HELPER_H__
+
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * @brief Print log data
+ * @param[in] format Format string of @c printf
+ * @param[in] args Argument after format string. (Same with @c printf)
+ */
+#define NNAPI_LOG(format, ...) printf(format "\n", __VA_ARGS__);
+
+/**
+ * @brief Create a function pointer named @c fn after loading NN API library
+ * @param[in] name Name of a function
+ */
+#define LOAD_FUNCTION(name) \
+ static name##_fn fn = reinterpret_cast<name##_fn>(nnfw::loadFunction(#name));
+
+/**
+ * @brief Run @c fn function. @c fn is created by @ref LOAD_FUNCTION
+ * @param[in] args List of arguments for the function @c fn
+ */
+#define EXECUTE_FUNCTION(...) \
+ if (fn != nullptr) { \
+ fn(__VA_ARGS__); \
+ }
+
+/**
+ * @brief Run @c fn function. @c fn is created by @ref LOAD_FUNCTION
+ * @param[in] args List of arguments for the function @c fn
+ * @return the return value of @c fn
+ */
+#define EXECUTE_FUNCTION_RETURN(...) return fn != nullptr ? fn(__VA_ARGS__) : 0;
+
+namespace nnfw
+{
+
+/**
+ * @brief Load NN API library
+ * @param[in] name path of NN API library
+ * @return a symbol table handle of NN API library
+ */
+inline void* loadLibrary(const char* name) {
+ // TODO: change RTLD_LOCAL? Assumes there can be multiple instances of nn
+ // api RT
+ void* handle = nullptr;
+#if 1 //#ifdef __ANDROID__
+ handle = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
+ if (handle == nullptr) {
+ NNAPI_LOG("nnapi error: unable to open library %s", name);
+ }
+#endif
+ return handle;
+}
+
+/**
+ * @brief Load libneuralnetworks.so and return handle of library
+ * @return a symbol table handle of NN API library
+ */
+inline void* getLibraryHandle() {
+ static void* handle = loadLibrary("libneuralnetworks.so");
+ return handle;
+}
+
+/**
+ * @brief Return function ptr in libneuralnetworks.so
+ * @param[in] name Name of function
+ * @return function pointer
+ */
+inline void* loadFunction(const char* name) {
+ void* fn = nullptr;
+ if (getLibraryHandle() != nullptr) {
+ fn = dlsym(getLibraryHandle(), name);
+ }
+ if (fn == nullptr) {
+ NNAPI_LOG("nnapi error: unable to open function %s", name);
+ abort();
+ }
+ else {
+#ifdef _GNU_SOURCE
+ Dl_info info;
+ if (dladdr(fn, &info))
+ {
+ NNAPI_LOG("nnapi function '%s' is loaded from '%s' ", name, info.dli_fname);
+ }
+ else
+ {
+ NNAPI_LOG("nnapi function '%s' is failed to load", name);
+ }
+#endif // _GNU_SOURCE
+ }
+ return fn;
+}
+
+/**
+ * @brief Check if libneuralnetworks.so can be loaded
+ * @return @c true if loading is successful, otherwise @c false.
+ */
+inline bool NNAPIExists() {
+ static bool nnapi_is_available = getLibraryHandle();
+ return nnapi_is_available;
+}
+
+} // namespace nnfw
+
+#endif // __NEURAL_NETWORKS_LOAD_HELPER_H__
diff --git a/runtime/libs/nnapi/include/NeuralNetworksShim.h b/runtime/libs/nnapi/include/NeuralNetworksShim.h
new file mode 100644
index 000000000..9cf52aafa
--- /dev/null
+++ b/runtime/libs/nnapi/include/NeuralNetworksShim.h
@@ -0,0 +1,1554 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// NOTE This header is derived from part of the following file
+// https://github.com/tensorflow/tensorflow/blob/v2.3.0/tensorflow/lite/nnapi/NeuralNetworksShim.h
+
+#ifndef __NEURAL_NETWORKS_SHIM_H__
+#define __NEURAL_NETWORKS_SHIM_H__
+
+#include "NeuralNetworksTypes.h"
+#include "NeuralNetworksLoadHelpers.h"
+
+// This interface is now deprecated. You should use instead
+// nnapi_implementation.
+
+// TODO(b/123017568): Update all current usages of this file.
+
+// NN api types based on NNAPI header file
+// https://developer.android.com/ndk/reference/group/neural-networks
+
+/**
+ * Creates a shared memory object from a file descriptor.
+ *
+ * The shared memory is backed by a file descriptor via mmap.
+ * See {@link ANeuralNetworksMemory} for a description on how to use
+ * this shared memory.
+ *
+ * @param size The requested size in bytes.
+ * Must not be larger than the file size.
+ * @param prot The desired memory protection for the mapping.
+ * It is either PROT_NONE or the bitwise OR of one or
+ * more of the following flags: PROT_READ, PROT_WRITE.
+ * @param fd The requested file descriptor.
+ * The file descriptor has to be mmap-able. The file
+ * descriptor will be duplicated.
+ * @param offset The offset to the beginning of the file of the area to map.
+ * The offset has to be aligned to a page size.
+ * @param memory The memory object to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the request completed normally.
+ */
+inline int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset,
+ ANeuralNetworksMemory **memory)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemory_createFromFd);
+ EXECUTE_FUNCTION_RETURN(size, protect, fd, offset, memory);
+}
+
+/**
+ * Delete a memory object.
+ *
+ * Destroys the object used by the run time to keep track of the memory.
+ * This will free the underlying actual memory if no other code has open
+ * handles to this memory.
+ *
+ * @param memory The memory object to be freed.
+ */
+inline void ANeuralNetworksMemory_free(ANeuralNetworksMemory *memory)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemory_free);
+ EXECUTE_FUNCTION(memory);
+}
+
+/**
+ * Create an empty {@link ANeuralNetworksModel}.
+ *
+ * <p>This only creates the object. Computation is performed once
+ * {@link ANeuralNetworksExecution_startCompute} is invoked.
+ *
+ * The model should be constructed with calls to
+ * {@link ANeuralNetworksModel_addOperation} and
+ * {@link ANeuralNetworksModel_addOperand}
+ *
+ * <p>{@link ANeuralNetworksModel_finish} should be called once the model
+ * has been fully constructed.</p>
+ *
+ * <p>{@link ANeuralNetworksModel_free} should be called once the model
+ * is no longer needed.</p>
+ *
+ * @param model The {@link ANeuralNetworksModel} to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_create(ANeuralNetworksModel **model)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_create);
+ EXECUTE_FUNCTION_RETURN(model);
+}
+
+/**
+ * Destroy a model.
+ *
+ * The model need not have been finished by a call to
+ * {@link ANeuralNetworksModel_finish}.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * @param model The model to be destroyed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+inline void ANeuralNetworksModel_free(ANeuralNetworksModel *model)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_free);
+ EXECUTE_FUNCTION(model);
+}
+
+/**
+ * Indicate that we have finished modifying a model. Required before
+ * calling {@link ANeuralNetworksCompilation_compile}.
+ *
+ * An application is responsible to make sure that no other thread uses
+ * the model at the same time.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * @param model The model to be finished.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_finish(ANeuralNetworksModel *model)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_finish);
+ EXECUTE_FUNCTION_RETURN(model);
+}
+
+/**
+ * Add an operand to a model.
+ *
+ * The order in which the operands are added is important. The first one added
+ * to a model will have the index value 0, the second 1, etc. These indexes are
+ * used as operand identifiers in {@link ANeuralNetworksModel_addOperation},
+ * {@link ANeuralNetworksExecution_setInput},
+ * {@link ANeuralNetworksExecution_setInputFromMemory},
+ * {@link ANeuralNetworksExecution_setOutput},
+ * {@link ANeuralNetworksExecution_setOutputFromMemory} and
+ * {@link ANeuralNetworksExecution_setOperandValue}.
+ *
+ * To build a model that can accommodate inputs of various sizes, as you may
+ * want to do for a CNN, set the size of the dimensions that will vary at run
+ * time to 0. If you do so, provide the full dimensions when calling
+ * {@link ANeuralNetworksExecution_setInput} or {@link
+ * ANeuralNetworksExecution_setInputFromMemory}.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has
+ * been called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * @param model The model to be modified.
+ * @param type The {@link ANeuralNetworksOperandType} that describes the shape
+ * of the operand.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model,
+ const ANeuralNetworksOperandType *type)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_addOperand);
+ EXECUTE_FUNCTION_RETURN(model, type);
+}
+
+/**
+ * Sets an operand to a constant value.
+ *
+ * For scalar values, the content of buffer is copied into the model.
+ *
+ * For tensor values, a pointer to the buffer is stored within the model.
+ * The application is responsible for not changing the content of this region
+ * until all executions using this model have completed. As the data may
+ * be copied during processing, modifying the data after this call yields
+ * undefined results.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has
+ * been called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param buffer A pointer to the data to use.
+ * @param length The size in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index,
+ const void *buffer, size_t length)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_setOperandValue);
+ EXECUTE_FUNCTION_RETURN(model, index, buffer, length);
+}
+
+/**
+ * Sets an operand's per channel quantization parameters.
+ *
+ * Sets parameters required by a tensor of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}.
+ * This function must be called for every tensor of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} before
+ * calling {@link ANeuralNetworksModel_finish}.
+ *
+ * Available since API level 29.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param channelQuant The per channel quantization parameters for the operand.
+ * No memory in this struct needs to outlive the call to
+ * this function.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(
+ ANeuralNetworksModel *model, int32_t index,
+ const ANeuralNetworksSymmPerChannelQuantParams *channelQuant)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams);
+ EXECUTE_FUNCTION_RETURN(model, index, channelQuant);
+}
+
+/**
+ * Sets an operand to a value stored in a memory object.
+ *
+ * The content of the memory is not copied. A reference to that memory is stored
+ * inside the model. The application is responsible for not changing the content
+ * of the memory region until all executions using this model have completed.
+ * As the data may be copied during processing, modifying the data after this
+ * call yields undefined results.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has
+ * been called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param buffer A pointer to the data to use.
+ * @param memory The memory containing the data.
+ * @param offset This specifies the location of the data within the memory.
+ * The offset is in bytes from the start of memory.
+ * @param length The size in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model,
+ int32_t index,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_setOperandValueFromMemory);
+ EXECUTE_FUNCTION_RETURN(model, index, memory, offset, length);
+}
+
+/**
+ * Add an operation to a model.
+ *
+ * @param model The model to be modified.
+ * @param type The type of the operation.
+ * @param inputCount The number of entries in the inputs array.
+ * @param inputs An array of indexes identifying each operand.
+ * @param outputCount The number of entries in the outputs array.
+ * @param outputs An array of indexes identifying each operand.
+ *
+ * The operands specified by inputs and outputs must have been
+ * previously added by calls to {@link ANeuralNetworksModel_addOperand}.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has
+ * been called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationType type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_addOperation);
+ EXECUTE_FUNCTION_RETURN(model, type, inputCount, inputs, outputCount, outputs);
+}
+
+/**
+ * Specifies which operands will be the model's inputs and outputs.
+ *
+ * An operand cannot be used for both input and output. Doing so will
+ * return an error.
+ *
+ * @param model The model to be modified.
+ * @param inputCount The number of entries in the inputs array.
+ * @param inputs An array of indexes identifying the input operands.
+ * @param outputCount The number of entries in the outputs array.
+ * @param outputs An array of indexes identifying the output operands.
+ *
+ * The operands specified by inputs and outputs must have been
+ * previously added by calls to {@link ANeuralNetworksModel_addOperand}.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has
+ * been called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ */
+inline int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model,
+ uint32_t inputCount,
+ const uint32_t *inputs,
+ uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_identifyInputsAndOutputs);
+ EXECUTE_FUNCTION_RETURN(model, inputCount, inputs, outputCount, outputs);
+}
+
+/**
+ * Specifies whether {@link ANEURALNETWORKS_TENSOR_FLOAT32} is allowed to be
+ * calculated with range and/or precision as low as that of the IEEE 754 16-bit
+ * floating-point format. By default, {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * must be calculated using at least the range and precision of the IEEE 754
+ * 32-bit floating-point format.
+ *
+ * @param model The model to be modified.
+ * @param allow 'true' indicates {@link ANEURALNETWORKS_TENSOR_FLOAT32} may be
+ * calculated with range and/or precision as low as that of the
+ * IEEE 754 16-bit floating point format. 'false' indicates
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32} must be calculated using
+ * at least the range and precision of the IEEE 754 32-bit floating
+ * point format.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has
+ * been called will return an error.
+ *
+ * Available since API level 28.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ */
+inline int ANeuralNetworksModel_relaxComputationFloat32toFloat16(ANeuralNetworksModel *model,
+ bool allow)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_relaxComputationFloat32toFloat16);
+ EXECUTE_FUNCTION_RETURN(model, allow);
+}
+
+/**
+ * Create a {@link ANeuralNetworksCompilation} to compile the given model.
+ * This only creates the object. Compilation is only performed once
+ * {@link ANeuralNetworksCompilation_start} is invoked.
+ *
+ * <p>The provided model must outlive the compilation.</p>
+ *
+ * The model must already have been finished by a call to
+ * {@link ANeuralNetworksModel_finish}.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded
+ * usage.
+ *
+ * @param model The {@link ANeuralNetworksModel} to be compiled.
+ * @param compilation The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA
+ * if the model is invalid.
+ */
+inline int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model,
+ ANeuralNetworksCompilation **compilation)
+{
+ LOAD_FUNCTION(ANeuralNetworksCompilation_create);
+ EXECUTE_FUNCTION_RETURN(model, compilation);
+}
+
+/**
+ * Destroy a compilation.
+ *
+ * <p>If called on a compilation for which
+ * {@link ANeuralNetworksCompilation_start} has been called, the
+ * function will return immediately but will mark the compilation to be deleted
+ * once the compilation completes. The {@link ANeuralNetworksCompilation_wait}
+ * will return ERROR_DELETED.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded
+ * usage.
+ *
+ * @param compilation The compilation to be destroyed. Passing NULL is
+ * acceptable and results in no operation.
+ */
+inline void ANeuralNetworksCompilation_free(ANeuralNetworksCompilation *compilation)
+{
+ LOAD_FUNCTION(ANeuralNetworksCompilation_free);
+ EXECUTE_FUNCTION(compilation);
+}
+
+/**
+ * Sets the execution preference.
+ *
+ * <p>Provides guidance to the runtime when trade-offs are possible.</p>
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded
+ * usage.
+ *
+ * @param compilation The compilation to be modified.
+ * @param preference Either {@link PREFER_LOW_POWER},
+ * {@link PREFER_SINGLE_FAST_ANSWER}, or
+ * {@link PREFER_SUSTAINED_SPEED}.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksCompilation_setPreference(ANeuralNetworksCompilation *compilation,
+ int32_t preference)
+{
+ LOAD_FUNCTION(ANeuralNetworksCompilation_setPreference);
+ EXECUTE_FUNCTION_RETURN(compilation, preference);
+}
+
+/**
+ * Waits until the compilation completes.
+ *
+ * More than one thread can wait on a compilation. When the compilation
+ * completes, all threads will be released.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded
+ * usage.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the compilation completed normally.
+ */
+inline int ANeuralNetworksCompilation_finish(ANeuralNetworksCompilation *compilation)
+{
+ LOAD_FUNCTION(ANeuralNetworksCompilation_finish);
+ EXECUTE_FUNCTION_RETURN(compilation);
+}
+/**
+ * Create a {@link ANeuralNetworksExecution} to apply the given compilation.
+ * This only creates the object. Computation is only performed once
+ * {@link ANeuralNetworksExecution_startCompute} is invoked.
+ *
+ * <p>The provided compilation must outlive the execution.</p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param compilation The {@link ANeuralNetworksCompilation} to be evaluated.
+ * @param execution The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA
+ * if the compilation is invalid.
+ */
+inline int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_create);
+ EXECUTE_FUNCTION_RETURN(compilation, execution);
+}
+
+/**
+ * Destroy an execution.
+ *
+ * <p>If called on an execution for which
+ * {@link ANeuralNetworksExecution_startCompute} has been called, the
+ * function will return immediately but will mark the execution to be deleted
+ * once the computation completes. The {link ANeuralNetworksExecution_wait}
+ * will return ANEURALNETWORKS_ERROR_DELETED.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param execution The execution to be destroyed. Passing NULL is acceptable
+ * and results in no operation.
+ */
+inline void ANeuralNetworksExecution_free(ANeuralNetworksExecution *execution)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_free);
+ EXECUTE_FUNCTION(execution);
+}
+
+/**
+ * Associate a user buffer with an input of the model of the
+ * {@link ANeuralNetworksExecution}.
+ *
+ * <p>The provided buffer must outlive the execution.</p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param execution The execution to be modified.
+ * @param index The index of the input argument we are setting. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link
+ * ANeuralNetworksModel_addOperand}.
+ * @param type The type of the operand. This should be used to specify the
+ * dimensions that were set to 0 when the operand was added to the
+ * model. All other properties of the type must be the same as
+ * specified in the model. If the type is the same as specified
+ * when the model was built, NULL can be passed.
+ * @param buffer The buffer containing the data.
+ * @param length The length in bytes of the buffer.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA if
+ * the name is not recognized or the buffer is too small for the input.
+ */
+inline int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const void *buffer, size_t length)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_setInput);
+ EXECUTE_FUNCTION_RETURN(execution, index, type, buffer, length);
+}
+
+/**
+ * Associate part of a memory object with an input of the model of the
+ * {@link ANeuralNetworksExecution}.
+ *
+ * <p>The provided memory must outlive the execution.</p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param execution The execution to be modified.
+ * @param index The index of the input argument we are setting. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link
+ * ANeuralNetworksModel_addOperand}.
+ * @param type The type of the operand. This can be used to specify the
+ * dimensions that were set to 0 when the operand was added to the
+ * model. All other values must be the same as specified in the
+ * model. If the type is the same as specified when the model
+ * was built, NULL can be passed.
+ * @param memory The memory containing the data.
+ * @param offset This specifies the location of the data within the memory.
+ * The offset is in bytes from the start of memory.
+ * @param length The size in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA if
+ * the name is not recognized or the buffer is too small for the input.
+ */
+inline int ANeuralNetworksExecution_setInputFromMemory(ANeuralNetworksExecution *execution,
+ int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_setInputFromMemory);
+ EXECUTE_FUNCTION_RETURN(execution, index, type, memory, offset, length);
+}
+
+/**
+ * Associate a user buffer with an output of the model of the
+ * {@link ANeuralNetworksExecution}.
+ *
+ * <p>The provided buffer must outlive the execution.</p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param execution The execution to be modified.
+ * @param index The index of the output argument we are setting. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link
+ * ANeuralNetworksModel_addOperand}.
+ * @param type The type of the operand. This can be used to specify the
+ * dimensions that were set to 0 when the operand was added to the
+ * model. All other values must be the same as specified in the
+ * model. If the type is the same as specified when the model
+ * was built, NULL can be passed.
+ * @param buffer The buffer where the data is to be written.
+ * @param length The length in bytes of the buffer.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA if
+ * the name is not recognized or the buffer is too small for the output.
+ */
+inline int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, void *buffer,
+ size_t length)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_setOutput);
+ EXECUTE_FUNCTION_RETURN(execution, index, type, buffer, length);
+}
+
+/**
+ * Associate part of a memory object with an output of the model of the
+ * {@link ANeuralNetworksExecution}.
+ *
+ * <p>The provided memory must outlive the execution.</p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param execution The execution to be modified.
+ * @param index The index of the output argument we are setting. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link
+ * ANeuralNetworksModel_addOperand}.
+ * @param type The type of the operand. This can be used to specify the
+ * dimensions that were set to 0 when the operand was added to the
+ * model. All other values must be the same as specified in the
+ * model. If the type is the same as specified when the model
+ * was built, NULL can be passed.
+ * @param memory The memory where the data is to be stored.
+ * @param offset This specifies the location of the data within the memory.
+ * The offset is in bytes from the start of memory.
+ * @param length The length in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA if
+ * the name is not recognized or the buffer is too small for the output.
+ */
+inline int ANeuralNetworksExecution_setOutputFromMemory(ANeuralNetworksExecution *execution,
+ int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_setOutputFromMemory);
+ EXECUTE_FUNCTION_RETURN(execution, index, type, memory, offset, length);
+}
+
+/**
+ * Schedule evaluation of the execution.
+ *
+ * <p>Schedules evaluation of the execution. Once the model has been
+ * applied and the outputs are ready to be consumed, the execution will be
+ * signaled. Use {@link ANeuralNetworksExecution_wait} to wait for that signal.
+ * </p>
+ *
+ * Multiple executions can be scheduled and evaluated concurrently, and
+ * compilations can be performed concurrently with executions. The runtime makes
+ * no guarantee on the ordering of the completion of compilations and
+ * executions. If it's important to the application, the application should
+ * enforce the ordering by using {@link ANeuralNetworksCompilation_wait} and
+ * {@link ANeuralNetworksExecution_wait}.
+ *
+ * ANeuralNetworksExecution_wait must be called to recuperate the resources used
+ * by the execution.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param execution The execution to be scheduled and executed.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution,
+ ANeuralNetworksEvent **event)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_startCompute);
+ EXECUTE_FUNCTION_RETURN(execution, event);
+}
+
+/**
+ * Waits until the execution completes.
+ *
+ * More than one thread can wait on an event. When the execution completes,
+ * all threads will be released.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the execution completed normally.
+ */
+inline int ANeuralNetworksEvent_wait(ANeuralNetworksEvent *event)
+{
+ LOAD_FUNCTION(ANeuralNetworksEvent_wait);
+ EXECUTE_FUNCTION_RETURN(event);
+}
+
+/**
+ * Destroys the event.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ */
+inline void ANeuralNetworksEvent_free(ANeuralNetworksEvent *event)
+{
+ LOAD_FUNCTION(ANeuralNetworksEvent_free);
+ EXECUTE_FUNCTION(event);
+}
+
+/**
+ * Get the number of available devices.
+ *
+ * @param numDevices Used to return the number of devices.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworks_getDeviceCount(uint32_t *numDevices)
+{
+ LOAD_FUNCTION(ANeuralNetworks_getDeviceCount);
+ EXECUTE_FUNCTION_RETURN(numDevices);
+}
+
+/**
+ * Get the representation of the specified device.
+ *
+ * @param devIndex The index of the specified device. Must be less than the
+ * number of available devices.
+ * @param device The representation of the specified device.
+ * The same representation will always be returned for the
+ * specified device.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+
+inline int ANeuralNetworks_getDevice(uint32_t devIndex, ANeuralNetworksDevice **device)
+{
+ LOAD_FUNCTION(ANeuralNetworks_getDevice);
+ EXECUTE_FUNCTION_RETURN(devIndex, device);
+}
+
+/**
+ * Get the name of the specified device.
+ *
+ * @param device The representation of the specified device.
+ * @param name The returned name of the specified device. The name will be in
+ * UTF-8 and will be null-terminated. It will be recognizable as a
+ * known device name rather than a cryptic string. For devices
+ * with API level 29 and above, the format of the name is
+ * {VENDOR}-{DEVICE}, e.g. “google-ipu”. For devices with feature
+ * level 28 or lower, the name will always be “unknown-device”.
+ * The name will remain valid for the duration of the application.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworksDevice_getName(const ANeuralNetworksDevice *device, const char **name)
+{
+ LOAD_FUNCTION(ANeuralNetworksDevice_getName);
+ EXECUTE_FUNCTION_RETURN(device, name);
+}
+
+/**
+ * Get the version of the driver implementation of the specified device.
+ *
+ * It’s the responsibility of the driver implementor to insure that this version
+ * string uniquely distinguishes this implementation from all previous
+ * implementations.
+ *
+ * This version string must not be confused with the feature level which is
+ * solely defined by {@link ANeuralNetworksDevice_getFeatureLevel}. There is no
+ * implicit ordering of the versions. For example, it is not possible to filter
+ * all drivers older than a certain version.
+ *
+ * Application developers may use this version string to avoid or prefer
+ * specific driver implementations. For example, an application may want to do
+ * so because:
+ * - A specific version of the driver does not provide the required
+ * performance, perhaps because of a performance regression.
+ * - A specific version of the driver has a bug or returns results that
+ * don’t match the minimum precision requirement for the application.
+ *
+ * @param device The representation of the specified device.
+ * @param version The returned version string of the driver for the specified
+ * device. The string will be in UTF-8 and will be
+ * null-terminated. For devices with feature level 28 or lower,
+ * "UNKNOWN" will be returned. The version string will remain
+ * valid for the duration of the application.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworksDevice_getVersion(const ANeuralNetworksDevice *device,
+ const char **version)
+{
+ LOAD_FUNCTION(ANeuralNetworksDevice_getVersion);
+ EXECUTE_FUNCTION_RETURN(device, version);
+}
+
+/**
+ * Get the supported NNAPI version of the specified device.
+ *
+ * Each device has a supported feature level, which is the most advanced feature
+ * this driver implements. For example, if the driver implements the features
+ * introduced in Android P, but does not implement the features introduced after
+ * Android P, the value would be 28. Developers could decide whether or not the
+ * specified device should be used for a Model that has certain feature
+ * requirements.
+ *
+ * @param device The representation of the specified device.
+ * @param featureLevel The API level of the most advanced feature this driver
+ * implements.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworksDevice_getFeatureLevel(const ANeuralNetworksDevice *device,
+ int64_t *featureLevel)
+{
+ LOAD_FUNCTION(ANeuralNetworksDevice_getFeatureLevel);
+ EXECUTE_FUNCTION_RETURN(device, featureLevel);
+}
+
+/**
+ * Get the supported operations for a specified set of devices. If multiple
+ * devices are selected, the supported operation list is a union of supported
+ * operations of all selected devices.
+ *
+ * @param model The model to be queried.
+ * @param devices The set of devices. Must not contain duplicates.
+ * @param numDevices The number of devices in the set.
+ * @param supportedOps The boolean array to be filled. True means supported. The
+ * size of the boolean array must be at least as large as
+ * the number of operations in the model. The order of
+ * elements in the supportedOps array matches the order in
+ * which the corresponding operations were added to the
+ * model.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+inline int
+ANeuralNetworksModel_getSupportedOperationsForDevices(const ANeuralNetworksModel *model,
+ const ANeuralNetworksDevice *const *devices,
+ uint32_t numDevices, bool *supportedOps)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_getSupportedOperationsForDevices);
+ EXECUTE_FUNCTION_RETURN(model, devices, numDevices, supportedOps);
+}
+
+/**
+ * Create a {@link ANeuralNetworksCompilation} to compile the given model for a
+ * specified set of devices. If more than one device is specified, the
+ * compilation will distribute the workload automatically across the devices.
+ * The model must be fully supported by the specified set of devices. This means
+ * that ANeuralNetworksModel_getSupportedOperationsForDevices() must have
+ * returned true for every operation for that model/devices pair.
+ *
+ * @param model The {@link ANeuralNetworksModel} to be compiled.
+ * @param devices The set of devices. Must not contain duplicates.
+ * @param numDevices The number of devices in the set.
+ * @param compilation The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA
+ * if the model is invalid.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworksCompilation_createForDevices(ANeuralNetworksModel *model,
+ const ANeuralNetworksDevice *const *devices,
+ uint32_t numDevices,
+ ANeuralNetworksCompilation **compilation)
+{
+ LOAD_FUNCTION(ANeuralNetworksCompilation_createForDevices);
+ EXECUTE_FUNCTION_RETURN(model, devices, numDevices, compilation);
+}
+
+/**
+ * Sets the compilation caching signature and the cache directory.
+ *
+ * Provides optional caching information to the runtime for faster repeated
+ * compilation.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded
+ * usage.
+ *
+ * @param compilation The compilation to be modified.
+ * @param cacheDir The cache directory to store and retrieve caching data. It is
+ * recommended to use the code_cache provided by the Android
+ * runtime. If not using the code_cache, the user should choose
+ * a directory local to the application, and is responsible to
+ * manage and clean the cache entries.
+ * @param token The token provided by the user to specify a model, must be of
+ * length ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN. The user should
+ * ensure that the token is unique to a model within the
+ * application. The NNAPI runtime will not detected token
+ * collisions. If there is a collision, the compilation outcome may
+ * be incorrect without notifying with error.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworksCompilation_setCaching(ANeuralNetworksCompilation *compilation,
+ const char *cacheDir, const uint8_t *token)
+{
+ LOAD_FUNCTION(ANeuralNetworksCompilation_setCaching);
+ EXECUTE_FUNCTION_RETURN(compilation, cacheDir, token);
+}
+
+/**
+ * Schedule synchronous evaluation of the execution.
+ *
+ * <p>Schedules synchronous evaluation of the execution. Returns once the
+ * execution has completed and the outputs are ready to be consumed.
+ * </p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * See {@link ANeuralNetworksExecution_startCompute} for asynchronous execution.
+ * Synchronous execution incurs lower overhead than asynchronous execution.
+ *
+ * Available since API level 29.
+ *
+ * @param execution The execution to be scheduled and executed.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the execution completed normally.
+ * ANEURALNETWORKS_UNMAPPABLE if the execution input or output memory
+ * cannot be properly mapped.
+ */
+inline int ANeuralNetworksExecution_compute(ANeuralNetworksExecution *execution)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_compute);
+ EXECUTE_FUNCTION_RETURN(execution);
+}
+
+/**
+ * Get the dimensional information of the specified output operand of the model
+ * of the
+ * {@link ANeuralNetworksExecution}.
+ *
+ * On asynchronous execution initiated by {@link
+ * ANeuralNetworksExecution_startCompute},
+ * {@link ANeuralNetworksEvent_wait} must be called prior to this function to
+ * recuperate the resources used by the execution.
+ *
+ * @param execution The execution to be queried.
+ * @param index The index of the output argument we are querying. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link
+ * ANeuralNetworksModel_addOperand}.
+ * @param rank The rank of the output operand.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful,
+ * ANEURALNETWORKS_OUTPUT_INSUFFICIENT_SIZE if the target output is provided an
+ * insufficient buffer at execution time, ANEURALNETWORKS_BAD_DATA if the index
+ * is invalid.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworksExecution_getOutputOperandRank(ANeuralNetworksExecution *execution,
+ int32_t index, uint32_t *rank)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_getOutputOperandRank);
+ EXECUTE_FUNCTION_RETURN(execution, index, rank);
+}
+
+/**
+ * Get the dimensional information of the specified output operand of the model
+ * of the
+ * {@link ANeuralNetworksExecution}. The target output operand cannot be a
+ * scalar.
+ *
+ * On asynchronous execution initiated by
+ * {@link ANeuralNetworksExecution_startCompute},
+ * {@link ANeuralNetworksEvent_wait} must be called prior to this function to
+ * recuperate the resources used by the execution.
+ *
+ * @param execution The execution to be queried.
+ * @param index The index of the output argument we are querying. It is an index
+ * into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with
+ * {@link ANeuralNetworksModel_addOperand}.
+ * @param dimensions The dimension array to be filled. The size of the array
+ * must be exactly as large as the rank of the output operand
+ * to be queried in the model.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful,
+ * ANEURALNETWORKS_OUTPUT_INSUFFICIENT_SIZE if the target output is provided an
+ * insufficient buffer at execution time, ANEURALNETWORKS_BAD_DATA if the index
+ * is invalid or if the target is a scalar.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworksExecution_getOutputOperandDimensions(ANeuralNetworksExecution *execution,
+ int32_t index, uint32_t *dimensions)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_getOutputOperandDimensions);
+ EXECUTE_FUNCTION_RETURN(execution, index, dimensions);
+}
+
+/**
+ * Create a {@link ANeuralNetworksBurst} to apply the given compilation.
+ * This only creates the burst object. Computation is only performed once
+ * {@link ANeuralNetworksExecution_burstCompute} is invoked with a valid
+ * {@link ANeuralNetworksExecution} and {@link ANeuralNetworksBurst}.
+ *
+ * <p>The provided compilation must outlive the burst object.</p>
+ *
+ * Available since API level 29.
+ *
+ * @param compilation The {@link ANeuralNetworksCompilation} to be evaluated.
+ * @param burst The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA
+ * if the compilation is invalid.
+ */
+inline int ANeuralNetworksBurst_create(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksBurst **burst)
+{
+ LOAD_FUNCTION(ANeuralNetworksBurst_create);
+ EXECUTE_FUNCTION_RETURN(compilation, burst);
+}
+
+/**
+ * Destroys the burst object.
+ *
+ * Available since API level 29.
+ *
+ * @param burst The burst object to be destroyed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+inline void ANeuralNetworksBurst_free(ANeuralNetworksBurst *burst)
+{
+ LOAD_FUNCTION(ANeuralNetworksBurst_free);
+ EXECUTE_FUNCTION(burst);
+}
+
+/**
+ * Schedule synchronous evaluation of the execution on a burst object.
+ *
+ * <p>Schedules synchronous evaluation of the execution. Returns once the
+ * execution has completed and the outputs are ready to be consumed.</p>
+ *
+ * <p>There must be at most one {@link ANeuralNetworksExecution} processing at
+ * any given time for any given burst object. Any
+ * {@link ANeuralNetworksExecution} launched before the previous has finished
+ * will result in ANEURALNETWORKS_BAD_STATE.</p>
+ *
+ * Available since API level 29.
+ *
+ * @param burst The burst object to execute on.
+ * @param execution The execution to be scheduled and executed. The execution
+ * must be created from the same {@link
+ * ANeuralNetworksCompilation} as the burst object.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the execution completed normally.
+ */
+inline int ANeuralNetworksExecution_burstCompute(ANeuralNetworksExecution *execution,
+ ANeuralNetworksBurst *burst)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_burstCompute);
+ EXECUTE_FUNCTION_RETURN(execution, burst);
+}
+
+/**
+ * Creates a shared memory object from an AHardwareBuffer handle.
+ *
+ * If the shared memory is backed by an AHardwareBuffer of
+ * AHARDWAREBUFFER_FORMAT_BLOB format, it can be used the same way as shared
+ * memory created from a file handle. See
+ * {@link ANeuralNetworksMemory} for a description on how to use this shared
+ * memory.
+ *
+ * If the shared memory is backed by an AHardwareBuffer of a format other than
+ * AHARDWAREBUFFER_FORMAT_BLOB, it can only be used for Model inputs and
+ * outputs. When calling {@link ANeuralNetworksExecution_setInputFromMemory} or
+ * {@link ANeuralNetworksExecution_setOutputFromMemory} with the shared memory,
+ * both offset and length must be set to zero and the entire memory region will
+ * be associated with the specified input or output operand. There is no
+ * guarantee that an arbitrary AHardwareBuffer_Format and
+ * AHardwareBuffer_UsageFlags combination can be used by arbitrary devices. The
+ * execution will fail if selected set of devices cannot consume the buffer.
+ *
+ * Calling {@link ANeuralNetworksModel_setOperandValueFromMemory} with shared
+ * memory backed by an AHardwareBuffer of a format other than
+ * AHARDWAREBUFFER_FORMAT_BLOB is disallowed.
+ *
+ * TODO(miaowang): add documentation about intended usage with introspection
+ * API.
+ *
+ * Available since API level 29.
+ *
+ * @param ahwb The AHardwareBuffer handle.
+ * @param memory The memory object to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the request completed normally.
+ *
+ * @see AHardwareBuffer
+ */
+inline int ANeuralNetworksMemory_createFromAHardwareBuffer(const AHardwareBuffer *ahwb,
+ ANeuralNetworksMemory **memory)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemory_createFromAHardwareBuffer);
+ EXECUTE_FUNCTION_RETURN(ahwb, memory);
+}
+
+/**
+ * Specifies whether duration of the {@link ANeuralNetworksExecution} is to be
+ * measured. By default, duration is not measured.
+ *
+ * The {@link ANeuralNetworksExecution} must have been created with
+ * {@link ANeuralNetworksCompilation_createForDevices} with numDevices = 1.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * Available since API level 29.
+ *
+ * @param execution The execution to be modified.
+ * @param measure 'true' if duration is to be measured, 'false' if not.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksExecution_setMeasureTiming(ANeuralNetworksExecution *execution,
+ bool measure)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_setMeasureTiming);
+ EXECUTE_FUNCTION_RETURN(execution, measure);
+}
+
+/**
+ * Get the time spent in the specified {@link ANeuralNetworksExecution}, in
+ * nanoseconds. The execution must have completed.
+ *
+ * @param execution The execution to be queried.
+ * @param durationCode The measurement to be queried, specified by {@link
+ * DurationCode}.
+ * @param duration The returned duration. If no measurement was requested by
+ * {@link ANeuralNetworksExecution_setMeasureTiming}, or for
+ * some other reason the duration is not available, UINT64_MAX will be returned.
+ * A particular device need not support any given measurement.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksExecution_getDuration(const ANeuralNetworksExecution *execution,
+ int32_t durationCode, uint64_t *duration)
+{
+ LOAD_FUNCTION(ANeuralNetworksExecution_getDuration);
+ EXECUTE_FUNCTION_RETURN(execution, durationCode, duration);
+}
+
+/**
+ * Queries whether an extension is supported by the driver implementation of
+ * the specified device.
+ *
+ * @param device The representation of the specified device.
+ * @param extension The extension name.
+ * @param isExtensionSupported The boolean value indicating whether the
+ * extension is supported.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+inline int ANeuralNetworksDevice_getExtensionSupport(const ANeuralNetworksDevice *device,
+ const char *extensionName,
+ bool *isExtensionSupported)
+{
+ LOAD_FUNCTION(ANeuralNetworksDevice_getExtensionSupport);
+ EXECUTE_FUNCTION_RETURN(device, extensionName, isExtensionSupported);
+}
+
+/**
+ * Creates an operand type from an extension name and an extension operand code.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 29.
+ *
+ * @param model The model to contain the operand.
+ * @param extensionName The extension name.
+ * @param operandCodeWithinExtension The extension operand code.
+ * @param type The operand type.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_getExtensionOperandType(ANeuralNetworksModel *model,
+ const char *extensionName,
+ uint16_t operandCodeWithinExtension,
+ int32_t *type)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_getExtensionOperandType);
+ EXECUTE_FUNCTION_RETURN(model, extensionName, operandCodeWithinExtension, type);
+}
+
+/**
+ * Creates an operation type from an extension name and an extension operation
+ * code.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 29.
+ *
+ * @param model The model to contain the operation.
+ * @param extensionName The extension name.
+ * @param operationCodeWithinExtension The extension operation code.
+ * @param type The operation type.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_getExtensionOperationType(ANeuralNetworksModel *model,
+ const char *extensionName,
+ uint16_t operationCodeWithinExtension,
+ ANeuralNetworksOperationType *type)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_getExtensionOperationType);
+ EXECUTE_FUNCTION_RETURN(model, extensionName, operationCodeWithinExtension, type);
+}
+
+/**
+ * Sets extension operand parameters.
+ *
+ * Available since API level 29.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param data A pointer to the extension operand data.
+ * The data does not have to outlive the call to this function.
+ * @param length The size in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksModel_setOperandExtensionData(ANeuralNetworksModel *model, int32_t index,
+ const void *data, size_t length)
+{
+ LOAD_FUNCTION(ANeuralNetworksModel_setOperandExtensionData);
+ EXECUTE_FUNCTION_RETURN(model, index, data, length);
+}
+
+/**
+ * Create a {@link ANeuralNetworksMemoryDesc} with no properties.
+ *
+ * This only creates the memory descriptor. Its properties should be set with
+ * calls to
+ * {@link ANeuralNetworksMemoryDesc_addInputRole},
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}, and
+ * {@link ANeuralNetworksMemoryDesc_setDimensions}.
+ *
+ * {@link ANeuralNetworksMemoryDesc_finish} must be called once all properties
+ * have been set.
+ *
+ * {@link ANeuralNetworksMemoryDesc_free} must be called once the memory
+ * descriptor is no longer needed.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The {@link ANeuralNetworksMemoryDesc} to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksMemoryDesc_create(ANeuralNetworksMemoryDesc **desc)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemoryDesc_create);
+ EXECUTE_FUNCTION_RETURN(desc);
+}
+
+/**
+ * Destroy a memory descriptor.
+ *
+ * The memory descriptor need not have been finished by a call to
+ * {@link ANeuralNetworksMemoryDesc_finish}.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be destroyed. Passing NULL is acceptable
+ * and results in no operation.
+ */
+inline void ANeuralNetworksMemoryDesc_free(ANeuralNetworksMemoryDesc *desc)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemoryDesc_free);
+ EXECUTE_FUNCTION(desc);
+}
+
+/**
+ * Specify that a memory object will be playing the role of an output to an
+ * execution created from a particular compilation.
+ *
+ * The compilation and the output index fully specify an output operand. This
+ * function may be invoked multiple times on the same memory descriptor with
+ * different output operands, and the same output operand may be specified on
+ * multiple memory descriptors. However, specifying the same output operand on
+ * the same memory descriptor object more than once will return an error.
+ *
+ * The dimensions of the corresponding model operands of all the roles specified
+ * by
+ * {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole} must be compatible with each
+ * other. Two dimensions are incompatible if both ranks are fully specified but
+ * have different values, or if there is at least one axis that is fully
+ * specified in both but has different values.
+ *
+ * At least one of {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole} must be called on the memory
+ * descriptor before invoking {@link ANeuralNetworksMemoryDesc_finish}.
+ *
+ * Attempting to modify a memory descriptor once
+ * {@link ANeuralNetworksMemoryDesc_finish} has been called will return an
+ * error.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be modified.
+ * @param compilation The compilation object. It must already have been finished
+ * by calling {@link ANeuralNetworksCompilation_finish}, and must outlive the
+ * memory descriptor.
+ * @param index The index of the output argument we are referencing from the
+ * compilation. It is an index into the outputs list passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link
+ * ANeuralNetworksModel_addOperand}.
+ * @param frequency A floating-point value within the range (0.0, 1.0].
+ * Describes how likely the memory is to be used in the specified role. This is
+ * provided as a hint to optimize the case when multiple roles
+ * prefer different memory locations or data layouts.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksMemoryDesc_addOutputRole(ANeuralNetworksMemoryDesc *desc,
+ const ANeuralNetworksCompilation *compilation,
+ int32_t index, float frequency)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemoryDesc_addOutputRole);
+ EXECUTE_FUNCTION_RETURN(desc, compilation, index, frequency);
+}
+
+/**
+ * Specify that a memory object will be playing the role of an input to an
+ * execution created from a particular compilation.
+ *
+ * The compilation and the input index fully specify an input operand. This
+ * function may be invoked multiple times on the same memory descriptor with
+ * different input operands, and the same input operand may be specified on
+ * multiple memory descriptors. However, specifying the same input operand on
+ * the same memory descriptor more than once will return an error.
+ *
+ * The dimensions of the corresponding model operands of all the roles specified
+ * by
+ * {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole} must be compatible with each
+ * other. Two dimensions are incompatible if both ranks are fully specified but
+ * have different values, or if there is at least one axis that is fully
+ * specified in both but has different values.
+ *
+ * At least one of {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole} must be called on a memory
+ * descriptor before invoking {@link ANeuralNetworksMemoryDesc_finish}.
+ *
+ * Attempting to modify a memory descriptor once
+ * {@link ANeuralNetworksMemoryDesc_finish} has been called will return an
+ * error.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be modified.
+ * @param compilation The compilation object. It must already have been finished
+ * by calling {@link ANeuralNetworksCompilation_finish}, and must outlive the
+ * memory descriptor.
+ * @param index The index of the input argument we are referencing from the
+ * compilation. It is an index into the inputs list passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link
+ * ANeuralNetworksModel_addOperand}.
+ * @param frequency A floating-point value within the range (0.0, 1.0].
+ * Describes how likely the memory is to be used in the specified role. This is
+ * provided as a hint to optimize the case when different roles
+ * prefer different memory locations or data layouts.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksMemoryDesc_addInputRole(ANeuralNetworksMemoryDesc *desc,
+ const ANeuralNetworksCompilation *compilation,
+ uint32_t index, float frequency)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemoryDesc_addInputRole);
+ EXECUTE_FUNCTION_RETURN(desc, compilation, index, frequency);
+}
+
+/**
+ * Set the dimensional information of the memory descriptor.
+ *
+ * The specified dimensions must be compatible with the dimensions of the
+ * corresponding model operands of all the roles specified by
+ * {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}. Two dimensions are
+ * incompatible if both ranks are fully specified but have different values, or
+ * if there is at least one axis that is fully specified in both but has
+ * different values.
+ *
+ * Attempting to modify a memory descriptor once
+ * {@link ANeuralNetworksMemoryDesc_finish} has been called will return an
+ * error.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be modified.
+ * @param rank The number of dimensions. Must be 0 for scalars.
+ * @param dimensions An array of dimensions. An entry with the value 0 indicates
+ * that the corresponding axis has an unknown size.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksMemoryDesc_setDimensions(ANeuralNetworksMemoryDesc *desc, uint32_t rank,
+ const uint32_t *dimensions)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemoryDesc_setDimensions);
+ EXECUTE_FUNCTION_RETURN(desc, rank, dimensions);
+}
+
+/**
+ * Indicate that we have finished modifying a memory descriptor. Required before
+ * calling
+ * {@link ANeuralNetworksMemory_createFromDesc}.
+ *
+ * This function must only be called once for a given memory descriptor.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be finished.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksMemoryDesc_finish(ANeuralNetworksMemoryDesc *desc)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemoryDesc_finish);
+ EXECUTE_FUNCTION_RETURN(desc);
+}
+
+/**
+ * Creates a memory object from a memory descriptor.
+ *
+ * The memory object is created with an uninitialized buffer. A memory object
+ * with an uninitialized buffer may only be used according to the roles
+ * specified by
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}, or as the destination memory
+ * in
+ * {@link ANeuralNetworksMemory_copy}. The buffer of a memory object is
+ * initialized after the memory object is used as an output in a successful
+ * execution, or used as the destination memory in a successful {@link
+ * ANeuralNetworksMemory_copy}. A memory object with an initialized buffer may
+ * be used according to all roles specified in
+ * {@link ANeuralNetworksMemoryDesc}, or as the source or destination memory in
+ * {@link ANeuralNetworksMemory_copy}. The buffer of a memory object will return
+ * to the uninitialized state if the memory object is used as an output in a
+ * failed execution, or used as the destination memory in a failed {@link
+ * ANeuralNetworksMemory_copy}.
+ *
+ * The dimensions of the memory descriptor are deduced from the dimensions of
+ * the corresponding model operands of all the roles specified by
+ * {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}, as well as the dimensions
+ * set by the call to {@link ANeuralNetworksMemoryDesc_setDimensions}, if any.
+ * The memory descriptor may have unspecified dimensions or rank. In such a
+ * case, the same memory object may be used with different shapes of outputs in
+ * different executions. When the memory is used as an input, the input shape
+ * must be the same as the output shape from the last execution using this
+ * memory object as an output, or the last
+ * {@link ANeuralNetworkMemory_copy} using this memory object as the destination
+ * memory. Creating a memory object with unspecified dimensions or rank may fail
+ * for certain sets of roles.
+ *
+ * Using the memory in roles or shapes that are not compatible with the rules
+ * specified above will return an error.
+ *
+ * When calling {@link ANeuralNetworksExecution_setInputFromMemory} or
+ * {@link ANeuralNetworksExecution_setOutputFromMemory} with the memory object,
+ * both offset and length must be set to zero and the entire memory region will
+ * be associated with the specified input or output operand.
+ *
+ * Calling {@link ANeuralNetworksModel_setOperandValueFromMemory} with the
+ * memory created from this function will return an error.
+ *
+ * {@link ANeuralNetworksMemory_free} must be called once the memory is no
+ * longer needed.
+ *
+ * Attempting to create memory from an unfinished memory descriptor will return
+ * an error.
+ *
+ * The provided {@link ANeuralNetworksMemoryDesc} need not outlive the
+ * {@link ANeuralNetworksMemory} object.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor.
+ * @param memory The memory object to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful; ANEURALNETWORKS_OP_FAILED if
+ * the memory is created with unspecified dimensions or rank and it is not
+ * supported for this set of roles.
+ */
+inline int ANeuralNetworksMemory_createFromDesc(const ANeuralNetworksMemoryDesc *desc,
+ ANeuralNetworksMemory **memory)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemory_createFromDesc);
+ EXECUTE_FUNCTION_RETURN(desc, memory);
+}
+
+/**
+ * Copies data from one memory object to another.
+ *
+ * If at most one of the src and dst is created from
+ * {@link ANeuralNetworksMemory_createFromDesc}, the src and dst must have the
+ * same logical size:
+ * - If the memory is created from {@link ANeuralNetworksMemory_createFromFd},
+ * or if it is created from {@link
+ * ANeuralNetworksMemory_createFromAHardwareBuffer} with format of
+ * AHARDWAREBUFFER_FORMAT_BLOB, the logical size equals the size of the memory.
+ * - If the memory is created from
+ * {@link ANeuralNetworksMemory_createFromAHardwareBuffer} with a format other
+ * than AHARDWAREBUFFER_FORMAT_BLOB, the logical size equals the size when there
+ * is no padding and the data is tightly packed. This function may fail if the
+ * AHardwareBuffer cannot be accessed.
+ * - If the memory is created from {@link ANeuralNetworksMemory_createFromDesc},
+ * the logical size equals the size indicated by the {@link OperandCode}
+ * multiplied by the number of elements. This function will fail if the number
+ * of elements is unknown.
+ *
+ * If both src and dst are created from {@link
+ * ANeuralNetworksMemory_createFromDesc}, they must have compatible dimensions.
+ * Two dimensions are incompatible if both ranks are fully specified but have
+ * different values, or if there is at least one axis that is fully specified in
+ * both but has different values. The dst may have unspecified dimensions or
+ * rank. In such a case, the dimensions of dst will get updated according to the
+ * dimensions of the src.
+ *
+ * In both cases, if the src is created from
+ * {@link ANeuralNetworksMemory_createFromDesc}, it must have been used as an
+ * output in a successful execution, or used as the destination memory in a
+ * successful
+ * {@link ANeuralNetworksMemory_copy}.
+ *
+ * The src and dst may have different data layout, in which case the data
+ * copying is performed logically with data layout transformation.
+ *
+ * Available since API level 30.
+ *
+ * @param src The source memory object.
+ * @param dst The destination memory object.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+inline int ANeuralNetworksMemory_copy(const ANeuralNetworksMemory *src,
+ const ANeuralNetworksMemory *dst)
+{
+ LOAD_FUNCTION(ANeuralNetworksMemory_copy);
+ EXECUTE_FUNCTION_RETURN(src, dst);
+}
+
+/**/
+
+#endif // __NEURAL_NETWORKS_SHIM_H__
diff --git a/runtime/libs/nnapi/include/NeuralNetworksTypes.h b/runtime/libs/nnapi/include/NeuralNetworksTypes.h
new file mode 100644
index 000000000..2e0568791
--- /dev/null
+++ b/runtime/libs/nnapi/include/NeuralNetworksTypes.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// NOTE This header is derived from part of the following file
+// https://github.com/tensorflow/tensorflow/blob/v2.3.0/tensorflow/lite/nnapi/NeuralNetworksTypes.h
+
+#ifndef __NEURAL_NETWORKS_TYPES_H__
+#define __NEURAL_NETWORKS_TYPES_H__
+
+#include "NeuralNetworks.h"
+
+// NN api types based on NNAPI header file
+// https://developer.android.com/ndk/reference/group/neural-networks
+
+// nn api function types
+
+typedef int (*ANeuralNetworksMemory_createFromFd_fn)(size_t size, int protect, int fd,
+ size_t offset, ANeuralNetworksMemory **memory);
+
+typedef void (*ANeuralNetworksMemory_free_fn)(ANeuralNetworksMemory *memory);
+
+typedef int (*ANeuralNetworksModel_create_fn)(ANeuralNetworksModel **model);
+
+typedef int (*ANeuralNetworksModel_finish_fn)(ANeuralNetworksModel *model);
+
+typedef void (*ANeuralNetworksModel_free_fn)(ANeuralNetworksModel *model);
+
+typedef int (*ANeuralNetworksCompilation_create_fn)(ANeuralNetworksModel *model,
+ ANeuralNetworksCompilation **compilation);
+
+typedef void (*ANeuralNetworksCompilation_free_fn)(ANeuralNetworksCompilation *compilation);
+
+typedef int (*ANeuralNetworksCompilation_setPreference_fn)(ANeuralNetworksCompilation *compilation,
+ int32_t preference);
+
+typedef int (*ANeuralNetworksCompilation_finish_fn)(ANeuralNetworksCompilation *compilation);
+
+typedef int (*ANeuralNetworksModel_addOperand_fn)(ANeuralNetworksModel *model,
+ const ANeuralNetworksOperandType *type);
+
+typedef int (*ANeuralNetworksModel_setOperandValue_fn)(ANeuralNetworksModel *model, int32_t index,
+ const void *buffer, size_t length);
+
+typedef int (*ANeuralNetworksModel_setOperandSymmPerChannelQuantParams_fn)(
+ ANeuralNetworksModel *model, int32_t index,
+ const ANeuralNetworksSymmPerChannelQuantParams *channelQuant);
+
+typedef int (*ANeuralNetworksModel_setOperandValueFromMemory_fn)(
+ ANeuralNetworksModel *model, int32_t index, const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length);
+
+typedef int (*ANeuralNetworksModel_addOperation_fn)(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationType type,
+ uint32_t inputCount, const uint32_t *inputs,
+ uint32_t outputCount, const uint32_t *outputs);
+
+typedef int (*ANeuralNetworksModel_identifyInputsAndOutputs_fn)(ANeuralNetworksModel *model,
+ uint32_t inputCount,
+ const uint32_t *inputs,
+ uint32_t outputCount,
+ const uint32_t *outputs);
+
+typedef int (*ANeuralNetworksModel_relaxComputationFloat32toFloat16_fn)(ANeuralNetworksModel *model,
+ bool allow);
+
+typedef int (*ANeuralNetworksExecution_create_fn)(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution);
+
+typedef void (*ANeuralNetworksExecution_free_fn)(ANeuralNetworksExecution *execution);
+
+typedef int (*ANeuralNetworksExecution_setInput_fn)(ANeuralNetworksExecution *execution,
+ int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const void *buffer, size_t length);
+
+typedef int (*ANeuralNetworksExecution_setInputFromMemory_fn)(
+ ANeuralNetworksExecution *execution, int32_t index, const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset, size_t length);
+
+typedef int (*ANeuralNetworksExecution_setOutput_fn)(ANeuralNetworksExecution *execution,
+ int32_t index,
+ const ANeuralNetworksOperandType *type,
+ void *buffer, size_t length);
+
+typedef int (*ANeuralNetworksExecution_setOutputFromMemory_fn)(
+ ANeuralNetworksExecution *execution, int32_t index, const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset, size_t length);
+
+typedef int (*ANeuralNetworksExecution_startCompute_fn)(ANeuralNetworksExecution *execution,
+ ANeuralNetworksEvent **event);
+
+typedef int (*ANeuralNetworksEvent_wait_fn)(ANeuralNetworksEvent *event);
+
+typedef void (*ANeuralNetworksEvent_free_fn)(ANeuralNetworksEvent *event);
+
+typedef int (*ASharedMemory_create_fn)(const char *name, size_t size);
+
+typedef int (*ANeuralNetworks_getDeviceCount_fn)(uint32_t *numDevices);
+
+typedef int (*ANeuralNetworks_getDevice_fn)(uint32_t devIndex, ANeuralNetworksDevice **device);
+
+typedef int (*ANeuralNetworksDevice_getName_fn)(const ANeuralNetworksDevice *device,
+ const char **name);
+
+typedef int (*ANeuralNetworksDevice_getType_fn)(const ANeuralNetworksDevice *device, int32_t *type);
+
+typedef int (*ANeuralNetworksDevice_getVersion_fn)(const ANeuralNetworksDevice *device,
+ const char **version);
+
+typedef int (*ANeuralNetworksDevice_getFeatureLevel_fn)(const ANeuralNetworksDevice *device,
+ int64_t *featureLevel);
+
+typedef int (*ANeuralNetworksModel_getSupportedOperationsForDevices_fn)(
+ const ANeuralNetworksModel *model, const ANeuralNetworksDevice *const *devices,
+ uint32_t numDevices, bool *supportedOps);
+
+typedef int (*ANeuralNetworksCompilation_createForDevices_fn)(
+ ANeuralNetworksModel *model, const ANeuralNetworksDevice *const *devices, uint32_t numDevices,
+ ANeuralNetworksCompilation **compilation);
+
+typedef int (*ANeuralNetworksCompilation_setCaching_fn)(ANeuralNetworksCompilation *compilation,
+ const char *cacheDir, const uint8_t *token);
+
+typedef int (*ANeuralNetworksCompilation_setTimeout_fn)(ANeuralNetworksCompilation *compilation,
+ uint64_t duration);
+
+typedef int (*ANeuralNetworksCompilation_setPriority_fn)(ANeuralNetworksCompilation *compilation,
+ int priority);
+
+typedef int (*ANeuralNetworksExecution_compute_fn)(ANeuralNetworksExecution *execution);
+
+typedef int (*ANeuralNetworksExecution_setTimeout_fn)(ANeuralNetworksExecution *execution,
+ uint64_t duration);
+
+typedef int (*ANeuralNetworksExecution_setLoopTimeout_fn)(ANeuralNetworksExecution *execution,
+ uint64_t duration);
+
+typedef int (*ANeuralNetworksExecution_getOutputOperandRank_fn)(ANeuralNetworksExecution *execution,
+ int32_t index, uint32_t *rank);
+
+typedef int (*ANeuralNetworksExecution_getOutputOperandDimensions_fn)(
+ ANeuralNetworksExecution *execution, int32_t index, uint32_t *dimensions);
+
+typedef int (*ANeuralNetworksBurst_create_fn)(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksBurst **burst);
+
+typedef void (*ANeuralNetworksBurst_free_fn)(ANeuralNetworksBurst *burst);
+
+typedef int (*ANeuralNetworksExecution_burstCompute_fn)(ANeuralNetworksExecution *execution,
+ ANeuralNetworksBurst *burst);
+
+typedef int (*ANeuralNetworksMemory_createFromAHardwareBuffer_fn)(const AHardwareBuffer *ahwb,
+ ANeuralNetworksMemory **memory);
+
+typedef int (*ANeuralNetworksExecution_setMeasureTiming_fn)(ANeuralNetworksExecution *execution,
+ bool measure);
+
+typedef int (*ANeuralNetworksExecution_getDuration_fn)(const ANeuralNetworksExecution *execution,
+ int32_t durationCode, uint64_t *duration);
+
+typedef int (*ANeuralNetworksDevice_getExtensionSupport_fn)(const ANeuralNetworksDevice *device,
+ const char *extensionName,
+ bool *isExtensionSupported);
+
+typedef int (*ANeuralNetworksModel_getExtensionOperandType_fn)(ANeuralNetworksModel *model,
+ const char *extensionName,
+ uint16_t operandCodeWithinExtension,
+ int32_t *type);
+
+typedef int (*ANeuralNetworksModel_getExtensionOperationType_fn)(
+ ANeuralNetworksModel *model, const char *extensionName, uint16_t operationCodeWithinExtension,
+ ANeuralNetworksOperationType *type);
+
+typedef int (*ANeuralNetworksModel_setOperandExtensionData_fn)(ANeuralNetworksModel *model,
+ int32_t index, const void *data,
+ size_t length);
+
+typedef int (*ANeuralNetworksMemoryDesc_create_fn)(ANeuralNetworksMemoryDesc **desc);
+
+typedef void (*ANeuralNetworksMemoryDesc_free_fn)(ANeuralNetworksMemoryDesc *desc);
+
+typedef int (*ANeuralNetworksMemoryDesc_addInputRole_fn)(
+ ANeuralNetworksMemoryDesc *desc, const ANeuralNetworksCompilation *compilation, int32_t index,
+ float frequency);
+
+typedef int (*ANeuralNetworksMemoryDesc_addOutputRole_fn)(
+ ANeuralNetworksMemoryDesc *desc, const ANeuralNetworksCompilation *compilation, uint32_t index,
+ float frequency);
+
+typedef int (*ANeuralNetworksMemoryDesc_setDimensions_fn)(ANeuralNetworksMemoryDesc *desc,
+ uint32_t rank,
+ const uint32_t *dimensions);
+
+typedef int (*ANeuralNetworksMemoryDesc_finish_fn)(ANeuralNetworksMemoryDesc *desc);
+
+typedef int (*ANeuralNetworksMemory_createFromDesc_fn)(const ANeuralNetworksMemoryDesc *desc,
+ ANeuralNetworksMemory **memory);
+
+typedef int (*ANeuralNetworksMemory_copy_fn)(const ANeuralNetworksMemory *src,
+ const ANeuralNetworksMemory *dst);
+
+#endif // __NEURAL_NETWORKS_TYPES_H__
diff --git a/runtime/libs/profiling/CMakeLists.txt b/runtime/libs/profiling/CMakeLists.txt
new file mode 100644
index 000000000..e0398ce93
--- /dev/null
+++ b/runtime/libs/profiling/CMakeLists.txt
@@ -0,0 +1,7 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(nnfw_lib_profiling STATIC ${SOURCES})
+set_property(TARGET nnfw_lib_profiling PROPERTY POSITION_INDEPENDENT_CODE ON)
+target_include_directories(nnfw_lib_profiling PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(nnfw_lib_profiling PRIVATE nnfw_common)
+target_link_libraries(nnfw_lib_profiling PRIVATE nnfw_coverage)
diff --git a/runtime/libs/profiling/include/profiling/profile_buffer.h b/runtime/libs/profiling/include/profiling/profile_buffer.h
new file mode 100644
index 000000000..bc8d75e7c
--- /dev/null
+++ b/runtime/libs/profiling/include/profiling/profile_buffer.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This header is derived from the following file (in TensorFlow v1.12)
+// 'externals/tensorflow/tensorflow/lite/profiling/profile_buffer.h
+#ifndef TENSORFLOW_CONTRIB_LITE_PROFILING_PROFILE_BUFFER_H_
+#define TENSORFLOW_CONTRIB_LITE_PROFILING_PROFILE_BUFFER_H_
+
+#include <cstddef>
+#include <cstdint>
+
+#include "profiling/time.h"
+
+namespace tflite {
+namespace profiling {
+
+// A profiling event.
+struct ProfileEvent {
+ // Describes the type of event.
+ // The event_metadata field may contain additional data for interpreting
+ // the event.
+ enum class EventType {
+ // Default event type, the metadata field has no special significance.
+ DEFAULT = 0,
+ // The event is an operator invocation and the event_metadata field is the
+ // index of operator node.
+ OPERATOR_INVOKE_EVENT = 1
+ };
+
+ // Label of the event. This usually describes the event.
+ const char* tag;
+ // Timestamp in microseconds when the event began.
+ uint64_t begin_timestamp_us;
+ // Timestamp in microseconds when the event ended.
+ uint64_t end_timestamp_us;
+ // The field containing the type of event. This must be one of the event types
+ // in EventType.
+ EventType event_type;
+ // Extra data describing the details of the event.
+ uint32_t event_metadata;
+};
+} // namespace profiling
+} // namespace tflite
+
+#ifdef TFLITE_PROFILING_ENABLED
+
+#include <sys/time.h>
+#include <vector>
+
+namespace tflite {
+namespace profiling {
+constexpr uint32_t kInvalidEventHandle = static_cast<uint32_t>(~0) - 1;
+
+// A ring buffer of profile events.
+// This class is not thread safe.
+class ProfileBuffer {
+ public:
+ ProfileBuffer(uint32_t max_num_entries, bool enabled)
+ : enabled_(enabled), current_index_(0), event_buffer_(max_num_entries) {}
+
+ // Adds an event to the buffer with begin timestamp set to the current
+ // timestamp. Returns a handle to event that can be used to call EndEvent. If
+ // buffer is disabled this has no affect.
+ // The tag of the event should remain valid till the buffer is valid.
+ uint32_t BeginEvent(const char* tag, ProfileEvent::EventType event_type,
+ uint32_t event_metadata) {
+ if (!enabled_) {
+ return kInvalidEventHandle;
+ }
+ uint64_t timestamp = time::NowMicros();
+ int index = current_index_ % event_buffer_.size();
+ event_buffer_[index].tag = tag;
+ event_buffer_[index].event_type = event_type;
+ event_buffer_[index].event_metadata = event_metadata;
+ event_buffer_[index].begin_timestamp_us = timestamp;
+ event_buffer_[index].end_timestamp_us = 0;
+ current_index_++;
+ return index;
+ }
+
+ // Sets the enabled state of buffer to |enabled|
+ void SetEnabled(bool enabled) { enabled_ = enabled; }
+
+ // Sets the end timestamp for event for the handle to current time.
+ // If the buffer is disabled or previous event has been overwritten this
+ // operation has not effect.
+ void EndEvent(uint32_t event_handle) {
+ if (!enabled_ || event_handle == kInvalidEventHandle ||
+ event_handle > current_index_) {
+ return;
+ }
+ const uint32_t max_size = event_buffer_.size();
+ if (current_index_ > (max_size + event_handle)) {
+ // Ignore, buffer has already overflowed.
+ return;
+ }
+
+ int event_index = event_handle % max_size;
+ event_buffer_[event_index].end_timestamp_us = time::NowMicros();
+ }
+
+ // Returns the size of the buffer.
+ size_t Size() const {
+ return (current_index_ >= event_buffer_.size()) ? event_buffer_.size()
+ : current_index_;
+ }
+
+ // Resets the buffer.
+ void Reset() {
+ enabled_ = false;
+ current_index_ = 0;
+ }
+
+ // Returns the profile event at the given index. If the index is invalid a
+ // nullptr is returned. The return event may get overwritten if more events
+ // are added to buffer.
+ const struct ProfileEvent* const At(int index) const {
+ size_t size = Size();
+ if (index >= size) {
+ return nullptr;
+ }
+ const uint32_t max_size = event_buffer_.size();
+ uint32_t start =
+ (current_index_ > max_size) ? current_index_ % max_size : max_size;
+ index = (index + start) % max_size;
+ return &event_buffer_[index];
+ }
+
+ private:
+ bool enabled_;
+ uint32_t current_index_;
+ std::vector<ProfileEvent> event_buffer_;
+};
+} // namespace profiling
+} // namespace tflite
+#endif // TFLITE_PROFILING_ENABLED
+#endif // TENSORFLOW_CONTRIB_LITE_PROFILING_PROFILE_BUFFER_H_
+
+// clang-format on
diff --git a/runtime/libs/profiling/include/profiling/profiler.h b/runtime/libs/profiling/include/profiling/profiler.h
new file mode 100644
index 000000000..ed3688140
--- /dev/null
+++ b/runtime/libs/profiling/include/profiling/profiler.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This header is derived from the following file (in TensorFlow v1.12)
+// 'externals/tensorflow/tensorflow/lite/profiling/profiler.h
+#ifndef TENSORFLOW_CONTRIB_LITE_PROFILING_PROFILER_H_
+#define TENSORFLOW_CONTRIB_LITE_PROFILING_PROFILER_H_
+
+#include <vector>
+
+#include "profiling/profile_buffer.h"
+
+#ifdef TFLITE_PROFILING_ENABLED
+
+namespace tflite {
+namespace profiling {
+class ScopedProfile;
+class ScopedOperatorProfile;
+
+// Controls whether profiling is enabled or disabled and collects profiles.
+// TFLite is used on platforms that don't have posix threads, so the profiler is
+// kept as simple as possible. It is designed to be used only on a single
+// thread.
+//
+// Profiles are collected using Scoped*Profile objects that begin and end a
+// profile event.
+// An example usage is shown in the example below:
+//
+// Say Worker class has a DoWork method and we are interested in profiling
+// the overall execution time for DoWork and time spent in Task1 and Task2
+// functions.
+//
+// class Worker {
+// public:
+// void DoWork() {
+// ScopedProfile(&controller, "DoWork");
+// Task1();
+// Task2();
+// .....
+// }
+//
+// void Task1() {
+// ScopedProfile(&controller, "Task1");
+// ....
+// }
+//
+// void Task2() {
+// ScopedProfile(&controller, "Task2");
+// }
+//
+// Profiler profiler;
+// }
+//
+// We instrument the functions that need to be profiled.
+//
+// Profile can be collected by enable profiling and then getting profile
+// events.
+//
+// void ProfileWorker() {
+// Worker worker;
+// worker.profiler.EnableProfiling();
+// worker.DoWork();
+// worker.profiler.DisableProfiling();
+// // Profiling is complete, extract profiles.
+// auto profile_events = worker.profiler.GetProfiles();
+// }
+//
+//
+class Profiler {
+ public:
+ Profiler() : buffer_(1024, false) {}
+
+ void StartProfiling() { buffer_.SetEnabled(true); }
+ void StopProfiling() { buffer_.SetEnabled(false); }
+ void Reset() { buffer_.Reset(); }
+ std::vector<const ProfileEvent*> GetProfileEvents() {
+ std::vector<const ProfileEvent*> profile_events;
+ profile_events.reserve(buffer_.Size());
+ for (size_t i = 0; i < buffer_.Size(); i++) {
+ profile_events.push_back(buffer_.At(i));
+ }
+ return profile_events;
+ }
+
+ private:
+ friend class ScopedProfile;
+ friend class ScopedOperatorProfile;
+ ProfileBuffer* GetProfileBuffer() { return &buffer_; }
+ ProfileBuffer buffer_;
+};
+
+class ScopedProfile {
+ public:
+ // Adds a profile event to profile that begins with the construction
+ // of object and ends when the object goes out of scope.
+ // The lifetime of tag should be at least the lifetime of profiler.
+
+ ScopedProfile(Profiler* profiler, const char* tag)
+ : buffer_(nullptr), event_handle_(0) {
+ if (profiler) {
+ buffer_ = profiler->GetProfileBuffer();
+ event_handle_ =
+ buffer_->BeginEvent(tag, ProfileEvent::EventType::DEFAULT, 0);
+ }
+ }
+ ~ScopedProfile() {
+ if (buffer_) {
+ buffer_->EndEvent(event_handle_);
+ }
+ }
+
+ private:
+ ProfileBuffer* buffer_;
+ int32_t event_handle_;
+};
+
+class ScopedOperatorProfile {
+ public:
+ // Adds a profile event to profile that begins with the construction
+ // of object and ends when the object goes out of scope.
+ // The lifetime of tag should be at least the lifetime of profiler.
+ ScopedOperatorProfile(Profiler* profiler, const char* tag, int node_index)
+ : buffer_(nullptr), event_handle_(0) {
+ if (profiler) {
+ buffer_ = profiler->GetProfileBuffer();
+ event_handle_ = buffer_->BeginEvent(
+ tag, ProfileEvent::EventType::OPERATOR_INVOKE_EVENT, node_index);
+ }
+ }
+
+ ~ScopedOperatorProfile() {
+ if (buffer_) {
+ buffer_->EndEvent(event_handle_);
+ }
+ }
+
+ private:
+ ProfileBuffer* buffer_;
+ int32_t event_handle_;
+};
+
+} // namespace profiling
+} // namespace tflite
+
+#define VARNAME_UNIQ(name, ctr) name##ctr
+
+#define SCOPED_OPERATOR_PROFILE(profiler, node_index) \
+ tflite::profiling::ScopedOperatorProfile VARNAME_UNIQ( \
+ _profile_, __COUNTER__)((profiler), "OpInvoke", (node_index))
+#else
+
+namespace tflite {
+namespace profiling {
+// A noop version of profiler when profiling is disabled.
+class Profiler {
+ public:
+ Profiler() {}
+ void StartProfiling() {}
+ void StopProfiling() {}
+ void Reset() {}
+ std::vector<const ProfileEvent*> GetProfileEvents() { return {}; }
+};
+} // namespace profiling
+} // namespace tflite
+
+#define SCOPED_OPERATOR_PROFILE(profiler, node_index)
+
+#endif // TFLITE_PROFILING_ENABLED
+
+#endif // TENSORFLOW_CONTRIB_LITE_PROFILING_PROFILER_H_
+
+// clang-format on
diff --git a/runtime/libs/profiling/include/profiling/profiling.h b/runtime/libs/profiling/include/profiling/profiling.h
new file mode 100644
index 000000000..79ad060c5
--- /dev/null
+++ b/runtime/libs/profiling/include/profiling/profiling.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_MISC_PROFILING_H__
+#define __NNFW_MISC_PROFILING_H__
+
+#include <iostream>
+
+namespace tflite
+{
+namespace profiling
+{
+class Profiler; // forward declaration
+}
+} // namespace tflite
+
+namespace profiling
+{
+
+class Context
+{
+public:
+ Context() : _sync(false), _profiler(nullptr) {}
+
+public:
+ const bool &sync(void) const { return _sync; }
+ tflite::profiling::Profiler *getProfiler() { return _profiler; }
+ void setProfiler(tflite::profiling::Profiler *p) { _profiler = p; }
+ void setSync(void) { _sync = true; }
+
+private:
+ bool _sync;
+ tflite::profiling::Profiler *_profiler;
+
+public:
+ static Context &get(void)
+ {
+ static Context ctx{};
+ return ctx;
+ }
+};
+
+} // namespace profiling
+#endif // __NNFW_MISC_PROFILING_H__
diff --git a/runtime/libs/profiling/include/profiling/time.h b/runtime/libs/profiling/include/profiling/time.h
new file mode 100644
index 000000000..03d18ddc8
--- /dev/null
+++ b/runtime/libs/profiling/include/profiling/time.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This header is derived from the following file (in TensorFlow v1.12)
+// 'externals/tensorflow/tensorflow/lite/profiling/time.h
+#ifndef TENSORFLOW_CONTRIB_LITE_PROFILING_TIME_H_
+#define TENSORFLOW_CONTRIB_LITE_PROFILING_TIME_H_
+
+#include <cstdint>
+
+namespace tflite {
+namespace profiling {
+namespace time {
+uint64_t NowMicros();
+} // namespace time
+} // namespace profiling
+} // namespace tflite
+#endif // TENSORFLOW_CONTRIB_LITE_PROFILING_TIME_H_
+
+// clang-format on
diff --git a/runtime/libs/profiling/src/profiling/time.cpp b/runtime/libs/profiling/src/profiling/time.cpp
new file mode 100644
index 000000000..4e045556e
--- /dev/null
+++ b/runtime/libs/profiling/src/profiling/time.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This header is derived from the following file (in TensorFlow v1.12)
+// 'externals/tensorflow/tensorflow/lite/profiling/time.cpp
+#include "profiling/time.h"
+
+#if defined(_MSC_VER)
+#include <chrono> // NOLINT(build/c++11)
+#else
+#include <sys/time.h>
+#endif
+
+namespace tflite {
+namespace profiling {
+namespace time {
+
+#if defined(_MSC_VER)
+
+uint64_t NowMicros() {
+ return std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+}
+
+#else
+
+uint64_t NowMicros() {
+ struct timeval tv;
+ gettimeofday(&tv, nullptr);
+ return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
+}
+
+#endif // defined(_MSC_VER)
+
+} // namespace time
+} // namespace profiling
+} // namespace tflite
+
+// clang-format on
diff --git a/runtime/libs/rua/CMakeLists.txt b/runtime/libs/rua/CMakeLists.txt
new file mode 100644
index 000000000..07ad9ea26
--- /dev/null
+++ b/runtime/libs/rua/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(core)
+add_subdirectory(dyn)
+add_subdirectory(anchor)
+add_subdirectory(shim)
diff --git a/runtime/libs/rua/README.md b/runtime/libs/rua/README.md
new file mode 100644
index 000000000..aea4ce033
--- /dev/null
+++ b/runtime/libs/rua/README.md
@@ -0,0 +1,4 @@
+# rua
+
+_rua_ is a **RU**ntime **A**bstraction layer which allows us to switch between multiple
+Android NN rutime during execution (not loading time).
diff --git a/runtime/libs/rua/anchor/CMakeLists.txt b/runtime/libs/rua/anchor/CMakeLists.txt
new file mode 100644
index 000000000..6e65641f4
--- /dev/null
+++ b/runtime/libs/rua/anchor/CMakeLists.txt
@@ -0,0 +1,9 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(nnfw_lib_rua_anchor STATIC ${SOURCES})
+set_target_properties(nnfw_lib_rua_anchor PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(nnfw_lib_rua_anchor PUBLIC include)
+target_link_libraries(nnfw_lib_rua_anchor PUBLIC nnfw_lib_rua_core)
+target_link_libraries(nnfw_lib_rua_anchor PRIVATE nnfw_lib_rua_dyn)
+target_link_libraries(nnfw_lib_rua_anchor PRIVATE nnfw_common)
+target_link_libraries(nnfw_lib_rua_anchor PRIVATE nnfw_coverage)
diff --git a/runtime/libs/rua/anchor/include/rua/Anchor.h b/runtime/libs/rua/anchor/include/rua/Anchor.h
new file mode 100644
index 000000000..f6056ab4e
--- /dev/null
+++ b/runtime/libs/rua/anchor/include/rua/Anchor.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_RUA_ANCHOR_H__
+#define __NNFW_RUA_ANCHOR_H__
+
+#include <rua/Service.h>
+
+namespace rua
+{
+
+/**
+ * @brief Global Runtime Abstraction Context
+ *
+ * "set" will have global effect (within each process).
+ */
+struct Anchor
+{
+ static const RuntimeService *get(void);
+ static void set(const RuntimeService *svc);
+};
+
+} // namespace rua
+
+#endif // __NNFW_RUA_ANCHOR_H__
diff --git a/runtime/libs/rua/anchor/src/Anchor.cpp b/runtime/libs/rua/anchor/src/Anchor.cpp
new file mode 100644
index 000000000..a78cca19e
--- /dev/null
+++ b/runtime/libs/rua/anchor/src/Anchor.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rua/Anchor.h"
+#include <rua/DynamicBinder.h>
+
+namespace
+{
+
+const rua::RuntimeService *anchored_service = rua::DynamicBinder::get();
+
+} // namespace
+
+namespace rua
+{
+
+const RuntimeService *Anchor::get(void) { return anchored_service; }
+void Anchor::set(const RuntimeService *service) { anchored_service = service; }
+
+} // namespace rua
diff --git a/runtime/libs/rua/core/CMakeLists.txt b/runtime/libs/rua/core/CMakeLists.txt
new file mode 100644
index 000000000..f7d41f657
--- /dev/null
+++ b/runtime/libs/rua/core/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library(nnfw_lib_rua_core INTERFACE)
+target_include_directories(nnfw_lib_rua_core INTERFACE include)
+target_link_libraries(nnfw_lib_rua_core INTERFACE nnfw_lib_nnapi)
diff --git a/runtime/libs/rua/core/include/rua/Service.h b/runtime/libs/rua/core/include/rua/Service.h
new file mode 100644
index 000000000..2129b7ac2
--- /dev/null
+++ b/runtime/libs/rua/core/include/rua/Service.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Service.h
+ * @brief Core abstraction that RUA depends on.
+ */
+#ifndef __NNFW_RUA_SERVICE_H__
+#define __NNFW_RUA_SERVICE_H__
+
+#include "NeuralNetworks.h"
+
+struct ANeuralNetworksMemory;
+struct ANeuralNetworksEvent;
+
+struct ANeuralNetworksModel;
+struct ANeuralNetworksCompilation;
+struct ANeuralNetworksExecution;
+
+namespace rua
+{
+
+/**
+ * @brief A wrapper for ANeuralNetworkMemory API
+ */
+struct MemoryService
+{
+ virtual ~MemoryService() = default;
+
+ virtual int createFromFd(size_t size, int protect, int fd, size_t offset,
+ ANeuralNetworksMemory **memory) const = 0;
+
+ virtual void free(ANeuralNetworksMemory *memory) const = 0;
+};
+
+/**
+ * @brief A wrapper for ANeuralNetworkModel API
+ */
+struct ModelService
+{
+ virtual ~ModelService() = default;
+
+ virtual int create(ANeuralNetworksModel **model) const = 0;
+
+ virtual int addOperand(ANeuralNetworksModel *model,
+ const ANeuralNetworksOperandType *type) const = 0;
+
+ virtual int setOperandValue(ANeuralNetworksModel *model, int32_t index, const void *buffer,
+ size_t length) const = 0;
+
+ virtual int setOperandValueFromMemory(ANeuralNetworksModel *model, int32_t index,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length) const = 0;
+
+ virtual int addOperation(ANeuralNetworksModel *model, ANeuralNetworksOperationType type,
+ uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs) const = 0;
+
+ virtual int identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs) const = 0;
+
+ virtual int relaxComputationFloat32toFloat16(ANeuralNetworksModel *model, bool allow) const = 0;
+
+ virtual int finish(ANeuralNetworksModel *model) const = 0;
+
+ virtual void free(ANeuralNetworksModel *model) const = 0;
+};
+
+/**
+ * @brief A wrapper for ANeuralNetworkCompilation API
+ */
+struct CompilationService
+{
+ virtual ~CompilationService() = default;
+
+ virtual int create(ANeuralNetworksModel *model,
+ ANeuralNetworksCompilation **compilation) const = 0;
+
+ virtual int setPreference(ANeuralNetworksCompilation *compilation, int32_t preference) const = 0;
+ virtual int finish(ANeuralNetworksCompilation *compilation) const = 0;
+
+ virtual void free(ANeuralNetworksCompilation *compilation) const = 0;
+};
+
+/**
+ * @brief A wrapper for ANeuralNetworkExecution API
+ */
+struct ExecutionService
+{
+ virtual ~ExecutionService() = default;
+
+ virtual int create(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution) const = 0;
+
+ virtual void free(ANeuralNetworksExecution *execution) const = 0;
+
+ virtual int setInput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, const void *buffer,
+ size_t length) const = 0;
+
+ virtual int setInputFromMemory(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length) const = 0;
+
+ virtual int setOutput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, void *buffer,
+ size_t length) const = 0;
+
+ virtual int setOutputFromMemory(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length) const = 0;
+
+ virtual int startCompute(ANeuralNetworksExecution *execution,
+ ANeuralNetworksEvent **event) const = 0;
+};
+
+/**
+ * @brief A wrapper for ANeuralNetworkEvent API
+ */
+struct EventService
+{
+ virtual int wait(ANeuralNetworksEvent *event) const = 0;
+ virtual void free(ANeuralNetworksEvent *event) const = 0;
+};
+
+/**
+ * @brief A wrapper for Android NN rutime itself
+ */
+struct RuntimeService
+{
+ virtual ~RuntimeService() = default;
+
+ virtual const MemoryService *memory(void) const = 0;
+ virtual const ModelService *model(void) const = 0;
+ virtual const CompilationService *compilation(void) const = 0;
+ virtual const ExecutionService *execution(void) const = 0;
+ virtual const EventService *event(void) const = 0;
+};
+
+} // namespace rua
+
+#endif // __NNFW_RUA_SERVICE_H__
diff --git a/runtime/libs/rua/dyn/CMakeLists.txt b/runtime/libs/rua/dyn/CMakeLists.txt
new file mode 100644
index 000000000..3f9ac8928
--- /dev/null
+++ b/runtime/libs/rua/dyn/CMakeLists.txt
@@ -0,0 +1,8 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(nnfw_lib_rua_dyn STATIC ${SOURCES})
+set_target_properties(nnfw_lib_rua_dyn PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(nnfw_lib_rua_dyn PUBLIC include)
+target_link_libraries(nnfw_lib_rua_dyn PUBLIC nnfw_lib_rua_core)
+target_link_libraries(nnfw_lib_rua_dyn PRIVATE nnfw_common)
+target_link_libraries(nnfw_lib_rua_dyn PRIVATE nnfw_coverage)
diff --git a/runtime/libs/rua/dyn/include/rua/DynamicBinder.h b/runtime/libs/rua/dyn/include/rua/DynamicBinder.h
new file mode 100644
index 000000000..1e2d30665
--- /dev/null
+++ b/runtime/libs/rua/dyn/include/rua/DynamicBinder.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_RUA_DYNAMIC_BINDER_H__
+#define __NNFW_RUA_DYNAMIC_BINDER_H__
+
+#include <rua/Service.h>
+
+namespace rua
+{
+
+/**
+ * @brief Bind Android NN runtime implementation via dlopen & dlsym
+ */
+struct DynamicBinder
+{
+ static const rua::RuntimeService *get(void);
+};
+
+} // namespace rua
+
+#endif // __NNFW_RUA_DYNAMIC_BINDER_H__
diff --git a/runtime/libs/rua/dyn/src/DynamicBinder.cpp b/runtime/libs/rua/dyn/src/DynamicBinder.cpp
new file mode 100644
index 000000000..fa3f0bb1e
--- /dev/null
+++ b/runtime/libs/rua/dyn/src/DynamicBinder.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rua/DynamicBinder.h"
+
+#include "NeuralNetworksLoadHelpers.h"
+
+using namespace rua;
+
+//
+// Memory
+//
+namespace
+{
+
+typedef int (*ANeuralNetworksMemory_createFromFd_fn)(size_t size, int protect, int fd,
+ size_t offset, ANeuralNetworksMemory **memory);
+
+typedef void (*ANeuralNetworksMemory_free_fn)(ANeuralNetworksMemory *memory);
+
+struct MemoryServiceImpl final : public MemoryService
+{
+ int createFromFd(size_t size, int protect, int fd, size_t offset,
+ ANeuralNetworksMemory **memory) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksMemory_createFromFd);
+ EXECUTE_FUNCTION_RETURN(size, protect, fd, offset, memory);
+ }
+
+ void free(ANeuralNetworksMemory *memory) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksMemory_free);
+ EXECUTE_FUNCTION(memory);
+ }
+};
+
+} // namespace
+
+//
+// Event
+//
+namespace
+{
+
+typedef int (*ANeuralNetworksEvent_wait_fn)(ANeuralNetworksEvent *event);
+
+typedef void (*ANeuralNetworksEvent_free_fn)(ANeuralNetworksEvent *event);
+
+struct EventServiceImpl final : public EventService
+{
+
+ int wait(ANeuralNetworksEvent *event) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksEvent_wait);
+ EXECUTE_FUNCTION_RETURN(event);
+ }
+
+ void free(ANeuralNetworksEvent *event) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksEvent_free);
+ EXECUTE_FUNCTION(event);
+ }
+};
+
+} // namespace
+
+//
+// Model
+//
+namespace
+{
+
+typedef int (*ANeuralNetworksModel_create_fn)(ANeuralNetworksModel **model);
+
+typedef int (*ANeuralNetworksModel_finish_fn)(ANeuralNetworksModel *model);
+
+typedef void (*ANeuralNetworksModel_free_fn)(ANeuralNetworksModel *model);
+
+typedef int (*ANeuralNetworksModel_addOperand_fn)(ANeuralNetworksModel *model,
+ const ANeuralNetworksOperandType *type);
+
+typedef int (*ANeuralNetworksModel_setOperandValue_fn)(ANeuralNetworksModel *model, int32_t index,
+ const void *buffer, size_t length);
+
+typedef int (*ANeuralNetworksModel_setOperandValueFromMemory_fn)(
+ ANeuralNetworksModel *model, int32_t index, const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length);
+
+typedef int (*ANeuralNetworksModel_addOperation_fn)(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationType type,
+ uint32_t inputCount, const uint32_t *inputs,
+ uint32_t outputCount, const uint32_t *outputs);
+
+typedef int (*ANeuralNetworksModel_identifyInputsAndOutputs_fn)(ANeuralNetworksModel *model,
+ uint32_t inputCount,
+ const uint32_t *inputs,
+ uint32_t outputCount,
+ const uint32_t *outputs);
+
+typedef int (*ANeuralNetworksModel_relaxComputationFloat32toFloat16_fn)(ANeuralNetworksModel *model,
+ bool allow);
+
+struct ModelServiceImpl final : public ModelService
+{
+ int create(ANeuralNetworksModel **model) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_create);
+ EXECUTE_FUNCTION_RETURN(model);
+ }
+
+ int addOperand(ANeuralNetworksModel *model, const ANeuralNetworksOperandType *type) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_addOperand);
+ EXECUTE_FUNCTION_RETURN(model, type);
+ }
+ int setOperandValue(ANeuralNetworksModel *model, int32_t index, const void *buffer,
+ size_t length) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_setOperandValue);
+ EXECUTE_FUNCTION_RETURN(model, index, buffer, length);
+ }
+
+ int setOperandValueFromMemory(ANeuralNetworksModel *model, int32_t index,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_setOperandValueFromMemory);
+ EXECUTE_FUNCTION_RETURN(model, index, memory, offset, length);
+ }
+
+ int addOperation(ANeuralNetworksModel *model, ANeuralNetworksOperationType type,
+ uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_addOperation);
+ EXECUTE_FUNCTION_RETURN(model, type, inputCount, inputs, outputCount, outputs);
+ }
+
+ int identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_identifyInputsAndOutputs);
+ EXECUTE_FUNCTION_RETURN(model, inputCount, inputs, outputCount, outputs);
+ }
+
+ int relaxComputationFloat32toFloat16(ANeuralNetworksModel *model, bool allow) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_relaxComputationFloat32toFloat16);
+ EXECUTE_FUNCTION_RETURN(model, allow);
+ }
+
+ int finish(ANeuralNetworksModel *model) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_finish);
+ EXECUTE_FUNCTION_RETURN(model);
+ }
+
+ void free(ANeuralNetworksModel *model) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksModel_free);
+ EXECUTE_FUNCTION(model);
+ }
+};
+
+} // namespace
+
+//
+// Compilation
+//
+namespace
+{
+
+typedef int (*ANeuralNetworksCompilation_create_fn)(ANeuralNetworksModel *model,
+ ANeuralNetworksCompilation **compilation);
+
+typedef void (*ANeuralNetworksCompilation_free_fn)(ANeuralNetworksCompilation *compilation);
+
+typedef int (*ANeuralNetworksCompilation_setPreference_fn)(ANeuralNetworksCompilation *compilation,
+ int32_t preference);
+
+typedef int (*ANeuralNetworksCompilation_finish_fn)(ANeuralNetworksCompilation *compilation);
+
+struct CompilationServiceImpl : public CompilationService
+{
+
+ int create(ANeuralNetworksModel *model, ANeuralNetworksCompilation **compilation) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksCompilation_create);
+ EXECUTE_FUNCTION_RETURN(model, compilation);
+ }
+
+ int setPreference(ANeuralNetworksCompilation *compilation, int32_t preference) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksCompilation_setPreference);
+ EXECUTE_FUNCTION_RETURN(compilation, preference);
+ }
+
+ int finish(ANeuralNetworksCompilation *compilation) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksCompilation_finish);
+ EXECUTE_FUNCTION_RETURN(compilation);
+ }
+
+ void free(ANeuralNetworksCompilation *compilation) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksCompilation_free);
+ EXECUTE_FUNCTION(compilation);
+ }
+};
+
+} // namespace
+
+//
+// Exceution
+//
+namespace
+{
+
+typedef int (*ANeuralNetworksExecution_create_fn)(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution);
+
+typedef void (*ANeuralNetworksExecution_free_fn)(ANeuralNetworksExecution *execution);
+
+typedef int (*ANeuralNetworksExecution_setInput_fn)(ANeuralNetworksExecution *execution,
+ int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const void *buffer, size_t length);
+
+typedef int (*ANeuralNetworksExecution_setInputFromMemory_fn)(
+ ANeuralNetworksExecution *execution, int32_t index, const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset, size_t length);
+
+typedef int (*ANeuralNetworksExecution_setOutput_fn)(ANeuralNetworksExecution *execution,
+ int32_t index,
+ const ANeuralNetworksOperandType *type,
+ void *buffer, size_t length);
+
+typedef int (*ANeuralNetworksExecution_setOutputFromMemory_fn)(
+ ANeuralNetworksExecution *execution, int32_t index, const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset, size_t length);
+
+typedef int (*ANeuralNetworksExecution_startCompute_fn)(ANeuralNetworksExecution *execution,
+ ANeuralNetworksEvent **event);
+
+struct ExecutionServiceImpl : public ExecutionService
+{
+
+ int create(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksExecution_create);
+ EXECUTE_FUNCTION_RETURN(compilation, execution);
+ }
+
+ int setInput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, const void *buffer,
+ size_t length) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksExecution_setInput);
+ EXECUTE_FUNCTION_RETURN(execution, index, type, buffer, length);
+ }
+
+ int setInputFromMemory(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksExecution_setInputFromMemory);
+ EXECUTE_FUNCTION_RETURN(execution, index, type, memory, offset, length);
+ }
+
+ int setOutput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, void *buffer, size_t length) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksExecution_setOutput);
+ EXECUTE_FUNCTION_RETURN(execution, index, type, buffer, length);
+ }
+
+ int setOutputFromMemory(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksExecution_setOutputFromMemory);
+ EXECUTE_FUNCTION_RETURN(execution, index, type, memory, offset, length);
+ }
+
+ int startCompute(ANeuralNetworksExecution *execution, ANeuralNetworksEvent **event) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksExecution_startCompute);
+ EXECUTE_FUNCTION_RETURN(execution, event);
+ }
+
+ void free(ANeuralNetworksExecution *execution) const override
+ {
+ LOAD_FUNCTION(ANeuralNetworksExecution_free);
+ EXECUTE_FUNCTION(execution);
+ }
+};
+
+} // namespace
+
+//
+// Runtime
+//
+namespace
+{
+
+class RuntimeImpl final : public RuntimeService
+{
+public:
+ const MemoryService *memory(void) const override { return &_memory; }
+ const EventService *event(void) const override { return &_event; }
+
+ const ModelService *model(void) const override { return &_model; }
+ const CompilationService *compilation(void) const override { return &_compilation; }
+ const ExecutionService *execution(void) const override { return &_execution; }
+
+private:
+ MemoryServiceImpl _memory;
+ EventServiceImpl _event;
+
+ ModelServiceImpl _model;
+ CompilationServiceImpl _compilation;
+ ExecutionServiceImpl _execution;
+};
+
+} // namespace
+
+namespace rua
+{
+
+const RuntimeService *DynamicBinder::get(void)
+{
+ static RuntimeImpl runtime;
+ return &runtime;
+}
+
+} // namespace rua
diff --git a/runtime/libs/rua/shim/CMakeLists.txt b/runtime/libs/rua/shim/CMakeLists.txt
new file mode 100644
index 000000000..814db5f7f
--- /dev/null
+++ b/runtime/libs/rua/shim/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(nnfw_lib_rua_shim INTERFACE)
+target_include_directories(nnfw_lib_rua_shim INTERFACE include)
+target_link_libraries(nnfw_lib_rua_shim INTERFACE nnfw_lib_rua_core)
+target_link_libraries(nnfw_lib_rua_shim INTERFACE nnfw_lib_rua_anchor)
diff --git a/runtime/libs/rua/shim/include/rua/Shim.h b/runtime/libs/rua/shim/include/rua/Shim.h
new file mode 100644
index 000000000..755803e3b
--- /dev/null
+++ b/runtime/libs/rua/shim/include/rua/Shim.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_RUA_SHIM_H__
+#define __NNFW_RUA_SHIM_H__
+
+#include <rua/Anchor.h>
+
+//
+// Memory
+//
+inline int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset,
+ ANeuralNetworksMemory **memory)
+{
+ return rua::Anchor::get()->memory()->createFromFd(size, protect, fd, offset, memory);
+}
+
+inline void ANeuralNetworksMemory_free(ANeuralNetworksMemory *memory)
+{
+ return rua::Anchor::get()->memory()->free(memory);
+}
+
+//
+// Event
+//
+inline int ANeuralNetworksEvent_wait(ANeuralNetworksEvent *event)
+{
+ return rua::Anchor::get()->event()->wait(event);
+}
+
+inline void ANeuralNetworksEvent_free(ANeuralNetworksEvent *event)
+{
+ return rua::Anchor::get()->event()->free(event);
+}
+
+//
+// Model
+//
+inline int ANeuralNetworksModel_create(ANeuralNetworksModel **model)
+{
+ return rua::Anchor::get()->model()->create(model);
+}
+
+inline int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model,
+ const ANeuralNetworksOperandType *type)
+{
+ return rua::Anchor::get()->model()->addOperand(model, type);
+}
+
+inline int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index,
+ const void *buffer, size_t length)
+{
+ return rua::Anchor::get()->model()->setOperandValue(model, index, buffer, length);
+}
+
+inline int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model,
+ int32_t index,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ return rua::Anchor::get()->model()->setOperandValueFromMemory(model, index, memory, offset,
+ length);
+}
+
+inline int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationType type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ return rua::Anchor::get()->model()->addOperation(model, type, inputCount, inputs, outputCount,
+ outputs);
+}
+
+inline int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model,
+ uint32_t inputCount,
+ const uint32_t *inputs,
+ uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ return rua::Anchor::get()->model()->identifyInputsAndOutputs(model, inputCount, inputs,
+ outputCount, outputs);
+}
+
+inline int ANeuralNetworksModel_relaxComputationFloat32toFloat16(ANeuralNetworksModel *model,
+ bool allow)
+{
+ return rua::Anchor::get()->model()->relaxComputationFloat32toFloat16(model, allow);
+}
+
+inline int ANeuralNetworksModel_finish(ANeuralNetworksModel *model)
+{
+ return rua::Anchor::get()->model()->finish(model);
+}
+
+inline void ANeuralNetworksModel_free(ANeuralNetworksModel *model)
+{
+ return rua::Anchor::get()->model()->free(model);
+}
+
+//
+// Compilation
+//
+inline int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model,
+ ANeuralNetworksCompilation **compilation)
+{
+ return rua::Anchor::get()->compilation()->create(model, compilation);
+}
+
+inline int ANeuralNetworksCompilation_setPreference(ANeuralNetworksCompilation *compilation,
+ int32_t preference)
+{
+ return rua::Anchor::get()->compilation()->setPreference(compilation, preference);
+}
+
+inline int ANeuralNetworksCompilation_finish(ANeuralNetworksCompilation *compilation)
+{
+ return rua::Anchor::get()->compilation()->finish(compilation);
+}
+
+inline void ANeuralNetworksCompilation_free(ANeuralNetworksCompilation *compilation)
+{
+ return rua::Anchor::get()->compilation()->free(compilation);
+}
+
+//
+// Execution
+//
+inline int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution)
+{
+ return rua::Anchor::get()->execution()->create(compilation, execution);
+}
+
+inline int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const void *buffer, size_t length)
+{
+ return rua::Anchor::get()->execution()->setInput(execution, index, type, buffer, length);
+}
+
+inline int ANeuralNetworksExecution_setInputFromMemory(ANeuralNetworksExecution *execution,
+ int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ return rua::Anchor::get()->execution()->setInputFromMemory(execution, index, type, memory, offset,
+ length);
+}
+
+inline int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, void *buffer,
+ size_t length)
+{
+ return rua::Anchor::get()->execution()->setOutput(execution, index, type, buffer, length);
+}
+
+inline int ANeuralNetworksExecution_setOutputFromMemory(ANeuralNetworksExecution *execution,
+ int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ return rua::Anchor::get()->execution()->setOutputFromMemory(execution, index, type, memory,
+ offset, length);
+}
+
+inline int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution,
+ ANeuralNetworksEvent **event)
+{
+ return rua::Anchor::get()->execution()->startCompute(execution, event);
+}
+
+inline void ANeuralNetworksExecution_free(ANeuralNetworksExecution *execution)
+{
+ return rua::Anchor::get()->execution()->free(execution);
+}
+
+#endif // __NNFW_RUA_SHIM_H__
diff --git a/runtime/libs/tflite/CMakeLists.txt b/runtime/libs/tflite/CMakeLists.txt
new file mode 100644
index 000000000..93a3c9789
--- /dev/null
+++ b/runtime/libs/tflite/CMakeLists.txt
@@ -0,0 +1,27 @@
+nnfw_find_package(TensorFlowLite EXACT 1.13.1 QUIET)
+if(NOT TensorFlowLite_FOUND)
+ message(STATUS "Check tensorflow lite library extension build: need tensorflow lite library")
+ return()
+endif(NOT TensorFlowLite_FOUND)
+
+add_subdirectory(port)
+
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(nnfw_lib_tflite STATIC ${SOURCES})
+set_target_properties(nnfw_lib_tflite PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(nnfw_lib_tflite PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(nnfw_lib_tflite PUBLIC tensorflow-lite-ex)
+target_link_libraries(nnfw_lib_tflite PUBLIC nnfw_lib_misc)
+target_link_libraries(nnfw_lib_tflite PRIVATE ${LIB_PTHREAD} dl)
+target_link_libraries(nnfw_lib_tflite PRIVATE nnfw_common)
+target_link_libraries(nnfw_lib_tflite PRIVATE nnfw_coverage)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+add_executable(nnfw_lib_tflite_test_TensorView src/TensorView.test.cpp)
+target_link_libraries(nnfw_lib_tflite_test_TensorView nnfw_lib_tflite)
diff --git a/runtime/libs/tflite/include/tflite/Assert.h b/runtime/libs/tflite/include/tflite/Assert.h
new file mode 100644
index 000000000..148ac7e01
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/Assert.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Assert.h
+ * @brief This file contains helper function of assertion
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_ASSERT_H__
+#define __NNFW_TFLITE_ASSERT_H__
+
+#include "tensorflow/lite/context.h"
+
+#include <sstream>
+
+#define STR_DETAIL(value) #value
+#define STR(value) STR_DETAIL(value)
+
+#define TFLITE_ENSURE(exp) \
+ { \
+ const TfLiteStatus status = (exp); \
+ \
+ if (status != kTfLiteOk) \
+ { \
+ std::ostringstream ss; \
+ ss << #exp << " failed (" << __FILE__ << ":" << __LINE__ << ")"; \
+ throw std::runtime_error{ss.str()}; \
+ } \
+ }
+
+#endif // __NNFW_TFLITE_ASSERT_H__
diff --git a/runtime/libs/tflite/include/tflite/Diff.h b/runtime/libs/tflite/include/tflite/Diff.h
new file mode 100644
index 000000000..fdc1a310b
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/Diff.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Diff.h
+ * @brief This file contains classes for testing correctess of implementation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_DIFF_H__
+#define __NNFW_TFLITE_DIFF_H__
+
+#include "tensorflow/lite/interpreter.h"
+
+#include "misc/RandomGenerator.h"
+#include "misc/tensor/Index.h"
+#include "misc/tensor/Diff.h"
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Comparator.h"
+
+#include "tflite/TensorView.h"
+
+#include <functional>
+#include <vector>
+
+/**
+ * @brief Class to define TfLite interpreter match application
+ */
+class TfLiteInterpMatchApp
+{
+public:
+ /**
+ * @brief Construct a new TfLiteInterpMatchApp object with Comparator
+ * @param[in] comparator Comparator object for tensor comparation
+ */
+ TfLiteInterpMatchApp(const nnfw::misc::tensor::Comparator &comparator)
+ : _verbose{false}, _comparator(comparator)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get reference verbose for debugging information
+ * @return Reference of verbose value
+ */
+ int &verbose(void) { return _verbose; }
+
+private:
+ int _verbose;
+
+public:
+ /**
+ * @brief Run two interpreter and return the output matching
+ * @param[in] pure Interpreter object of expected(with TfLite)
+ * @param[in] nnapi Interpreter object of obtained(through NNAPI)
+ * @return @c true if two Interpreter results are same, otherwise @c false
+ */
+ bool run(::tflite::Interpreter &pure, ::tflite::Interpreter &nnapi) const;
+ /**
+ * @brief Compare two TensorView values and return the match result
+ * @param[in] expected TensorView object to read expected values
+ * @param[in] obtained TensorView object to read obtained values
+ * @param[in] id Tensor ID value used for debug message
+ * @return @c true if two TensorView values are same, otherwise @c false
+ */
+ template <typename T>
+ bool compareSingleTensorView(const nnfw::tflite::TensorView<T> &expected,
+ const nnfw::tflite::TensorView<T> &obtained, int id) const;
+
+private:
+ const nnfw::misc::tensor::Comparator &_comparator;
+};
+
+#endif // __NNFW_TFLITE_DIFF_H__
diff --git a/runtime/libs/tflite/include/tflite/FeatureView.h b/runtime/libs/tflite/include/tflite/FeatureView.h
new file mode 100644
index 000000000..a8f069c40
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/FeatureView.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file FeatureView.h
+ * @brief This file contains FeatureView class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_FEATURE_VIEW_H__
+#define __NNFW_TFLITE_FEATURE_VIEW_H__
+
+#include "tensorflow/lite/interpreter.h"
+
+#include "tflite/InputIndex.h"
+#include "tflite/OutputIndex.h"
+
+#include "misc/feature/Shape.h"
+#include "misc/feature/Reader.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+template <typename T> class FeatureView;
+
+/**
+ * @brief Class to support reading element of float type feature
+ */
+template <> class FeatureView<float> : public nnfw::misc::feature::Reader<float>
+{
+public:
+ /**
+ * @brief Construct a new FeatureView object
+ * @param[in] interp Interpreter to read from
+ * @param[in] index InputIndex index of input
+ */
+ FeatureView(::tflite::Interpreter &interp, const InputIndex &index);
+ /**
+ * @brief Construct a new FeatureView object
+ * @param[in] interp Interpreter to read from
+ * @param[in] index OutputIndex index of output
+ */
+ FeatureView(::tflite::Interpreter &interp, const OutputIndex &index);
+
+public:
+ /**
+ * @brief Get value of element using channel, row and column index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ float at(uint32_t ch, uint32_t row, uint32_t col) const;
+ /**
+ * @brief Get reference of element using channel, row and column index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Reference of element
+ */
+ float &at(uint32_t ch, uint32_t row, uint32_t col);
+
+ float at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const = 0;
+
+private:
+ /**
+ * @brief Get offset of element from channel, row and column index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Offset of element
+ */
+ uint32_t getElementOffset(uint32_t ch, uint32_t row, uint32_t col) const
+ {
+ uint32_t res = 0;
+
+ // TensorFlow Lite assumes that NHWC ordering for tessor
+ res += row * _shape.W * _shape.C;
+ res += col * _shape.C;
+ res += ch;
+
+ return res;
+ }
+
+private:
+ nnfw::misc::feature::Shape _shape;
+ float *_base;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_FEATURE_VIEW_H__
diff --git a/runtime/libs/tflite/include/tflite/InputIndex.h b/runtime/libs/tflite/include/tflite/InputIndex.h
new file mode 100644
index 000000000..f535b2626
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/InputIndex.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file InputIndex.h
+ * @brief This file contains InputIndex class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_INPUT_INDEX_H__
+#define __NNFW_TFLITE_INPUT_INDEX_H__
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to express index of input
+ */
+class InputIndex
+{
+public:
+ /**
+ * @brief Construct a new InputIndex object with index value
+ * @param [in] index The value of index
+ */
+ InputIndex(int index) : _index(index)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get index value as int
+ * @return Index value as int
+ */
+ int asInt(void) const { return _index; }
+
+private:
+ int _index;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_INPUT_INDEX_H__
diff --git a/runtime/libs/tflite/include/tflite/InterpreterSession.h b/runtime/libs/tflite/include/tflite/InterpreterSession.h
new file mode 100644
index 000000000..deaf05a7f
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/InterpreterSession.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file InterpreterSession.h
+ * @brief This file contains InterpreterSession class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_INTERPRETER_SESSION_H__
+#define __NNFW_TFLITE_INTERPRETER_SESSION_H__
+
+#include "Session.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to define TfLite interpreter session which is inherited from Session class
+ */
+class InterpreterSession final : public Session
+{
+public:
+ /**
+ * @brief Construct a InterpreterSession object with interpreter of TfLite
+ * @param[in] interp The TfLite interpreter pointer
+ */
+ InterpreterSession(::tflite::Interpreter *interp) : _interp{interp}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get TfLite interpreter pointer
+ * @return The TfLite interpreter
+ */
+ ::tflite::Interpreter *interp(void) override { return _interp; }
+
+public:
+ /**
+ * @brief Prepare the TfLite interpreter session
+ * @return @c true if tensor preparation is successful, otherwise @c false
+ */
+ bool prepare(void) override
+ {
+ _interp->UseNNAPI(false);
+
+ if (kTfLiteOk != _interp->AllocateTensors())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief Run the Invoke function of TfLite interpreter
+ * @return @c true if Invoke() is successful, otherwise @c false
+ */
+ bool run(void) override
+ {
+ // Return true if Invoke returns kTfLiteOk
+ return kTfLiteOk == _interp->Invoke();
+ }
+
+ /**
+ * @brief Tear down TfLite interpreter session
+ * @return @c true always
+ */
+ bool teardown(void) override
+ {
+ // Do NOTHING currently
+ return true;
+ }
+
+private:
+ ::tflite::Interpreter *const _interp;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_INTERPRETER_SESSION_H__
diff --git a/runtime/libs/tflite/include/tflite/NNAPISession.h b/runtime/libs/tflite/include/tflite/NNAPISession.h
new file mode 100644
index 000000000..f430e86d3
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/NNAPISession.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file NNAPISession.h
+ * @brief This file contains NNAPISession class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_NNAPI_SESSION_H__
+#define __NNFW_TFLITE_NNAPI_SESSION_H__
+
+#include "Session.h"
+#include "tflite/ext/nnapi_delegate.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to define NNAPI interpreter session which is inherited from Session class
+ */
+class NNAPISession final : public Session
+{
+public:
+ /**
+ * @brief Construct a NNAPISession object with interpreter of TfLite
+ * @param[in] interp The TfLite interpreter pointer
+ * @note Invoke BuildGraph() of NNAPI delegate from Interpreter
+ */
+ NNAPISession(::tflite::Interpreter *interp) : _interp{interp}
+ {
+ // Construct Graph from Interpreter
+ // primary_subgraph: Experimental interface. Return 1st sugbraph
+ _delegate.BuildGraph(&interp->primary_subgraph());
+ }
+
+public:
+ /**
+ * @brief Get TfLite interpreter pointer
+ * @return The TfLite interpreter
+ */
+ ::tflite::Interpreter *interp(void) override { return _interp; }
+
+public:
+ /**
+ * @brief Prepare the TfLite interpreter session
+ * @return @c true if tensor preparation is successful, otherwise @c false
+ */
+ bool prepare(void) override
+ {
+ // Explicitly turn off T/F lite internal NNAPI delegation in order to use locally defined
+ // NNAPI delegation.
+ _interp->UseNNAPI(false);
+
+ if (kTfLiteOk != _interp->AllocateTensors())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief Run the Invoke function of NNAPI delegate
+ * @return @c true if Invoke() is successful, otherwise @c false
+ */
+ bool run(void) override { return kTfLiteOk == _delegate.Invoke(&_interp->primary_subgraph()); }
+
+ /**
+ * @brief Tear down TfLite interpreter session
+ * @return @c true always
+ */
+ bool teardown(void) override
+ {
+ // DO NOTHING
+ return true;
+ }
+
+private:
+ ::tflite::Interpreter *const _interp;
+ nnfw::tflite::NNAPIDelegate _delegate;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_NNAPI_SESSION_H__
diff --git a/runtime/libs/tflite/include/tflite/OutputIndex.h b/runtime/libs/tflite/include/tflite/OutputIndex.h
new file mode 100644
index 000000000..dd1ca8d44
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/OutputIndex.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file OutputIndex.h
+ * @brief This file contains OutputIndex class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_OUTPUT_INDEX_H__
+#define __NNFW_TFLITE_OUTPUT_INDEX_H__
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to define OutputIndex
+ */
+class OutputIndex
+{
+public:
+ /**
+ * @brief Construct a OutputIndex object with index value
+ * @param[in] index The value of index
+ */
+ OutputIndex(int index) : _index(index)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get index value as int
+ * @return Index valuel as int
+ */
+ int asInt(void) const { return _index; }
+
+private:
+ int _index;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_OUTPUT_INDEX_H__
diff --git a/runtime/libs/tflite/include/tflite/Quantization.h b/runtime/libs/tflite/include/tflite/Quantization.h
new file mode 100644
index 000000000..8272bcdc0
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/Quantization.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Quantization.h
+ * @brief This file contains BitwiseIntToFloat union and quantization related
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_QUANTIZATION_H__
+#define __NNFW_TFLITE_QUANTIZATION_H__
+
+/**
+ * @brief Union to provide bitwise conversion of integer and float
+ */
+union BitwiseIntToFloat {
+ int i;
+ float f;
+};
+
+static const float FLOAT_NEAREST_TO_1 = BitwiseIntToFloat{0x3f7fffff}.f;
+
+#include "tensorflow/lite/context.h"
+
+/**
+ * @brief Get TfLiteQuantizationParams object with default values
+ * @return TfLiteQuantizationParams object
+ */
+TfLiteQuantizationParams make_default_quantization(void);
+
+#endif // __NNFW_TFLITE_QUANTIZATION_H__
diff --git a/runtime/libs/tflite/include/tflite/RandomTestRunner.h b/runtime/libs/tflite/include/tflite/RandomTestRunner.h
new file mode 100644
index 000000000..c0b304c74
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/RandomTestRunner.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file RandomTestRunner.h
+ * @brief This file contains class for random input testing
+ */
+
+#ifndef __NNFW_TFLITE_RANDOM_TEST_RUNNER_H__
+#define __NNFW_TFLITE_RANDOM_TEST_RUNNER_H__
+
+#include "tflite/interp/Builder.h"
+
+#include <misc/RandomGenerator.h>
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Structure for NNAPI correctness test
+ */
+struct RandomTestParam
+{
+ int verbose; //!< Verbosity of debug information
+ int tolerance; //!< Torlerance of value difference
+ int tensor_logging = 0; //!< Save logging to a file if not 0
+ std::string log_path = ""; //!< Path of log file, meaningful only when tensor_logging is 1
+};
+
+/**
+ * @brief Class to define Random test runner
+ */
+class RandomTestRunner
+{
+public:
+ /**
+ * @brief Construct a new RandomTestRunner object
+ * @param[in] seed Random seed value
+ * @param[in] param RandomTestParam object for test runner
+ * @param[in] quantization TfLiteQuantizationParams type to represent quantization value
+ */
+ RandomTestRunner(uint32_t seed, const RandomTestParam &param)
+ : _randgen{seed, 0.0f, 2.0f}, _param{param}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Run the random test runner
+ * @param[in] running_count Count to run tflite interpreter with NNAPI
+ * @return 0 if test succeeds, otherwise failure
+ */
+ int run(size_t running_count);
+
+public:
+ /**
+ * @brief Get RandomGenerator reference
+ * @return RandomGenerator reference
+ */
+ nnfw::misc::RandomGenerator &generator() { return _randgen; };
+
+public:
+ /**
+ * @brief Compile the random test runner
+ * @param[in] builder Interpreter Builder used to run
+ */
+ void compile(const nnfw::tflite::Builder &builder);
+
+private:
+ nnfw::misc::RandomGenerator _randgen;
+ const RandomTestParam _param;
+ std::unique_ptr<::tflite::Interpreter> _tfl_interp;
+ std::unique_ptr<::tflite::Interpreter> _nnapi;
+
+public:
+ /**
+ * @brief Create a RandomTestRunner object
+ * @param[in] seed Random seed value
+ * @return RandomGenerator object
+ */
+ static RandomTestRunner make(uint32_t seed);
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_RANDOM_TEST_RUNNER_H__
diff --git a/runtime/libs/tflite/include/tflite/Session.h b/runtime/libs/tflite/include/tflite/Session.h
new file mode 100644
index 000000000..b653acf61
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/Session.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Session.h
+ * @brief This file contains Session class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_SESSION_H__
+#define __NNFW_TFLITE_SESSION_H__
+
+#include <tensorflow/lite/interpreter.h>
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Structure to provide interface methods of interpreter session
+ */
+struct Session
+{
+ /**
+ * @brief Destruct Session object using default destructor
+ */
+ virtual ~Session() = default;
+
+ /**
+ * @brief Get the Interpreter object pointer
+ * @return The Interpreter object pointer
+ */
+ virtual ::tflite::Interpreter *interp(void) = 0;
+
+ /**
+ * @brief Prepare the session
+ * @return @c true if prepare method succeeded, otherwise @c false
+ */
+ virtual bool prepare(void) = 0;
+ /**
+ * @brief Run the session
+ * @return @c true if run method succeeded, otherwise @c false
+ */
+ virtual bool run(void) = 0;
+ /**
+ * @brief Teardown(release) the session
+ * @return @c true if teardown method succeeded, otherwise @c false
+ */
+ virtual bool teardown(void) = 0;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_INTERP_SESSION_H__
diff --git a/runtime/libs/tflite/include/tflite/TensorLogger.h b/runtime/libs/tflite/include/tflite/TensorLogger.h
new file mode 100644
index 000000000..a824c3411
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/TensorLogger.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file TensorLogger.h
+ * @brief This file contains TensorLogger class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_TENSOR_LOGGER_H__
+#define __NNFW_TFLITE_TENSOR_LOGGER_H__
+
+#include "misc/tensor/IndexIterator.h"
+#include "tflite/TensorView.h"
+
+#include <tensorflow/lite/interpreter.h>
+#include <tensorflow/lite/context.h>
+#include <fstream>
+#include <iomanip>
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to write input and output value / shape into a file in python form
+ * @note This is a utility to write input and output value / shape into a file in python form.\n
+ * any python app can load this value by running the python code below:\n
+ * exec(open(filename).read())\n
+ * generated python code looks like the following: \n
+ * tensor_shape_gen = []\n
+ * tensor_value_gen = []\n\n
+ * tensor_shape_gen.append("{2, 1, 2}")\n
+ * tensor_value_gen.append([1, 2, 3, 4])\n\n
+ * tensor_shape_gen.append("{2}")\n
+ * tensor_value_gen.append([1, 2])\n\n
+ * tensor_shape_gen.append("{2, 1, 2}")\n
+ * tensor_value_gen.append([1, 4, 3, 8])\n
+ */
+class TensorLogger
+{
+private:
+ std::ofstream _outfile;
+
+public:
+ /**
+ * @brief Get TensorLogger instance
+ * @return The TensorLogger instance
+ */
+ static TensorLogger &get()
+ {
+ static TensorLogger instance;
+ return instance;
+ }
+
+ /**
+ * @brief Save the tensor details to file from interpreter
+ * @param[in] path The file path to save
+ * @param[in] interp The TfLite interpreter
+ */
+ void save(const std::string &path, ::tflite::Interpreter &interp)
+ {
+ open(path);
+
+ int log_index = 0;
+ for (const auto id : interp.inputs())
+ {
+ _outfile << "# input tensors" << std::endl;
+ printTensor(interp, id, log_index++);
+ }
+ for (const auto id : interp.outputs())
+ {
+ _outfile << "# output tensors" << std::endl;
+ printTensor(interp, id, log_index++);
+ }
+ close();
+ }
+
+private:
+ void open(const std::string &path)
+ {
+ if (!_outfile.is_open())
+ _outfile.open(path, std::ios_base::out);
+
+ _outfile << "# ------ file: " << path << " ------" << std::endl
+ << "tensor_shape_gen = []" << std::endl
+ << "tensor_value_gen = []" << std::endl
+ << std::endl;
+ }
+
+ void printTensor(::tflite::Interpreter &interp, const int id, const int log_index)
+ {
+ const TfLiteTensor *tensor = interp.tensor(id);
+
+ _outfile << "# tensor name: " << tensor->name << std::endl;
+ _outfile << "# tflite::interpreter.tensor(" << id << ") -> "
+ "tensor_value_gen["
+ << log_index << "]" << std::endl;
+
+ if (tensor->type == kTfLiteInt32)
+ {
+ printTensorShape(tensor);
+ printTensorValue<int32_t>(tensor, tensor->data.i32);
+ }
+ else if (interp.tensor(id)->type == kTfLiteUInt8)
+ {
+ printTensorShape(tensor);
+ printTensorValue<uint8_t>(tensor, tensor->data.uint8);
+ }
+ else if (tensor->type == kTfLiteFloat32)
+ {
+ printTensorShape(tensor);
+ printTensorValue<float>(tensor, tensor->data.f);
+ }
+ }
+
+ void printTensorShape(const TfLiteTensor *tensor)
+ {
+ _outfile << "tensor_shape_gen.append('{";
+
+ int r = 0;
+ for (; r < tensor->dims->size - 1; r++)
+ {
+ _outfile << tensor->dims->data[r] << ", ";
+ }
+ _outfile << tensor->dims->data[r];
+
+ _outfile << "}')" << std::endl;
+ }
+
+ template <typename T> void printTensorValue(const TfLiteTensor *tensor, T *tensor_data_ptr)
+ {
+ _outfile << "tensor_value_gen.append([";
+
+ _outfile << std::fixed << std::setprecision(10);
+
+ const T *end = reinterpret_cast<const T *>(tensor->data.raw_const + tensor->bytes);
+ for (T *ptr = tensor_data_ptr; ptr < end; ptr++)
+ _outfile << *ptr << ", ";
+
+ _outfile << "])" << std::endl << std::endl;
+ }
+
+ void close()
+ {
+ _outfile << "# --------- tensor shape and value defined above ---------" << std::endl;
+ _outfile.close();
+ }
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_TENSOR_LOGGER_H__
diff --git a/runtime/libs/tflite/include/tflite/TensorShapeUtils.h b/runtime/libs/tflite/include/tflite/TensorShapeUtils.h
new file mode 100644
index 000000000..ba8687413
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/TensorShapeUtils.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file TensorShapeUtils.h
+ * @brief This file contains utilities function of tensor shape
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_TENSOR_SHAPE_UTILS_H__
+#define __NNFW_TFLITE_TENSOR_SHAPE_UTILS_H__
+
+#include "misc/tensor/Shape.h"
+
+#include <vector>
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Converts tensor::Shape into a vector
+ * @param[in] shape The tensor shape to be converted
+ * @return vector value of given shape object
+ */
+static inline std::vector<int32_t> as_dims(const nnfw::misc::tensor::Shape &shape)
+{
+ std::vector<int32_t> dims;
+
+ for (uint32_t axis = 0; axis < shape.rank(); ++axis)
+ {
+ dims.emplace_back(shape.dim(axis));
+ }
+
+ return dims;
+}
+
+/**
+ * @brief Broadcasts between two given shapes
+ * @param[in] lhs_shape The left hand side shape
+ * @param[in] rhs_shape The right hand side shape
+ * @return The broadcasted shape
+ */
+nnfw::misc::tensor::Shape broadcast(const nnfw::misc::tensor::Shape &lhs_shape,
+ const nnfw::misc::tensor::Shape &rhs_shape);
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_TENSOR_SHAPE_UTILS_H__
diff --git a/runtime/libs/tflite/include/tflite/TensorUtils.h b/runtime/libs/tflite/include/tflite/TensorUtils.h
new file mode 100644
index 000000000..08af1468b
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/TensorUtils.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file TensorUtils.h
+ * @brief This file contains utilities function
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_TENSOR_UTILS_H__
+#define __NNFW_TFLITE_TENSOR_UTILS_H__
+
+#include <tensorflow/lite/context.h>
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Get @c true if tensor type is kTfLiteFloat32, otherwise @c false
+ * @param[in] tensor The tensor object to be compared
+ * @return @c true if tensor type is kTfLiteFloat32, otherwise @c false
+ */
+inline bool isFloatTensor(const TfLiteTensor *tensor) { return tensor->type == kTfLiteFloat32; }
+
+/**
+ * @brief Get @c true if tensor is 4-D tensor and the first dimension length is 1,
+ * otherwise @c false
+ * @param[in] tensor The tensor object to be compared
+ * @return @c true if tensor is 4-D tensor and the first dimension length is 1, otherwise @c false
+ */
+inline bool isFeatureTensor(const TfLiteTensor *tensor)
+{
+ return (tensor->dims->size == 4) && (tensor->dims->data[0] == 1);
+}
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_TENSOR_UTILS_H__
diff --git a/runtime/libs/tflite/include/tflite/TensorView.h b/runtime/libs/tflite/include/tflite/TensorView.h
new file mode 100644
index 000000000..ce791a73f
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/TensorView.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file TensorView.h
+ * @brief This file contains TensorView class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_TENSOR_VIEW_H__
+#define __NNFW_TFLITE_TENSOR_VIEW_H__
+
+#include "tensorflow/lite/interpreter.h"
+
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Index.h"
+#include "misc/tensor/Reader.h"
+#include "misc/tensor/NonIncreasingStride.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to define TensorView which is inherited from nnfw::misc::tensor::Reader<T> class
+ */
+template <typename T> class TensorView final : public nnfw::misc::tensor::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a TensorView object with base and shape informations
+ * @param[in] shape The shape of a tensor
+ * @param[in] base The base address of a tensor
+ */
+ TensorView(const nnfw::misc::tensor::Shape &shape, T *base) : _shape{shape}, _base{base}
+ {
+ // Set 'stride'
+ _stride.init(_shape);
+ }
+
+public:
+ /**
+ * @brief Get shape of tensor
+ * @return Reference of shape
+ */
+ const nnfw::misc::tensor::Shape &shape(void) const { return _shape; }
+
+public:
+ /**
+ * @brief Get value of tensor index
+ * @param[in] index The tensor index
+ * @return The value at the index
+ */
+ T at(const nnfw::misc::tensor::Index &index) const override
+ {
+ const auto offset = _stride.offset(index);
+ return *(_base + offset);
+ }
+
+public:
+ /**
+ * @brief Get reference value of tensor index
+ * @param[in] index The tensor index
+ * @return The reference value at the index
+ */
+ T &at(const nnfw::misc::tensor::Index &index)
+ {
+ const auto offset = _stride.offset(index);
+ return *(_base + offset);
+ }
+
+private:
+ nnfw::misc::tensor::Shape _shape; /**< The tensor shape */
+
+public:
+ T *_base; /**< The base address of tensor */
+ nnfw::misc::tensor::NonIncreasingStride _stride; /**< The NonIncreasingStride object */
+
+public:
+ // TODO Introduce Operand ID class
+ /**
+ * @brief Create TensorView object using given parameters
+ * @param[in] interp The TfLite interpreter
+ * @param[in] tensor_index The tensor index
+ * @return The new TensorView<T> object
+ */
+ static TensorView<T> make(::tflite::Interpreter &interp, int tensor_index)
+ {
+ auto tensor_ptr = interp.tensor(tensor_index);
+
+ // Set 'shape'
+ nnfw::misc::tensor::Shape shape(tensor_ptr->dims->size);
+
+ for (uint32_t axis = 0; axis < shape.rank(); ++axis)
+ {
+ shape.dim(axis) = tensor_ptr->dims->data[axis];
+ }
+
+ return TensorView<T>(shape, interp.typed_tensor<T>(tensor_index));
+ }
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_TENSOR_VIEW_H__
diff --git a/runtime/libs/tflite/include/tflite/interp/Builder.h b/runtime/libs/tflite/include/tflite/interp/Builder.h
new file mode 100644
index 000000000..0f54e1779
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/interp/Builder.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Builder.h
+ * @brief This file contains Builder structure
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_INTERP_BUILDER_H__
+#define __NNFW_TFLITE_INTERP_BUILDER_H__
+
+#include <tensorflow/lite/interpreter.h>
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Structure to Builder
+ */
+struct Builder
+{
+ /**
+ * @brief Destroy the Builder object
+ */
+ virtual ~Builder() = default;
+
+ /**
+ * @brief Build a FlatBuffer model
+ * @return The TfLite interpreter object
+ */
+ virtual std::unique_ptr<::tflite::Interpreter> build(void) const = 0;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_INTERP_BUILDER_H__
diff --git a/runtime/libs/tflite/include/tflite/interp/FlatBufferBuilder.h b/runtime/libs/tflite/include/tflite/interp/FlatBufferBuilder.h
new file mode 100644
index 000000000..2d96af50b
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/interp/FlatBufferBuilder.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file FlatBufferBuilder.h
+ * @brief This file contains FlatBufferBuilder class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_INTERP_FLAT_BUFFER_BUILDER_H__
+#define __NNFW_TFLITE_INTERP_FLAT_BUFFER_BUILDER_H__
+
+#include <tensorflow/lite/model.h>
+
+#include "tflite/interp/Builder.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to define FlatBufferBuilder which is inherited from Builder
+ */
+class FlatBufferBuilder final : public Builder
+{
+public:
+ /**
+ * @brief Construct a FlatBufferBuilder object with FlatBufferModel of TfLite
+ * @param[in] model The TfLite Flatbuffer model
+ */
+ FlatBufferBuilder(const ::tflite::FlatBufferModel &model) : _model{model}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Build a FlatBuffer model
+ * @return The TfLite interpreter pointer address
+ */
+ std::unique_ptr<::tflite::Interpreter> build(void) const override;
+
+private:
+ const ::tflite::FlatBufferModel &_model;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_INTERP_FLAT_BUFFER_BUILDER_H__
diff --git a/runtime/libs/tflite/include/tflite/interp/FunctionBuilder.h b/runtime/libs/tflite/include/tflite/interp/FunctionBuilder.h
new file mode 100644
index 000000000..7bfb8db2d
--- /dev/null
+++ b/runtime/libs/tflite/include/tflite/interp/FunctionBuilder.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file FunctionBuilder.h
+ * @brief This file contains FunctionBuilder class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_INTERP_FUNCTION_BUILDER_H__
+#define __NNFW_TFLITE_INTERP_FUNCTION_BUILDER_H__
+
+#include <tensorflow/lite/model.h>
+
+#include "tflite/interp/Builder.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to define FunctionBuilder which is inherited from Builder
+ */
+class FunctionBuilder final : public Builder
+{
+public:
+ using SetupFunc = std::function<void(::tflite::Interpreter &)>;
+
+public:
+ /**
+ * @brief Construct a FunctionBuilder object with SetupFunction
+ * @param[in] fn The SetupFunc object
+ */
+ FunctionBuilder(const SetupFunc &fn) : _fn{fn}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Build a SetupFunc
+ * @return The TfLite interpreter pointer address
+ */
+ std::unique_ptr<::tflite::Interpreter> build(void) const override;
+
+private:
+ SetupFunc _fn;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_INTERP_FUNCTION_BUILDER_H__
diff --git a/runtime/libs/tflite/port/1.13.1/CMakeLists.txt b/runtime/libs/tflite/port/1.13.1/CMakeLists.txt
new file mode 100644
index 000000000..e3cf97569
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/CMakeLists.txt
@@ -0,0 +1,14 @@
+if(NOT SUPPORT_TFLITE_VERSION VERSION_EQUAL 1.13.1)
+ return()
+endif(NOT SUPPORT_TFLITE_VERSION VERSION_EQUAL 1.13.1)
+
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(tensorflow-lite-ex STATIC ${SOURCES})
+set_target_properties(tensorflow-lite-ex PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(tensorflow-lite-ex PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(tensorflow-lite-ex PUBLIC tensorflow-lite)
+target_link_libraries(tensorflow-lite-ex PUBLIC nnfw_lib_misc nnfw_lib_rua_shim)
+target_link_libraries(tensorflow-lite-ex PRIVATE ${LIB_PTHREAD} dl)
+target_link_libraries(tensorflow-lite-ex PRIVATE nnfw_common)
+target_link_libraries(tensorflow-lite-ex PRIVATE nnfw_coverage)
diff --git a/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/CustomOps.h b/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/CustomOps.h
new file mode 100644
index 000000000..c073ad58e
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/CustomOps.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file CustomOps.h
+ * @brief This file contains registration of custom operands
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_EXT_KERNELS_CUSTOM_OP_H__
+#define __NNFW_TFLITE_EXT_KERNELS_CUSTOM_OP_H__
+
+#include "tensorflow/lite/context.h"
+#include "tflite/ext/kernels/SquaredDifference.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+namespace custom
+{
+
+#define REGISTER_FUNCTION(Name) \
+ TfLiteRegistration *Register_##Name(void) \
+ { \
+ static TfLiteRegistration r = {}; \
+ r.init = Name::Init##Name; \
+ r.free = Name::Free##Name; \
+ r.prepare = Name::Prepare##Name; \
+ r.invoke = Name::Eval##Name; \
+ r.custom_name = #Name; \
+ return &r; \
+ }
+
+REGISTER_FUNCTION(SquaredDifference)
+
+#undef REGISTER_FUNCTION
+
+} // namespace custom
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_EXT_KERNELS_CUSTOM_OP_H__
diff --git a/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/SquaredDifference.h b/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/SquaredDifference.h
new file mode 100644
index 000000000..5512ead78
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/SquaredDifference.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file SquaredDifference.h
+ * @brief This file contains SquaredDifference namespace and SquaredDifference function
+ * definitions
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NNFW_TFLITE_EXT_KERNELS_SQUARED_DIFFERENCE_H__
+#define __NNFW_TFLITE_EXT_KERNELS_SQUARED_DIFFERENCE_H__
+
+#include "tensorflow/lite/context.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+namespace custom
+{
+namespace SquaredDifference
+{
+
+/**
+ * @brief Initialize SquaredDifference operand using the contents of buffer
+ * @param[in] context The TfLite context
+ * @param[in] buffer The buffer with contents
+ * @param[in] length The buffer length
+ * @return The void pointer for user data
+ */
+void *InitSquaredDifference(TfLiteContext *context, const char *buffer, size_t length);
+
+/**
+ * @brief Release any memory it might have allocated via 'InitSquaredDifference'
+ * @param[in] context The TfLite context
+ * @param[in] buffer The buffer with contents
+ * @return N/A
+ */
+void FreeSquaredDifference(TfLiteContext *context, void *buffer);
+
+/**
+ * @brief Prepare the SquaredDifference operand for execution
+ * @param[in] context The TfLite context
+ * @param[in] node The operand node
+ * @return The TfLite status
+ */
+TfLiteStatus PrepareSquaredDifference(TfLiteContext *context, TfLiteNode *node);
+
+/**
+ * @brief Evaluation the SquaredDifference operand for execution
+ * @param[in] context The TfLite context
+ * @param[in] node The operand node
+ * @return The TfLite status
+ */
+TfLiteStatus EvalSquaredDifference(TfLiteContext *context, TfLiteNode *node);
+
+} // namespace SquaredDifference
+} // namespace custom
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_EXT_KERNELS_SQUARED_DIFFERENCE_H__
diff --git a/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/register.h b/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/register.h
new file mode 100644
index 000000000..6e32b35fb
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/include/tflite/ext/kernels/register.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This header is derived from the following file (in TensorFlow v1.13.1)
+// 'externals/tensorflow/tensorflow/lite/kernels/register.h'
+#ifndef __NNFW_TFLITE_EXT_KERNELS_REGISTER_H__
+#define __NNFW_TFLITE_EXT_KERNELS_REGISTER_H__
+
+#include <unordered_map>
+#include "tensorflow/lite/context.h"
+#include "tensorflow/lite/model.h"
+
+namespace nnfw {
+namespace tflite {
+
+class BuiltinOpResolver : public ::tflite::MutableOpResolver {
+ public:
+ BuiltinOpResolver();
+
+ const TfLiteRegistration* FindOp(::tflite::BuiltinOperator op,
+ int version) const override;
+ const TfLiteRegistration* FindOp(const char* op, int version) const override;
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_EXT_KERNELS_REGISTER_H__
+
+// clang-format on
diff --git a/runtime/libs/tflite/port/1.13.1/include/tflite/ext/nnapi_delegate.h b/runtime/libs/tflite/port/1.13.1/include/tflite/ext/nnapi_delegate.h
new file mode 100644
index 000000000..231baa25c
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/include/tflite/ext/nnapi_delegate.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This header is derived from the following file (in TensorFlow v1.13.1)
+// 'externals/tensorflow/tensorflow/lite/nnapi_delegate.h'
+#ifndef __NNFW_TFLITE_EXT_NNAPI_DELEGATE_H__
+#define __NNFW_TFLITE_EXT_NNAPI_DELEGATE_H__
+
+#include "tensorflow/lite/allocation.h"
+#include "tensorflow/lite/c/c_api_internal.h"
+#include "tensorflow/lite/core/api/error_reporter.h"
+#include "tensorflow/lite/core/subgraph.h"
+#include "tensorflow/lite/interpreter.h"
+
+struct ANeuralNetworksModel;
+struct ANeuralNetworksMemory;
+struct ANeuralNetworksCompilation;
+
+namespace nnfw {
+namespace tflite {
+
+class NNAPIAllocation : public ::tflite::MMAPAllocation {
+ public:
+ NNAPIAllocation(const char* filename, ::tflite::ErrorReporter* error_reporter);
+ ~NNAPIAllocation();
+
+ size_t offset(const void* ptr) const {
+ auto signed_offset = reinterpret_cast<const uint8_t*>(ptr) -
+ reinterpret_cast<const uint8_t*>(mmapped_buffer_);
+
+ return static_cast<size_t>(signed_offset);
+ }
+
+ ANeuralNetworksMemory* memory() const { return handle_; }
+ bool valid() const override { return handle_ != nullptr; }
+
+ private:
+ mutable ANeuralNetworksMemory* handle_ = nullptr;
+};
+
+class NNAPIDelegate {
+ public:
+ ~NNAPIDelegate();
+
+ // Convert a tflite graph to NNAPI
+ TfLiteStatus BuildGraph(::tflite::Subgraph* subgraph);
+
+ // Run
+ TfLiteStatus Invoke(::tflite::Subgraph* subgraph);
+
+ // Whether the current platform supports NNAPI delegation.
+ static bool IsSupported();
+
+ private:
+ // The NN API model handle
+ ANeuralNetworksModel* nn_model_ = nullptr;
+ // The NN API compilation handle
+ ANeuralNetworksCompilation* nn_compiled_model_ = nullptr;
+ // Model status
+ TfLiteStatus model_status_ = kTfLiteOk;
+
+ // List of state tensors for LSTM, RNN, SVDF.
+ // NN API does not allow ops to maintain states across multiple
+ // invocations. We need to manually create state input tensors from
+ // corresponding state output tensors of TFLite operations, and map them
+ // correctly.
+ std::vector<int> model_states_inputs_; // holds NNAPI operand ids
+ std::vector<int> model_states_outputs_; // holds TFLite tensor ids
+};
+
+} // namespace tflite
+} // namespace nnfw
+
+#endif // __NNFW_TFLITE_EXT_NNAPI_DELEGATE_H__
+
+// clang-format on
diff --git a/runtime/libs/tflite/port/1.13.1/src/kernels/SquaredDifference.cpp b/runtime/libs/tflite/port/1.13.1/src/kernels/SquaredDifference.cpp
new file mode 100644
index 000000000..615878513
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/src/kernels/SquaredDifference.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/ext/kernels/SquaredDifference.h"
+#include "tensorflow/lite/kernels/kernel_util.h"
+
+#include <iostream>
+
+namespace nnfw
+{
+namespace tflite
+{
+namespace custom
+{
+namespace SquaredDifference
+{
+
+void *InitSquaredDifference(TfLiteContext *, const char *, size_t) { return nullptr; }
+
+void FreeSquaredDifference(TfLiteContext *, void *) {}
+
+TfLiteStatus PrepareSquaredDifference(TfLiteContext *context, TfLiteNode *node)
+{
+ TF_LITE_ENSURE_EQ(context, ::tflite::NumInputs(node), 2);
+ TF_LITE_ENSURE_EQ(context, ::tflite::NumOutputs(node), 1);
+
+ const TfLiteTensor *input1 = ::tflite::GetInput(context, node, 0);
+ const TfLiteTensor *input2 = ::tflite::GetInput(context, node, 1);
+ TfLiteTensor *output = ::tflite::GetOutput(context, node, 0);
+
+ TF_LITE_ENSURE_EQ(context, input1->type, input2->type);
+ TF_LITE_ENSURE_EQ(context, input1->type, output->type);
+
+ return context->ResizeTensor(context, output, TfLiteIntArrayCopy(input1->dims));
+}
+
+TfLiteStatus EvalSquaredDifference(TfLiteContext *context, TfLiteNode *node)
+{
+
+ const TfLiteTensor *input1 = ::tflite::GetInput(context, node, 0);
+ const TfLiteTensor *input2 = ::tflite::GetInput(context, node, 1);
+
+ TfLiteTensor *output = ::tflite::GetOutput(context, node, 0);
+
+ size_t elements = ::tflite::NumElements(input1);
+
+ switch (input1->type)
+ {
+ case kTfLiteFloat32:
+ {
+ const float *in1 = input1->data.f;
+ const float *in2 = input2->data.f;
+ const float *in_end1 = in1 + elements;
+ float *out = output->data.f;
+
+ for (; in1 < in_end1; in1++, in2++, out++)
+ *out = ((*in1 - *in2) * (*in1 - *in2));
+
+ return kTfLiteOk;
+ }
+ case kTfLiteInt32:
+ {
+ const int *in1 = input1->data.i32;
+ const int *in2 = input2->data.i32;
+ const int *in_end1 = in1 + elements;
+ int *out = output->data.i32;
+
+ for (; in1 < in_end1; in1++, in2++, out++)
+ *out = ((*in1 - *in2) * (*in1 - *in2));
+
+ return kTfLiteOk;
+ }
+ case kTfLiteInt64:
+ {
+ const int64_t *in1 = input1->data.i64;
+ const int64_t *in2 = input1->data.i64;
+ const int64_t *in_end1 = in1 + elements;
+ int64_t *out = output->data.i64;
+
+ for (; in1 < in_end1; in1++, in2++, out++)
+ *out = ((*in1 - *in2) * (*in1 - *in2));
+
+ return kTfLiteOk;
+ }
+ default:
+ {
+ context->ReportError(context, "InputType is %d Unsupported", input1->type);
+ return kTfLiteError;
+ }
+ }
+}
+
+} // namespace SquaredDifference
+} // namespace custom
+} // namespace tflite
+} // namespace nnfw
diff --git a/runtime/libs/tflite/port/1.13.1/src/kernels/register.cpp b/runtime/libs/tflite/port/1.13.1/src/kernels/register.cpp
new file mode 100644
index 000000000..89f81b612
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/src/kernels/register.cpp
@@ -0,0 +1,314 @@
+/* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This code is derived from the following file (in TensorFlow v1.13.1)
+// 'externals/tensorflow/tensorflow/lite/kernels/register.cc'
+#include "tflite/ext/kernels/register.h"
+#include "tensorflow/lite/util.h"
+#include "tflite/ext/kernels/CustomOps.h"
+
+namespace tflite {
+namespace ops {
+
+namespace custom {
+
+// Need additional external library for AUDIO_SPECTROGRAM
+//TfLiteRegistration* Register_AUDIO_SPECTROGRAM();
+TfLiteRegistration* Register_LAYER_NORM_LSTM();
+TfLiteRegistration* Register_MFCC();
+TfLiteRegistration* Register_DETECTION_POSTPROCESS();
+TfLiteRegistration* Register_RELU_1();
+
+} // namespace custom
+}
+}
+
+namespace tflite {
+namespace ops {
+namespace builtin {
+
+TfLiteRegistration* Register_ABS();
+TfLiteRegistration* Register_RELU();
+TfLiteRegistration* Register_RELU_N1_TO_1();
+TfLiteRegistration* Register_RELU6();
+TfLiteRegistration* Register_TANH();
+TfLiteRegistration* Register_LOGISTIC();
+TfLiteRegistration* Register_AVERAGE_POOL_2D();
+TfLiteRegistration* Register_MAX_POOL_2D();
+TfLiteRegistration* Register_L2_POOL_2D();
+TfLiteRegistration* Register_CONV_2D();
+TfLiteRegistration* Register_DEPTHWISE_CONV_2D();
+TfLiteRegistration* Register_SVDF();
+TfLiteRegistration* Register_RNN();
+TfLiteRegistration* Register_BIDIRECTIONAL_SEQUENCE_RNN();
+TfLiteRegistration* Register_UNIDIRECTIONAL_SEQUENCE_RNN();
+TfLiteRegistration* Register_EMBEDDING_LOOKUP();
+TfLiteRegistration* Register_EMBEDDING_LOOKUP_SPARSE();
+TfLiteRegistration* Register_FULLY_CONNECTED();
+TfLiteRegistration* Register_LSH_PROJECTION();
+TfLiteRegistration* Register_HASHTABLE_LOOKUP();
+TfLiteRegistration* Register_SOFTMAX();
+TfLiteRegistration* Register_CONCATENATION();
+TfLiteRegistration* Register_ADD();
+TfLiteRegistration* Register_SPACE_TO_BATCH_ND();
+TfLiteRegistration* Register_DIV();
+TfLiteRegistration* Register_SUB();
+TfLiteRegistration* Register_BATCH_TO_SPACE_ND();
+TfLiteRegistration* Register_MUL();
+TfLiteRegistration* Register_L2_NORMALIZATION();
+TfLiteRegistration* Register_LOCAL_RESPONSE_NORMALIZATION();
+TfLiteRegistration* Register_LSTM();
+TfLiteRegistration* Register_BIDIRECTIONAL_SEQUENCE_LSTM();
+TfLiteRegistration* Register_UNIDIRECTIONAL_SEQUENCE_LSTM();
+TfLiteRegistration* Register_PAD();
+TfLiteRegistration* Register_PADV2();
+TfLiteRegistration* Register_RESHAPE();
+TfLiteRegistration* Register_RESIZE_BILINEAR();
+TfLiteRegistration* Register_RESIZE_NEAREST_NEIGHBOR();
+TfLiteRegistration* Register_SKIP_GRAM();
+TfLiteRegistration* Register_SPACE_TO_DEPTH();
+TfLiteRegistration* Register_GATHER();
+TfLiteRegistration* Register_TRANSPOSE();
+TfLiteRegistration* Register_MEAN();
+TfLiteRegistration* Register_SPLIT();
+TfLiteRegistration* Register_SPLIT_V();
+TfLiteRegistration* Register_SQUEEZE();
+TfLiteRegistration* Register_STRIDED_SLICE();
+TfLiteRegistration* Register_EXP();
+TfLiteRegistration* Register_TOPK_V2();
+TfLiteRegistration* Register_LOG();
+TfLiteRegistration* Register_LOG_SOFTMAX();
+TfLiteRegistration* Register_CAST();
+TfLiteRegistration* Register_DEQUANTIZE();
+TfLiteRegistration* Register_PRELU();
+TfLiteRegistration* Register_MAXIMUM();
+TfLiteRegistration* Register_MINIMUM();
+TfLiteRegistration* Register_ARG_MAX();
+TfLiteRegistration* Register_ARG_MIN();
+TfLiteRegistration* Register_GREATER();
+TfLiteRegistration* Register_GREATER_EQUAL();
+TfLiteRegistration* Register_LESS();
+TfLiteRegistration* Register_LESS_EQUAL();
+TfLiteRegistration* Register_FLOOR();
+TfLiteRegistration* Register_TILE();
+TfLiteRegistration* Register_NEG();
+TfLiteRegistration* Register_SUM();
+TfLiteRegistration* Register_REDUCE_PROD();
+TfLiteRegistration* Register_REDUCE_MAX();
+TfLiteRegistration* Register_REDUCE_MIN();
+TfLiteRegistration* Register_REDUCE_ANY();
+TfLiteRegistration* Register_SELECT();
+TfLiteRegistration* Register_SLICE();
+TfLiteRegistration* Register_SIN();
+TfLiteRegistration* Register_TRANSPOSE_CONV();
+TfLiteRegistration* Register_EXPAND_DIMS();
+TfLiteRegistration* Register_SPARSE_TO_DENSE();
+TfLiteRegistration* Register_EQUAL();
+TfLiteRegistration* Register_NOT_EQUAL();
+TfLiteRegistration* Register_SQRT();
+TfLiteRegistration* Register_RSQRT();
+TfLiteRegistration* Register_SHAPE();
+TfLiteRegistration* Register_POW();
+TfLiteRegistration* Register_FAKE_QUANT();
+TfLiteRegistration* Register_PACK();
+TfLiteRegistration* Register_ONE_HOT();
+TfLiteRegistration* Register_LOGICAL_OR();
+TfLiteRegistration* Register_LOGICAL_AND();
+TfLiteRegistration* Register_LOGICAL_NOT();
+TfLiteRegistration* Register_UNPACK();
+TfLiteRegistration* Register_FLOOR_DIV();
+TfLiteRegistration* Register_SQUARE();
+TfLiteRegistration* Register_ZEROS_LIKE();
+TfLiteRegistration* Register_FLOOR_MOD();
+TfLiteRegistration* Register_RANGE();
+TfLiteRegistration* Register_LEAKY_RELU();
+TfLiteRegistration* Register_SQUARED_DIFFERENCE();
+TfLiteRegistration* Register_FILL();
+TfLiteRegistration* Register_MIRROR_PAD();
+
+} // namespace builtin
+} // namespace ops
+} // namespace tflite
+
+namespace nnfw {
+namespace tflite {
+
+// Using namespace directive to minimize diff with upstream tensorflow
+using namespace ::tflite::ops::custom;
+using namespace ::tflite::ops::builtin;
+using namespace ::tflite;
+
+// Fix to use strict build option
+TfLiteStatus UnsupportedTensorFlowOp(TfLiteContext* context, TfLiteNode* /*node*/) {
+ context->ReportError(
+ context,
+ "Regular TensorFlow ops are not supported by this interpreter. Make sure "
+ "you invoke the Flex delegate before inference.");
+ return kTfLiteError;
+}
+
+const TfLiteRegistration* BuiltinOpResolver::FindOp(tflite::BuiltinOperator op,
+ int version) const {
+ return MutableOpResolver::FindOp(op, version);
+}
+
+const TfLiteRegistration* BuiltinOpResolver::FindOp(const char* op,
+ int version) const {
+ // Return the NULL Op for all ops whose name start with "Flex", allowing
+ // the interpreter to delegate their execution.
+ if (IsFlexOp(op)) {
+ static TfLiteRegistration null_op{
+ nullptr, nullptr, &UnsupportedTensorFlowOp,
+ nullptr, nullptr, BuiltinOperator_CUSTOM,
+ "Flex", 1};
+ return &null_op;
+ }
+ return MutableOpResolver::FindOp(op, version);
+}
+
+BuiltinOpResolver::BuiltinOpResolver() {
+ AddBuiltin(BuiltinOperator_ABS, Register_ABS());
+ AddBuiltin(BuiltinOperator_RELU, Register_RELU());
+ AddBuiltin(BuiltinOperator_RELU_N1_TO_1, Register_RELU_N1_TO_1());
+ AddBuiltin(BuiltinOperator_RELU6, Register_RELU6());
+ AddBuiltin(BuiltinOperator_TANH, Register_TANH());
+ AddBuiltin(BuiltinOperator_LOGISTIC, Register_LOGISTIC());
+ AddBuiltin(BuiltinOperator_AVERAGE_POOL_2D, Register_AVERAGE_POOL_2D());
+ AddBuiltin(BuiltinOperator_MAX_POOL_2D, Register_MAX_POOL_2D());
+ AddBuiltin(BuiltinOperator_L2_POOL_2D, Register_L2_POOL_2D());
+ AddBuiltin(BuiltinOperator_CONV_2D, Register_CONV_2D());
+ AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(),
+ /* min_version */ 1,
+ /* max_version */ 2);
+ AddBuiltin(BuiltinOperator_SVDF, Register_SVDF());
+ AddBuiltin(BuiltinOperator_RNN, Register_RNN());
+ AddBuiltin(BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN,
+ Register_BIDIRECTIONAL_SEQUENCE_RNN());
+ AddBuiltin(BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN,
+ Register_UNIDIRECTIONAL_SEQUENCE_RNN());
+ AddBuiltin(BuiltinOperator_EMBEDDING_LOOKUP, Register_EMBEDDING_LOOKUP());
+ AddBuiltin(BuiltinOperator_EMBEDDING_LOOKUP_SPARSE,
+ Register_EMBEDDING_LOOKUP_SPARSE());
+ AddBuiltin(BuiltinOperator_FULLY_CONNECTED, Register_FULLY_CONNECTED(),
+ /* min_version */ 1,
+ /* max_version */ 2);
+ AddBuiltin(BuiltinOperator_LSH_PROJECTION, Register_LSH_PROJECTION());
+ AddBuiltin(BuiltinOperator_HASHTABLE_LOOKUP, Register_HASHTABLE_LOOKUP());
+ AddBuiltin(BuiltinOperator_SOFTMAX, Register_SOFTMAX());
+ AddBuiltin(BuiltinOperator_CONCATENATION, Register_CONCATENATION());
+ AddBuiltin(BuiltinOperator_ADD, Register_ADD());
+ AddBuiltin(BuiltinOperator_SPACE_TO_BATCH_ND, Register_SPACE_TO_BATCH_ND());
+ AddBuiltin(BuiltinOperator_BATCH_TO_SPACE_ND, Register_BATCH_TO_SPACE_ND());
+ AddBuiltin(BuiltinOperator_MUL, Register_MUL());
+ AddBuiltin(BuiltinOperator_L2_NORMALIZATION, Register_L2_NORMALIZATION());
+ AddBuiltin(BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION,
+ Register_LOCAL_RESPONSE_NORMALIZATION());
+ AddBuiltin(BuiltinOperator_LSTM, Register_LSTM(), /* min_version */ 1,
+ /* max_version */ 2);
+ AddBuiltin(BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM,
+ Register_BIDIRECTIONAL_SEQUENCE_LSTM());
+ AddBuiltin(BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM,
+ Register_UNIDIRECTIONAL_SEQUENCE_LSTM());
+ AddBuiltin(BuiltinOperator_PAD, Register_PAD());
+ AddBuiltin(BuiltinOperator_PADV2, Register_PADV2());
+ AddBuiltin(BuiltinOperator_RESHAPE, Register_RESHAPE());
+ AddBuiltin(BuiltinOperator_RESIZE_BILINEAR, Register_RESIZE_BILINEAR());
+ AddBuiltin(BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
+ Register_RESIZE_NEAREST_NEIGHBOR());
+ AddBuiltin(BuiltinOperator_SKIP_GRAM, Register_SKIP_GRAM());
+ AddBuiltin(BuiltinOperator_SPACE_TO_DEPTH, Register_SPACE_TO_DEPTH());
+ AddBuiltin(BuiltinOperator_GATHER, Register_GATHER());
+ AddBuiltin(BuiltinOperator_TRANSPOSE, Register_TRANSPOSE());
+ AddBuiltin(BuiltinOperator_MEAN, Register_MEAN());
+ AddBuiltin(BuiltinOperator_DIV, Register_DIV());
+ AddBuiltin(BuiltinOperator_SUB, Register_SUB());
+ AddBuiltin(BuiltinOperator_SPLIT, Register_SPLIT());
+ AddBuiltin(BuiltinOperator_SPLIT_V, Register_SPLIT_V());
+ AddBuiltin(BuiltinOperator_SQUEEZE, Register_SQUEEZE());
+ AddBuiltin(BuiltinOperator_STRIDED_SLICE, Register_STRIDED_SLICE());
+ AddBuiltin(BuiltinOperator_EXP, Register_EXP());
+ AddBuiltin(BuiltinOperator_TOPK_V2, Register_TOPK_V2());
+ AddBuiltin(BuiltinOperator_LOG, Register_LOG());
+ AddBuiltin(BuiltinOperator_LOG_SOFTMAX, Register_LOG_SOFTMAX());
+ AddBuiltin(BuiltinOperator_CAST, Register_CAST());
+ AddBuiltin(BuiltinOperator_DEQUANTIZE, Register_DEQUANTIZE(),
+ /* min_version */ 1,
+ /* max_version */ 2);
+ AddBuiltin(BuiltinOperator_PRELU, Register_PRELU());
+ AddBuiltin(BuiltinOperator_MAXIMUM, Register_MAXIMUM());
+ AddBuiltin(BuiltinOperator_MINIMUM, Register_MINIMUM());
+ AddBuiltin(BuiltinOperator_ARG_MAX, Register_ARG_MAX());
+ AddBuiltin(BuiltinOperator_ARG_MIN, Register_ARG_MIN());
+ AddBuiltin(BuiltinOperator_GREATER, Register_GREATER());
+ AddBuiltin(BuiltinOperator_GREATER_EQUAL, Register_GREATER_EQUAL());
+ AddBuiltin(BuiltinOperator_LESS, Register_LESS());
+ AddBuiltin(BuiltinOperator_LESS_EQUAL, Register_LESS_EQUAL());
+ AddBuiltin(BuiltinOperator_FLOOR, Register_FLOOR());
+ AddBuiltin(BuiltinOperator_NEG, Register_NEG());
+ AddBuiltin(BuiltinOperator_SELECT, Register_SELECT());
+ AddBuiltin(BuiltinOperator_SLICE, Register_SLICE());
+ AddBuiltin(BuiltinOperator_SIN, Register_SIN());
+ AddBuiltin(BuiltinOperator_TRANSPOSE_CONV, Register_TRANSPOSE_CONV());
+ AddBuiltin(BuiltinOperator_TILE, Register_TILE());
+ AddBuiltin(BuiltinOperator_SUM, Register_SUM());
+ AddBuiltin(BuiltinOperator_REDUCE_PROD, Register_REDUCE_PROD());
+ AddBuiltin(BuiltinOperator_REDUCE_MAX, Register_REDUCE_MAX());
+ AddBuiltin(BuiltinOperator_REDUCE_MIN, Register_REDUCE_MIN());
+ AddBuiltin(BuiltinOperator_REDUCE_ANY, Register_REDUCE_ANY());
+ AddBuiltin(BuiltinOperator_EXPAND_DIMS, Register_EXPAND_DIMS());
+ AddBuiltin(BuiltinOperator_SPARSE_TO_DENSE, Register_SPARSE_TO_DENSE());
+ AddBuiltin(BuiltinOperator_EQUAL, Register_EQUAL());
+ AddBuiltin(BuiltinOperator_NOT_EQUAL, Register_NOT_EQUAL());
+ AddBuiltin(BuiltinOperator_SQRT, Register_SQRT());
+ AddBuiltin(BuiltinOperator_RSQRT, Register_RSQRT());
+ AddBuiltin(BuiltinOperator_SHAPE, Register_SHAPE());
+ AddBuiltin(BuiltinOperator_POW, Register_POW());
+ AddBuiltin(BuiltinOperator_FAKE_QUANT, Register_FAKE_QUANT(), 1, 2);
+ AddBuiltin(BuiltinOperator_PACK, Register_PACK());
+ AddBuiltin(BuiltinOperator_ONE_HOT, Register_ONE_HOT());
+ AddBuiltin(BuiltinOperator_LOGICAL_OR, Register_LOGICAL_OR());
+ AddBuiltin(BuiltinOperator_LOGICAL_AND, Register_LOGICAL_AND());
+ AddBuiltin(BuiltinOperator_LOGICAL_NOT, Register_LOGICAL_NOT());
+ AddBuiltin(BuiltinOperator_UNPACK, Register_UNPACK());
+ AddBuiltin(BuiltinOperator_FLOOR_DIV, Register_FLOOR_DIV());
+ AddBuiltin(BuiltinOperator_SQUARE, Register_SQUARE());
+ AddBuiltin(BuiltinOperator_ZEROS_LIKE, Register_ZEROS_LIKE());
+ AddBuiltin(BuiltinOperator_FLOOR_MOD, Register_FLOOR_MOD());
+ AddBuiltin(BuiltinOperator_RANGE, Register_RANGE());
+ AddBuiltin(BuiltinOperator_LEAKY_RELU, Register_LEAKY_RELU());
+ AddBuiltin(BuiltinOperator_SQUARED_DIFFERENCE, Register_SQUARED_DIFFERENCE());
+ AddBuiltin(BuiltinOperator_FILL, Register_FILL());
+ AddBuiltin(BuiltinOperator_MIRROR_PAD, Register_MIRROR_PAD());
+
+ AddCustom("SquaredDifference", nnfw::tflite::custom::Register_SquaredDifference());
+
+ // TODO(andrewharp, ahentz): Move these somewhere more appropriate so that
+ // custom ops aren't always included by default.
+ AddCustom("Mfcc", tflite::ops::custom::Register_MFCC());
+ // Need additional external library for audio spectrogram
+ //AddCustom("AudioSpectrogram",
+ // tflite::ops::custom::Register_AUDIO_SPECTROGRAM());
+ AddCustom("LayerNormLstm", tflite::ops::custom::Register_LAYER_NORM_LSTM());
+ AddCustom("Relu1", tflite::ops::custom::Register_RELU_1());
+ AddCustom("TFLite_Detection_PostProcess",
+ tflite::ops::custom::Register_DETECTION_POSTPROCESS());
+}
+
+} // namespace tflite
+} // namespace nnfw
diff --git a/runtime/libs/tflite/port/1.13.1/src/nnapi_delegate.cpp b/runtime/libs/tflite/port/1.13.1/src/nnapi_delegate.cpp
new file mode 100644
index 000000000..9675570ad
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/src/nnapi_delegate.cpp
@@ -0,0 +1,1262 @@
+/* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+// NOTE To minimize diff with upstream tensorflow, disable clang-format
+// clang-format off
+
+// NOTE This code is derived from the following file (in TensorFlow v1.13.1)
+// 'externals/tensorflow/tensorflow/lite/nnapi_delegate.cc'
+#include "tflite/ext/nnapi_delegate.h"
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "tensorflow/lite/c/builtin_op_data.h"
+#include "tensorflow/lite/core/api/error_reporter.h"
+#include "tensorflow/lite/model.h"
+#include <rua/Shim.h>
+#include "NeuralNetworksExShim.h"
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#include <sys/system_properties.h>
+#endif
+
+#include <memory>
+
+namespace nnfw {
+namespace tflite {
+
+void logError(const char* format, ...) {
+ // stderr is convenient for native tests, but is not captured for apps
+ va_list args_for_stderr;
+ va_start(args_for_stderr, format);
+ vfprintf(stderr, format, args_for_stderr);
+ va_end(args_for_stderr);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+#ifdef __ANDROID__
+ // produce logcat output for general consumption
+ va_list args_for_log;
+ va_start(args_for_log, format);
+ __android_log_vprint(ANDROID_LOG_ERROR, "tflite", format, args_for_log);
+ va_end(args_for_log);
+#endif
+}
+
+#define FATAL(...) \
+ logError(__VA_ARGS__); \
+ exit(1);
+
+// TODO(aselle): Change the error model to use status codes.
+#define CHECK_TFLITE_SUCCESS(x) \
+ if (x != kTfLiteOk) { \
+ FATAL("Aborting since tflite returned failure nnapi_delegate.cc:%d.", \
+ __LINE__); \
+ }
+
+#define CHECK_NN(x) \
+ if (x != ANEURALNETWORKS_NO_ERROR) { \
+ FATAL("Aborting since NNAPI returned failure nnapi_delegate.cc:%d", \
+ __LINE__); \
+ }
+
+#define RETURN_ERROR_IF_TFLITE_FAILED(x) \
+ if (x != kTfLiteOk) { \
+ logError( \
+ "Returning error since TFLite returned failure nnapi_delegate.cc:%d.", \
+ __LINE__); \
+ return kTfLiteError; \
+ }
+
+#define RETURN_ERROR_IF_NN_FAILED(x) \
+ if (x != ANEURALNETWORKS_NO_ERROR) { \
+ logError( \
+ "Returning error since NNAPI returned failure nnapi_delegate.cc:%d.", \
+ __LINE__); \
+ return kTfLiteError; \
+ }
+
+// Tracking of NNAPI operand ids
+static const int64_t kOperandIdNotSet = -1;
+static const int64_t kOperandNotNeeded = -2;
+
+namespace {
+
+int32_t GetAndroidSdkVersion() {
+#ifdef __ANDROID__
+ const char* sdkProp = "ro.build.version.sdk";
+ char sdkVersion[PROP_VALUE_MAX];
+ int length = __system_property_get(sdkProp, sdkVersion);
+ if (length != 0) {
+ for (int i = 0; i < length; ++i) {
+ int digit = sdkVersion[i] - '0';
+ if (digit < 0 || digit > 9) {
+ // Non-numeric SDK version, assume it's higher then expected;
+ return 0xFFFF;
+ }
+ }
+ // NOTE use std::strtol instead of atoi: security issue
+ return std::strtol(sdkVersion, NULL, 0);
+ }
+ FATAL("No %s prop", sdkProp);
+#endif // __ANDROID__
+ return 0;
+}
+
+int32_t GetAndroidSdkVersionCached() {
+ static int32_t androidSdkVersion = GetAndroidSdkVersion();
+ return androidSdkVersion;
+}
+
+// WORKAROUND Some model have dimension zero
+// Consider scalar as vector size 1
+static const uint32_t dimension_for_scalar[1] = {1};
+
+} // namespace
+
+NNAPIAllocation::NNAPIAllocation(const char* filename,
+ ::tflite::ErrorReporter* error_reporter)
+ : MMAPAllocation(filename, error_reporter) {
+ if (mmapped_buffer_ != MAP_FAILED)
+ CHECK_NN(ANeuralNetworksMemory_createFromFd(buffer_size_bytes_, PROT_READ,
+ mmap_fd_, 0, &handle_));
+}
+
+NNAPIAllocation::~NNAPIAllocation() {
+ if (handle_) {
+ ANeuralNetworksMemory_free(handle_);
+ }
+}
+
+NNAPIDelegate::~NNAPIDelegate() {
+ if (nn_compiled_model_) {
+ ANeuralNetworksCompilation_free(nn_compiled_model_);
+ nn_compiled_model_ = nullptr;
+ }
+ if (nn_model_) {
+ ANeuralNetworksModel_free(nn_model_);
+ nn_model_ = nullptr;
+ // TODO(aselle): Is this thread-safe and callable multiple times?
+ }
+ // ANeuralNetworksShutdown();
+}
+
+// Adds the tensors of the subgraph to the NN API model.
+TfLiteStatus addTensorOperands(::tflite::Subgraph* subgraph,
+ ANeuralNetworksModel* nn_model,
+ uint32_t* no_of_operands_added,
+ std::vector<int64_t>* nnapi_ids) {
+ uint32_t next_id = 0;
+ // Allocate temporary buffer to save casted boolean tensor
+ std::unordered_map<size_t, std::unique_ptr<uint8_t[]>> const_boolean_tensors;
+
+ for (size_t i = 0; i < subgraph->tensors_size(); i++) {
+ // Skip temporaries and RNN back-edges.
+ if ((*nnapi_ids)[i] == kOperandNotNeeded) continue;
+
+ (*nnapi_ids)[i] = int64_t(next_id);
+
+ int32_t nn_type = 0;
+ // NNAPI requires 32-bit float scale to be zero, tflite doesn't care
+ float scale = 0.0f;
+ int32_t zeroPoint = 0;
+ TfLiteTensor* tensor = subgraph->tensor(i);
+ switch (tensor->type) {
+ case kTfLiteNoType:
+ // Tensors added during initialization of Ops don't have a type yet and
+ // should not be registered with the NNAPI.
+ continue;
+ case kTfLiteFloat32:
+ nn_type = ANEURALNETWORKS_TENSOR_FLOAT32;
+ break;
+ case kTfLiteUInt8:
+ // NNAPI uses ANEURALNETWORKS_TENSOR_QUANT8_ASYMM to represent uint8 type
+ // ex. ANEURALNETWORKS_CAST
+ nn_type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM;
+ scale = tensor->params.scale;
+ // ANEURALNETWORKS_TENSOR_QUANT8_ASYMM type requires scale > 0,
+ // zeroPoint >= 0 and zeroPoint <= 255
+ scale = (scale == 0.0f) ? 1.0f : scale;
+ zeroPoint = tensor->params.zero_point;
+ break;
+ case kTfLiteInt32:
+ nn_type = ANEURALNETWORKS_TENSOR_INT32;
+ scale = tensor->params.scale;
+ zeroPoint = tensor->params.zero_point;
+ break;
+ case kTfLiteBool:
+ // Workaround to pass bool type under NNAPI
+ // Use bool type using ANEURALNETWORKS_TENSOR_QUANT8_ASYMM with scale = 1.0f and zero_point = 0
+ nn_type = ANEURALNETWORKS_TENSOR_BOOL8;
+ break;
+ default:
+ logError("Unsupported tensor type %d", tensor->type);
+ return kTfLiteError;
+ }
+ if (tensor->dims->size == 0) {
+ // WORKAROUND Some model have dimension zero
+ switch (tensor->type) {
+ case kTfLiteFloat32:
+ nn_type = ANEURALNETWORKS_TENSOR_FLOAT32;
+ break;
+ case kTfLiteInt32:
+ nn_type = ANEURALNETWORKS_TENSOR_INT32;
+ break;
+ default:
+ logError("NNAPI doesn't support tensors with rank 0 (index %d name %s)",
+ i, tensor->name);
+ return kTfLiteError;
+ }
+ }
+ if (tensor->dims->size > 4) {
+ logError("NNAPI doesn't support tensors with rank > 4 (index %d name %s)",
+ i, tensor->name);
+ return kTfLiteError;
+ }
+ // TODO(aselle): Note, many of these are intermediate results. Do I need
+ // to ever specify these sizes. I am currently below doing setValue
+ // on all of them, but I shouldn't in the future.
+ // Answer(jeanluc): If all the operators can set the dimension correctly,
+ // you won't need to.
+ ANeuralNetworksOperandType operand_type{
+ nn_type, static_cast<uint32_t>(tensor->dims->size),
+ reinterpret_cast<uint32_t*>(tensor->dims->data), scale, zeroPoint};
+ if (tensor->dims->size == 0) {
+ // WORKAROUND Some model have dimension zero
+ // Consider scalar as vector size 1
+ operand_type.dimensions = dimension_for_scalar;
+ operand_type.dimensionCount = 1;
+ }
+ RETURN_ERROR_IF_NN_FAILED(
+ ANeuralNetworksModel_addOperand(nn_model, &operand_type));
+ // TODO(aselle): Based on Michael's suggestion, limiting this to read
+ // only memory
+ if (tensor->allocation_type == kTfLiteMmapRo) {
+ if (tensor->type == kTfLiteBool)
+ {
+ // ANEURALNETWORKS_TENSOR_BOOL8 tensor element size is 8 bits
+ size_t elements = tensor->bytes / sizeof(bool);
+ const_boolean_tensors[i] = std::make_unique<uint8_t[]>(elements);
+ for (size_t idx = 0; idx < elements; idx++)
+ {
+ const_boolean_tensors[i].get()[idx] = (tensor->data.b[idx] ? 0x00 : 0xff);
+ }
+ RETURN_ERROR_IF_NN_FAILED(ANeuralNetworksModel_setOperandValue(
+ nn_model, next_id, const_boolean_tensors[i].get(), tensor->bytes));
+ }
+ else if (const NNAPIAllocation* alloc = dynamic_cast<const NNAPIAllocation*>(
+ static_cast<const ::tflite::Allocation*>(tensor->allocation))) {
+ RETURN_ERROR_IF_NN_FAILED(
+ ANeuralNetworksModel_setOperandValueFromMemory(
+ nn_model, next_id, alloc->memory(),
+ alloc->offset(tensor->data.raw), tensor->bytes));
+ } else {
+ RETURN_ERROR_IF_NN_FAILED(ANeuralNetworksModel_setOperandValue(
+ nn_model, next_id, tensor->data.raw, tensor->bytes));
+ }
+ } else if (tensor->bytes == 0) {
+ // These size 0 tensors are optional tensors reserved.
+ RETURN_ERROR_IF_NN_FAILED(
+ ANeuralNetworksModel_setOperandValue(nn_model, next_id, nullptr, 0));
+ }
+
+ ++next_id;
+ }
+ *no_of_operands_added = next_id;
+ return kTfLiteOk;
+}
+
+void MapAndAddTensorIds(const int* from_ids_buf, size_t from_ids_count,
+ std::vector<uint32_t>* into,
+ const std::vector<int64_t>& map) {
+ for (size_t i = 0; i < from_ids_count; i++) {
+ int from_id = from_ids_buf[i];
+ if (from_id == kOptionalTensor) {
+ into->push_back(from_id);
+ } else {
+ into->push_back(map[from_id]);
+ }
+ }
+}
+
+// Adds the operations and their parameters to the NN API model.
+// 'next-id' is the operand ID of the next operand of the model.
+TfLiteStatus AddOpsAndParams(
+ ::tflite::Subgraph* subgraph, ANeuralNetworksModel* nn_model,
+ uint32_t next_id, std::vector<int>* model_state_inputs,
+ std::vector<int>* model_state_outputs,
+ const std::vector<int64_t>& tensor_id_to_nnapi_id) {
+ for (size_t i = 0; i < subgraph->nodes_size(); i++) {
+ const auto* node_and_registration = subgraph->node_and_registration(i);
+ const TfLiteNode& node = node_and_registration->first;
+ const TfLiteRegistration& registration = node_and_registration->second;
+ ::tflite::BuiltinOperator builtin =
+ static_cast<::tflite::BuiltinOperator>(registration.builtin_code);
+
+ // Add the parameters.
+ std::vector<uint32_t> augmented_inputs, augmented_outputs;
+ MapAndAddTensorIds(node.inputs->data, node.inputs->size, &augmented_inputs,
+ tensor_id_to_nnapi_id);
+ MapAndAddTensorIds(node.outputs->data, node.outputs->size,
+ &augmented_outputs, tensor_id_to_nnapi_id);
+
+ auto add_scalar_int32 = [&nn_model, &augmented_inputs,
+ &next_id](int value) {
+ // Fix to use strict build option
+ ANeuralNetworksOperandType operand_type{}; operand_type.type = ANEURALNETWORKS_INT32;
+ CHECK_NN(ANeuralNetworksModel_addOperand(nn_model, &operand_type))
+ CHECK_NN(ANeuralNetworksModel_setOperandValue(nn_model, next_id, &value,
+ sizeof(int32_t)))
+ augmented_inputs.push_back(next_id++);
+ };
+
+ auto add_scalar_float32 = [&nn_model, &augmented_inputs,
+ &next_id](float value) {
+ // Fix to use strict build option
+ ANeuralNetworksOperandType operand_type{}; operand_type.type = ANEURALNETWORKS_FLOAT32;
+ CHECK_NN(ANeuralNetworksModel_addOperand(nn_model, &operand_type))
+ CHECK_NN(ANeuralNetworksModel_setOperandValue(nn_model, next_id, &value,
+ sizeof(float)))
+ augmented_inputs.push_back(next_id++);
+ };
+
+ auto add_vector_int32 = [&](const int* values, uint32_t num_values) {
+ // Fix to use strict build option
+ ANeuralNetworksOperandType operand_type{};
+ operand_type.type = ANEURALNETWORKS_TENSOR_INT32;
+ operand_type.dimensionCount = 1;
+ operand_type.dimensions = &num_values;
+ CHECK_NN(ANeuralNetworksModel_addOperand(nn_model, &operand_type))
+ CHECK_NN(ANeuralNetworksModel_setOperandValue(
+ nn_model, next_id, values, sizeof(int32_t) * num_values));
+ augmented_inputs.push_back(next_id++);
+ };
+
+ // Handle state tensors of RNN, LSTM, SVDF.
+ // For each state_out tensor, a corresponding state_in operand needs to be
+ // created for NNAPI.
+ auto duplicate_state_tensor_float32 =
+ [subgraph, &nn_model, &next_id, &augmented_inputs, &model_state_inputs,
+ &model_state_outputs](int tensor_id) {
+ const TfLiteTensor* tensor = subgraph->tensor(tensor_id);
+ ANeuralNetworksOperandType operand_type{
+ ANEURALNETWORKS_TENSOR_FLOAT32,
+ static_cast<uint32_t>(tensor->dims->size),
+ reinterpret_cast<uint32_t*>(tensor->dims->data),
+ tensor->params.scale, tensor->params.zero_point};
+ CHECK_NN(ANeuralNetworksModel_addOperand(nn_model, &operand_type));
+ augmented_inputs.push_back(next_id);
+ model_state_inputs->push_back(next_id);
+ model_state_outputs->push_back(tensor_id);
+ next_id++;
+ };
+ auto check_and_add_activation = [&add_scalar_int32](int activation) {
+ if (activation > kTfLiteActRelu6) {
+ logError("NNAPI only supports RELU, RELU1 and RELU6 activations");
+ return kTfLiteError;
+ }
+ add_scalar_int32(activation);
+ return kTfLiteOk;
+ };
+
+ auto add_add_params = [&add_scalar_int32](void* data) {
+ auto* builtin = reinterpret_cast<TfLiteAddParams*>(data);
+ if (builtin->activation > kTfLiteActRelu6) {
+ logError("NNAPI only supports RELU, RELU1 and RELU6 activations");
+ return kTfLiteError;
+ }
+ add_scalar_int32(builtin->activation);
+ return kTfLiteOk;
+ };
+
+ auto add_pooling_params = [&add_scalar_int32,
+ &check_and_add_activation](void* data) {
+ auto builtin = reinterpret_cast<TfLitePoolParams*>(data);
+ add_scalar_int32(builtin->padding);
+ add_scalar_int32(builtin->stride_width);
+ add_scalar_int32(builtin->stride_height);
+ add_scalar_int32(builtin->filter_width);
+ add_scalar_int32(builtin->filter_height);
+ return check_and_add_activation(builtin->activation);
+ };
+
+ auto add_convolution_params = [&add_scalar_int32,
+ &check_and_add_activation](void* data) {
+ auto builtin = reinterpret_cast<TfLiteConvParams*>(data);
+ add_scalar_int32(builtin->padding);
+ add_scalar_int32(builtin->stride_width);
+ add_scalar_int32(builtin->stride_height);
+ return check_and_add_activation(builtin->activation);
+ };
+
+ auto add_depthwise_conv_params = [&add_scalar_int32,
+ &check_and_add_activation](void* data) {
+ auto builtin = reinterpret_cast<TfLiteDepthwiseConvParams*>(data);
+ add_scalar_int32(builtin->padding);
+ add_scalar_int32(builtin->stride_width);
+ add_scalar_int32(builtin->stride_height);
+ add_scalar_int32(builtin->depth_multiplier);
+ return check_and_add_activation(builtin->activation);
+ };
+
+ auto add_fully_connected_params = [&check_and_add_activation](void* data) {
+ auto builtin = reinterpret_cast<TfLiteFullyConnectedParams*>(data);
+ return check_and_add_activation(builtin->activation);
+ };
+
+ auto add_concatenation_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteConcatenationParams*>(data);
+ add_scalar_int32(builtin->axis);
+ if (builtin->activation != kTfLiteActNone) {
+ logError("Concatenation does not support fused activation in NNAPI");
+ return kTfLiteError;
+ }
+ return kTfLiteOk;
+ };
+
+ auto add_softmax_params = [&add_scalar_float32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteSoftmaxParams*>(data);
+ add_scalar_float32(builtin->beta);
+ };
+
+ auto add_space_to_depth_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteSpaceToDepthParams*>(data);
+ add_scalar_int32(builtin->block_size);
+ };
+
+ auto add_lstm_params = [&add_scalar_int32,
+ &add_scalar_float32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteLSTMParams*>(data);
+ add_scalar_int32(builtin->activation);
+ add_scalar_float32(builtin->cell_clip);
+ add_scalar_float32(builtin->proj_clip);
+ };
+
+ // LSTM in NNAPI requires scratch tensor as an output operand.
+ auto add_lstm_scratch_tensor_float32 = [subgraph, &node, &nn_model,
+ &next_id, &augmented_outputs]() {
+ if (node.temporaries->size == 0) return;
+ int scratch_buffer_index = node.temporaries->data[0];
+ const TfLiteTensor* tensor = subgraph->tensor(scratch_buffer_index);
+ ANeuralNetworksOperandType operand_type{
+ ANEURALNETWORKS_TENSOR_FLOAT32,
+ static_cast<uint32_t>(tensor->dims->size),
+ reinterpret_cast<uint32_t*>(tensor->dims->data), tensor->params.scale,
+ tensor->params.zero_point};
+ CHECK_NN(ANeuralNetworksModel_addOperand(nn_model, &operand_type));
+ augmented_outputs.insert(augmented_outputs.begin(), next_id++);
+ };
+
+ auto add_mean_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteReducerParams*>(data);
+ add_scalar_int32(builtin->keep_dims);
+ };
+
+ auto add_svdf_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteSVDFParams*>(data);
+ add_scalar_int32(builtin->rank);
+ add_scalar_int32(builtin->activation);
+ };
+
+ auto add_rnn_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteRNNParams*>(data);
+ add_scalar_int32(builtin->activation);
+ };
+
+ auto add_squeeze_params = [&](void* data) {
+ const auto* builtin = reinterpret_cast<TfLiteSqueezeParams*>(data);
+ // Note that we add the squeeze dimensions even if the dimensions were
+ // unspecified (empty), as NNAPI requires the operand.
+ add_vector_int32(builtin->squeeze_dims,
+ static_cast<uint32_t>(builtin->num_squeeze_dims));
+ };
+
+ // Handle optional input tensors.
+ auto add_optional_tensors = [&nn_model, &augmented_inputs,
+ &next_id](int nn_type) {
+ for (size_t idx = 0; idx < augmented_inputs.size(); idx++) {
+ // Fix to use strict build option
+ if (augmented_inputs[idx] == static_cast<uint32_t>(kOptionalTensor)) {
+ const std::vector<uint32_t> dim = {0, 0};
+ ANeuralNetworksOperandType operand_type{nn_type, 2, dim.data(), 0, 0};
+ CHECK_NN(ANeuralNetworksModel_addOperand(nn_model, &operand_type))
+ CHECK_NN(ANeuralNetworksModel_setOperandValue(nn_model, next_id,
+ nullptr, 0))
+ augmented_inputs[idx] = next_id++;
+ }
+ }
+ };
+
+ int nnapi_version = 10;
+#include "nnapi_delegate_ex_AddOpsAndParams_lambda.inc"
+
+ // Fix to use strict build option
+ ANeuralNetworksOperationType nn_op_type = -1;
+
+ // Using namespace directive to minimize diff with upstream tensorflow
+ namespace tflite = ::tflite;
+
+ switch (builtin) {
+ case tflite::BuiltinOperator_ADD:
+ nn_op_type = ANEURALNETWORKS_ADD;
+ RETURN_ERROR_IF_TFLITE_FAILED(add_add_params(node.builtin_data));
+ break;
+ case tflite::BuiltinOperator_MUL:
+ nn_op_type = ANEURALNETWORKS_MUL;
+ RETURN_ERROR_IF_TFLITE_FAILED(add_add_params(node.builtin_data));
+ break;
+ case tflite::BuiltinOperator_AVERAGE_POOL_2D:
+ RETURN_ERROR_IF_TFLITE_FAILED(add_pooling_params(node.builtin_data));
+ nn_op_type = ANEURALNETWORKS_AVERAGE_POOL_2D;
+ break;
+ case tflite::BuiltinOperator_MAX_POOL_2D:
+ RETURN_ERROR_IF_TFLITE_FAILED(add_pooling_params(node.builtin_data));
+ nn_op_type = ANEURALNETWORKS_MAX_POOL_2D;
+ break;
+ case tflite::BuiltinOperator_L2_POOL_2D:
+ RETURN_ERROR_IF_TFLITE_FAILED(add_pooling_params(node.builtin_data));
+ nn_op_type = ANEURALNETWORKS_L2_POOL_2D;
+ break;
+ case tflite::BuiltinOperator_CONV_2D: {
+ auto builtin = reinterpret_cast<TfLiteConvParams*>(node.builtin_data);
+ if (builtin->dilation_width_factor != 1 ||
+ builtin->dilation_height_factor != 1 || node.inputs->size != 3) {
+ logError("NNAPI does not support dilated Conv2D.");
+ return kTfLiteError;
+ }
+ }
+ RETURN_ERROR_IF_TFLITE_FAILED(
+ add_convolution_params(node.builtin_data));
+ nn_op_type = ANEURALNETWORKS_CONV_2D;
+ break;
+ case tflite::BuiltinOperator_RELU:
+ nn_op_type = ANEURALNETWORKS_RELU;
+ break;
+ case tflite::BuiltinOperator_RELU_N1_TO_1:
+ nn_op_type = ANEURALNETWORKS_RELU1;
+ break;
+ case tflite::BuiltinOperator_RELU6:
+ nn_op_type = ANEURALNETWORKS_RELU6;
+ break;
+ case tflite::BuiltinOperator_TANH:
+ nn_op_type = ANEURALNETWORKS_TANH;
+ break;
+ case tflite::BuiltinOperator_FLOOR:
+ nn_op_type = ANEURALNETWORKS_FLOOR;
+ break;
+ case tflite::BuiltinOperator_LOGISTIC:
+ nn_op_type = ANEURALNETWORKS_LOGISTIC;
+ break;
+ case tflite::BuiltinOperator_DEPTHWISE_CONV_2D:
+ RETURN_ERROR_IF_TFLITE_FAILED(
+ add_depthwise_conv_params(node.builtin_data));
+ nn_op_type = ANEURALNETWORKS_DEPTHWISE_CONV_2D;
+ break;
+ case tflite::BuiltinOperator_CONCATENATION:
+ RETURN_ERROR_IF_TFLITE_FAILED(
+ add_concatenation_params(node.builtin_data));
+ nn_op_type = ANEURALNETWORKS_CONCATENATION;
+ break;
+ case tflite::BuiltinOperator_SOFTMAX:
+ add_softmax_params(node.builtin_data);
+ nn_op_type = ANEURALNETWORKS_SOFTMAX;
+ break;
+ case tflite::BuiltinOperator_FULLY_CONNECTED:
+ RETURN_ERROR_IF_TFLITE_FAILED(
+ add_fully_connected_params(node.builtin_data));
+ nn_op_type = ANEURALNETWORKS_FULLY_CONNECTED;
+ break;
+ case tflite::BuiltinOperator_RESHAPE:
+ if (node.inputs->size != 2) {
+ logError("NNAPI only supports 2-input RESHAPE");
+ return kTfLiteError;
+ }
+ nn_op_type = ANEURALNETWORKS_RESHAPE;
+ // add_reshape_params(node.builtin_data);
+ break;
+ case tflite::BuiltinOperator_RESIZE_BILINEAR:
+ add_resize_bilinear_params(node.builtin_data);
+ nn_op_type = ANEURALNETWORKS_RESIZE_BILINEAR;
+ break;
+ case tflite::BuiltinOperator_SPACE_TO_DEPTH:
+ add_space_to_depth_params(node.builtin_data);
+ nn_op_type = ANEURALNETWORKS_SPACE_TO_DEPTH;
+ break;
+ case tflite::BuiltinOperator_LSTM: {
+ if (node.inputs->size + /* no of params */ 3 != 21) {
+ logError("NNAPI only supports 21-input LSTMs");
+ return kTfLiteError;
+ }
+ duplicate_state_tensor_float32(
+ node.outputs->data[/*kOutputStateTensor*/ 0]);
+ duplicate_state_tensor_float32(
+ node.outputs->data[/*kCellStateTensor*/ 1]);
+ add_lstm_params(node.builtin_data);
+ add_lstm_scratch_tensor_float32();
+ add_optional_tensors(ANEURALNETWORKS_TENSOR_FLOAT32);
+ nn_op_type = ANEURALNETWORKS_LSTM;
+ break;
+ }
+ case tflite::BuiltinOperator_DEQUANTIZE:
+ nn_op_type = ANEURALNETWORKS_DEQUANTIZE;
+ break;
+ case tflite::BuiltinOperator_SVDF: {
+ duplicate_state_tensor_float32(node.outputs->data[/*kStateTensor*/ 0]);
+ add_svdf_params(node.builtin_data);
+ nn_op_type = ANEURALNETWORKS_SVDF;
+ break;
+ }
+ case tflite::BuiltinOperator_RNN: {
+ duplicate_state_tensor_float32(
+ node.outputs->data[/*kHiddenStateTensor*/ 0]);
+ add_rnn_params(node.builtin_data);
+ nn_op_type = ANEURALNETWORKS_RNN;
+ break;
+ }
+ case tflite::BuiltinOperator_EMBEDDING_LOOKUP:
+ nn_op_type = ANEURALNETWORKS_EMBEDDING_LOOKUP;
+ break;
+ case tflite::BuiltinOperator_PAD:
+ nnapi_version = 11; // require NNAPI 1.1
+ nn_op_type = ANEURALNETWORKS_PAD;
+ break;
+ case tflite::BuiltinOperator_MEAN:
+ nnapi_version = 11; // require NNAPI 1.1
+ add_mean_params(node.builtin_data);
+ nn_op_type = ANEURALNETWORKS_MEAN;
+ break;
+ case tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION:
+ nn_op_type = ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION;
+ add_lrn_params(node.builtin_data);
+ break;
+ case tflite::BuiltinOperator_DIV:
+ nnapi_version = 11; // require NNAPI 1.1
+ nn_op_type = ANEURALNETWORKS_DIV;
+ RETURN_ERROR_IF_TFLITE_FAILED(check_and_add_activation(
+ reinterpret_cast<TfLiteDivParams*>(node.builtin_data)->activation));
+ break;
+ case tflite::BuiltinOperator_SUB:
+ nnapi_version = 11; // require NNAPI 1.1
+ nn_op_type = ANEURALNETWORKS_SUB;
+ RETURN_ERROR_IF_TFLITE_FAILED(check_and_add_activation(
+ reinterpret_cast<TfLiteSubParams*>(node.builtin_data)->activation));
+ break;
+ case tflite::BuiltinOperator_SQUEEZE:
+ nnapi_version = 11; // requires NNAPI 1.1
+ add_squeeze_params(node.builtin_data);
+ nn_op_type = ANEURALNETWORKS_SQUEEZE;
+ break;
+ case tflite::BuiltinOperator_TRANSPOSE:
+ // The permutation input tensor value dictates the output dimensions.
+ // TODO(b/110888333): Support dynamically-sized tensors in delegates.
+ if ((node.inputs->size > 1) &&
+ (subgraph->tensor(node.inputs->data[1])->allocation_type !=
+ kTfLiteMmapRo)) {
+ logError("NNAPI does not yet support dynamic tensors.");
+ return kTfLiteError;
+ }
+ nnapi_version = 11; // require NNAPI 1.1
+ nn_op_type = ANEURALNETWORKS_TRANSPOSE;
+ break;
+ case tflite::BuiltinOperator_L2_NORMALIZATION:
+ nn_op_type = ANEURALNETWORKS_L2_NORMALIZATION;
+ if (reinterpret_cast<TfLiteL2NormParams*>(node.builtin_data)
+ ->activation != kTfLiteActNone) {
+ logError(
+ "NNAPI does not support L2Normalization with fused activations");
+ return kTfLiteError;
+ }
+ if ((node.inputs->size > 0) &&
+ (subgraph->tensor(node.inputs->data[0])->dims->size != 4)) {
+ logError("NNAPI only supports input rank 4 for L2Normalization");
+ return kTfLiteError;
+ }
+ break;
+ case tflite::BuiltinOperator_HASHTABLE_LOOKUP:
+ if (subgraph->tensor(node.outputs->data[0])->type != kTfLiteFloat32) {
+ logError("NNAPI only support HASHTABLE_LOOKUP with float32 output",
+ builtin);
+ return kTfLiteError;
+ }
+ nn_op_type = ANEURALNETWORKS_HASHTABLE_LOOKUP;
+ break;
+ case tflite::BuiltinOperator_SLICE:
+ nn_op_type = ANEURALNETWORKS_SLICE;
+ break;
+ case tflite::BuiltinOperator_STRIDED_SLICE:
+ add_strided_slice_params(node.builtin_data);
+ nn_op_type = ANEURALNETWORKS_STRIDED_SLICE;
+ break;
+ case tflite::BuiltinOperator_SPACE_TO_BATCH_ND:
+ nnapi_version = 11; // require NNAPI 1.1
+ nn_op_type = ANEURALNETWORKS_SPACE_TO_BATCH_ND;
+ break;
+ case tflite::BuiltinOperator_BATCH_TO_SPACE_ND:
+ nnapi_version = 11; // require NNAPI 1.1
+ nn_op_type = ANEURALNETWORKS_BATCH_TO_SPACE_ND;
+ check_batch_to_space_params();
+ break;
+ case tflite::BuiltinOperator_CAST:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_CAST;
+ break;
+ case tflite::BuiltinOperator_TOPK_V2:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_TOPK_V2;
+ break;
+ case tflite::BuiltinOperator_GREATER:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_GREATER;
+ break;
+ case tflite::BuiltinOperator_GREATER_EQUAL:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_GREATER_EQUAL;
+ break;
+ case tflite::BuiltinOperator_LESS:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_LESS;
+ break;
+ case tflite::BuiltinOperator_LESS_EQUAL:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_LESS_EQUAL;
+ break;
+ case tflite::BuiltinOperator_GATHER:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_GATHER;
+ add_gather_params(node.builtin_data);
+ break;
+ case tflite::BuiltinOperator_SPLIT:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_SPLIT;
+ add_split_params(node.builtin_data);
+ break;
+ case tflite::BuiltinOperator_NEG:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_NEG;
+ break;
+ case tflite::BuiltinOperator_EXP:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_EXP;
+ break;
+ case tflite::BuiltinOperator_TRANSPOSE_CONV:
+ add_transpose_conv_params(node.builtin_data);
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_TRANSPOSE_CONV_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(), static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue;
+ case tflite::BuiltinOperator_PRELU:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_PRELU;
+ break;
+ case tflite::BuiltinOperator_ARG_MAX:
+ check_arg_max_input(node.builtin_data);
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_ARGMAX;
+ break;
+ case tflite::BuiltinOperator_PACK:
+ add_pack_ex_params(node.builtin_data);
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_PACK_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(), static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue;
+ case tflite::BuiltinOperator_UNPACK:
+ add_unpack_ex_params(node.builtin_data);
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_UNPACK_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(), static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue;
+ case tflite::BuiltinOperator_SQRT:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_SQRT;
+ break;
+ case tflite::BuiltinOperator_RSQRT:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_RSQRT;
+ break;
+ case tflite::BuiltinOperator_EQUAL:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_EQUAL;
+ break;
+ case tflite::BuiltinOperator_NOT_EQUAL:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_NOT_EQUAL;
+ break;
+ case tflite::BuiltinOperator_SUM:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_REDUCE_SUM;
+ add_reducer_params(node.builtin_data);
+ break;
+ case tflite::BuiltinOperator_REDUCE_ANY:
+ add_reducer_params(node.builtin_data);
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_REDUCE_ANY;
+ break;
+ case tflite::BuiltinOperator_REDUCE_MAX:
+ add_reducer_params(node.builtin_data);
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_REDUCE_MAX;
+ break;
+ case tflite::BuiltinOperator_REDUCE_MIN:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_REDUCE_MIN;
+ add_reducer_params(node.builtin_data);
+ break;
+ case tflite::BuiltinOperator_LOG:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_LOG;
+ break;
+ case tflite::BuiltinOperator_LOGICAL_AND:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_LOGICAL_AND;
+ break;
+ case tflite::BuiltinOperator_LOGICAL_OR:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_LOGICAL_OR;
+ break;
+ case tflite::BuiltinOperator_LOGICAL_NOT:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_LOGICAL_NOT;
+ break;
+ case tflite::BuiltinOperator_SQUARED_DIFFERENCE:
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_SQUARED_DIFFERENCE_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(),
+ static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue;
+ case tflite::BuiltinOperator_MAXIMUM:
+ nn_op_type = ANEURALNETWORKS_MAXIMUM;
+ break;
+ case tflite::BuiltinOperator_MINIMUM:
+ nn_op_type = ANEURALNETWORKS_MINIMUM;
+ break;
+ case tflite::BuiltinOperator_ABS:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_ABS;
+ break;
+ case tflite::BuiltinOperator_ONE_HOT:
+ add_one_hot_params(node.builtin_data);
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_ONE_HOT_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(), static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue; // _EX operator should use `continue` to skip addOperanation.
+ case tflite::BuiltinOperator_SIN:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_SIN;
+ break;
+ case tflite::BuiltinOperator_SHAPE:
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_SHAPE_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(), static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue; // _EX operator should use `continue` to skip addOperanation.
+ case tflite::BuiltinOperator_REDUCE_PROD:
+ add_reducer_params(node.builtin_data);
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_REDUCE_PROD;
+ break;
+ case tflite::BuiltinOperator_EXPAND_DIMS:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_EXPAND_DIMS;
+ break;
+ case tflite::BuiltinOperator_POW:
+ if (!(subgraph->tensor(node.inputs->data[0])->type == kTfLiteFloat32 &&
+ subgraph->tensor(node.inputs->data[1])->type == kTfLiteFloat32)) {
+ logError("NNAPI delegate for Pow supports only float32.", builtin);
+ return kTfLiteError;
+ }
+ nn_op_type = ANEURALNETWORKS_POW;
+ break;
+ case tflite::BuiltinOperator_SELECT:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_SELECT;
+ break;
+ case tflite::BuiltinOperator_ZEROS_LIKE:
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_ZEROS_LIKE_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(), static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue; // _EX operator should use `continue` to skip addOperanation.
+ case tflite::BuiltinOperator_TILE:
+ nnapi_version = 12; // require NNAPI 1.2
+ nn_op_type = ANEURALNETWORKS_TILE;
+ break;
+ case tflite::BuiltinOperator_CONCAT_EMBEDDINGS:
+ case tflite::BuiltinOperator_LSH_PROJECTION:
+ case tflite::BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN:
+ case tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN:
+ case tflite::BuiltinOperator_EMBEDDING_LOOKUP_SPARSE:
+ case tflite::BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM:
+ case tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM:
+ //case tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION:
+ case tflite::BuiltinOperator_PADV2:
+ //case tflite::BuiltinOperator_RESIZE_BILINEAR:
+ case tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR:
+ case tflite::BuiltinOperator_CALL:
+ case tflite::BuiltinOperator_SKIP_GRAM:
+ //case tflite::BuiltinOperator_RELU_N1_TO_1:
+ //case tflite::BuiltinOperator_GATHER:
+ //case tflite::BuiltinOperator_SPACE_TO_BATCH_ND:
+ //case tflite::BuiltinOperator_BATCH_TO_SPACE_ND:
+ //case tflite::BuiltinOperator_TOPK_V2:
+ //case tflite::BuiltinOperator_SPLIT:
+ //case tflite::BuiltinOperator_STRIDED_SLICE:
+ //case tflite::BuiltinOperator_EXP:
+ case tflite::BuiltinOperator_LOG_SOFTMAX:
+ //case tflite::BuiltinOperator_DEQUANTIZE:
+ case tflite::BuiltinOperator_DELEGATE:
+ //case tflite::BuiltinOperator_CAST:
+ //case tflite::BuiltinOperator_PRELU:
+ //case tflite::BuiltinOperator_MAXIMUM:
+ //case tflite::BuiltinOperator_MINIMUM:
+ //case tflite::BuiltinOperator_ARG_MAX:
+ case tflite::BuiltinOperator_ARG_MIN:
+ //case tflite::BuiltinOperator_GREATER:
+ //case tflite::BuiltinOperator_GREATER_EQUAL:
+ //case tflite::BuiltinOperator_LESS:
+ //case tflite::BuiltinOperator_LESS_EQUAL:
+ //case tflite::BuiltinOperator_NEG:
+ //case tflite::BuiltinOperator_SELECT:
+ // case tflite::BuiltinOperator_SLICE:
+ //case tflite::BuiltinOperator_SIN:
+ //case tflite::BuiltinOperator_LOG:
+ //case tflite::BuiltinOperator_TRANSPOSE_CONV:
+ //case tflite::BuiltinOperator_TILE:
+ //case tflite::BuiltinOperator_EXPAND_DIMS:
+ case tflite::BuiltinOperator_SPARSE_TO_DENSE:
+ //case tflite::BuiltinOperator_EQUAL:
+ //case tflite::BuiltinOperator_NOT_EQUAL:
+ //case tflite::BuiltinOperator_SUM:
+ //case tflite::BuiltinOperator_REDUCE_MAX:
+ //case tflite::BuiltinOperator_REDUCE_MIN:
+ //case tflite::BuiltinOperator_REDUCE_PROD:
+ //case tflite::BuiltinOperator_SQRT:
+ //case tflite::BuiltinOperator_RSQRT:
+ //case tflite::BuiltinOperator_SHAPE:
+ //case tflite::BuiltinOperator_POW:
+ case tflite::BuiltinOperator_FAKE_QUANT:
+ //case tflite::BuiltinOperator_PACK:
+ //case tflite::BuiltinOperator_LOGICAL_OR:
+ //case tflite::BuiltinOperator_ONE_HOT:
+ //case tflite::BuiltinOperator_LOGICAL_AND:
+ //case tflite::BuiltinOperator_LOGICAL_NOT:
+ //case tflite::BuiltinOperator_UNPACK:
+ case tflite::BuiltinOperator_FLOOR_DIV:
+ //case tflite::BuiltinOperator_REDUCE_ANY:
+ case tflite::BuiltinOperator_SQUARE:
+ //case tflite::BuiltinOperator_ZEROS_LIKE:
+ case tflite::BuiltinOperator_FILL:
+ case tflite::BuiltinOperator_FLOOR_MOD:
+ case tflite::BuiltinOperator_RANGE:
+ case tflite::BuiltinOperator_LEAKY_RELU:
+ //case tflite::BuiltinOperator_SQUARED_DIFFERENCE:
+ case tflite::BuiltinOperator_MIRROR_PAD:
+ //case tflite::BuiltinOperator_ABS:
+ case tflite::BuiltinOperator_SPLIT_V:
+ logError("Op code %d is currently not delegated to NNAPI", builtin);
+ return kTfLiteError;
+ break;
+ case tflite::BuiltinOperator_CUSTOM: {
+ std::string custom_name(registration.custom_name);
+ if (custom_name.compare("SquaredDifference") == 0) {
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_SQUARED_DIFFERENCE_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(),
+ static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue;
+ }
+ else if (custom_name.compare("MatrixBandPart") == 0) {
+ CHECK_NN(ANeuralNetworksModel_addOperationEx(
+ nn_model, ANEURALNETWORKS_MATRIX_BAND_PART_EX,
+ static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(),
+ static_cast<uint32_t>(node.outputs->size),
+ reinterpret_cast<uint32_t*>(node.outputs->data)));
+ continue;
+ }
+ logError("Custom operations are not supported when using NNAPI.");
+ return kTfLiteError;
+ break;
+ }
+ default:
+ // Fix to use strict build option
+ logError("Op code %d is currently not delegated to NNAPI", builtin);
+ return kTfLiteError;
+ break;
+ }
+
+ if (nnapi_version == 11 && GetAndroidSdkVersionCached() < 28) {
+ //logError("Op %d needs NNAPI1.1", builtin);
+ //return kTfLiteError;
+ }
+
+ // Add the operation.
+ RETURN_ERROR_IF_NN_FAILED(ANeuralNetworksModel_addOperation(
+ nn_model, nn_op_type, static_cast<uint32_t>(augmented_inputs.size()),
+ augmented_inputs.data(),
+ static_cast<uint32_t>(augmented_outputs.size()),
+ reinterpret_cast<uint32_t*>(augmented_outputs.data())));
+ }
+ return kTfLiteOk;
+}
+
+TfLiteStatus NNAPIDelegate::BuildGraph(::tflite::Subgraph* subgraph) {
+ if (nn_model_ && nn_compiled_model_) return model_status_;
+
+ // TODO(aselle): This is not correct. need to handle resize invalidation.
+ if (!nn_model_) {
+ CHECK_NN(ANeuralNetworksModel_create(&nn_model_));
+
+ // Find which tensors should be added to NNAPI. TFLite has temporaries
+ // and RNN back-edges which are are not valid for NNAPI. We look through all
+ // inputs and outputs and mark the mapping in tensor_id_to_nnapi_id with
+ // kOperandIdNotSet. addTensorOperands will replace those with the
+ // corresponding NNAPI operand ids and skip kOperandNotNeeded entries.
+ std::vector<int64_t> tensor_id_to_nnapi_id(subgraph->tensors_size(),
+ kOperandNotNeeded);
+ // Fix to use strict build option
+ auto set_ids_to_not_set = [&tensor_id_to_nnapi_id](const int* buf,
+ int count) {
+ for (int j = 0; j < count; j++) {
+ auto tensor_id = buf[j];
+ if (tensor_id != kOptionalTensor) {
+ tensor_id_to_nnapi_id[tensor_id] = kOperandIdNotSet;
+ }
+ }
+ };
+ for (size_t i = 0; i < subgraph->nodes_size(); i++) {
+ const auto* node_and_registration = subgraph->node_and_registration(i);
+ const TfLiteNode& node = node_and_registration->first;
+ set_ids_to_not_set(node.inputs->data, node.inputs->size);
+ set_ids_to_not_set(node.outputs->data, node.outputs->size);
+ }
+ set_ids_to_not_set(subgraph->inputs().data(), subgraph->inputs().size());
+ set_ids_to_not_set(subgraph->outputs().data(), subgraph->outputs().size());
+
+ uint32_t next_id = 0;
+ RETURN_ERROR_IF_TFLITE_FAILED(addTensorOperands(
+ subgraph, nn_model_, &next_id, &tensor_id_to_nnapi_id));
+ RETURN_ERROR_IF_TFLITE_FAILED(
+ AddOpsAndParams(subgraph, nn_model_, next_id, &model_states_inputs_,
+ &model_states_outputs_, tensor_id_to_nnapi_id));
+
+ std::vector<uint32_t> augmented_inputs;
+ MapAndAddTensorIds(subgraph->inputs().data(), subgraph->inputs().size(),
+ &augmented_inputs, tensor_id_to_nnapi_id);
+ augmented_inputs.insert(augmented_inputs.end(),
+ model_states_inputs_.begin(),
+ model_states_inputs_.end());
+ std::vector<uint32_t> augmented_outputs;
+ MapAndAddTensorIds(subgraph->outputs().data(), subgraph->outputs().size(),
+ &augmented_outputs, tensor_id_to_nnapi_id);
+ MapAndAddTensorIds(model_states_outputs_.data(),
+ model_states_outputs_.size(), &augmented_outputs,
+ tensor_id_to_nnapi_id);
+
+ CHECK_NN(ANeuralNetworksModel_identifyInputsAndOutputs(
+ nn_model_, static_cast<uint32_t>(augmented_inputs.size()),
+ reinterpret_cast<const uint32_t*>(augmented_inputs.data()),
+ static_cast<uint32_t>(augmented_outputs.size()),
+ reinterpret_cast<const uint32_t*>(augmented_outputs.data())));
+
+ // TODO Support ANeuralNetworksModel_relaxComputationFloat32toFloat16
+ /*if (GetAndroidSdkVersionCached() >= 28) {
+ CHECK_NN(ANeuralNetworksModel_relaxComputationFloat32toFloat16(
+ nn_model_, subgraph->GetAllowFp16PrecisionForFp32()));
+ }*/
+ CHECK_NN(ANeuralNetworksModel_finish(nn_model_));
+ }
+ if (!nn_compiled_model_) {
+ CHECK_NN(ANeuralNetworksCompilation_create(nn_model_, &nn_compiled_model_));
+ CHECK_NN(ANeuralNetworksCompilation_finish(nn_compiled_model_));
+ }
+ return kTfLiteOk;
+}
+
+// Use unordered_map for temporary buffer
+#include <unordered_map>
+
+TfLiteStatus NNAPIDelegate::Invoke(::tflite::Subgraph* subgraph) {
+ if (!nn_model_) {
+ model_status_ = BuildGraph(subgraph);
+ if (model_status_ != kTfLiteOk) {
+ logError("Failed to build graph for NNAPI");
+ }
+ }
+ if (model_status_ != kTfLiteOk) {
+ return model_status_;
+ }
+
+ ANeuralNetworksExecution* execution = nullptr;
+ CHECK_NN(ANeuralNetworksExecution_create(nn_compiled_model_, &execution));
+
+ // Allocate temporary buffer to save casted boolean tensor
+ std::unordered_map<size_t, uint8_t*> input_boolean_tensors;
+ std::unordered_map<size_t, uint8_t*> output_boolean_tensors;
+ for (size_t i = 0; i < subgraph->inputs().size(); i++)
+ {
+ int input = subgraph->inputs()[i];
+ TfLiteTensor* tensor = subgraph->tensor(input);
+ if (tensor->type == kTfLiteBool)
+ {
+ size_t elements = tensor->bytes / sizeof(bool);
+ uint8_t* temp_tensor = new uint8_t[tensor->bytes / sizeof(bool)];
+ input_boolean_tensors[i] = temp_tensor;
+ for (size_t idx = 0; idx < elements; idx++)
+ {
+ temp_tensor[idx] = (tensor->data.b[idx] ? 0x00 : 0xff);
+ }
+ }
+ }
+ for (size_t i = 0; i < subgraph->outputs().size(); i++)
+ {
+ int output = subgraph->outputs()[i];
+ TfLiteTensor* tensor = subgraph->tensor(output);
+ if (tensor->type == kTfLiteBool)
+ {
+ uint8_t* temp_tensor = new uint8_t[tensor->bytes / sizeof(bool)];
+ output_boolean_tensors[i] = temp_tensor;
+ }
+ }
+
+ // Currently perform deep copy of input buffer
+ for (size_t i = 0; i < subgraph->inputs().size(); i++) {
+ int input = subgraph->inputs()[i];
+ // TODO(aselle): Is this what we want or do we want input instead?
+ // TODO(aselle): This should be called setInputValue maybe to be cons.
+ TfLiteTensor* tensor = subgraph->tensor(input);
+ // Workaround to pass bool type under NNAPI
+ // ANEURALNETWORKS_TENSOR_BOOL8 tensor element size is 8 bits
+ if (tensor->type == kTfLiteBool)
+ {
+ CHECK_NN(ANeuralNetworksExecution_setInput(
+ execution, i, nullptr, input_boolean_tensors[i], tensor->bytes * sizeof(uint8_t) / sizeof(bool)));
+ }
+ else
+ {
+ CHECK_NN(ANeuralNetworksExecution_setInput(
+ execution, i, nullptr, tensor->data.raw, tensor->bytes));
+ }
+ }
+
+ // Tell nn api where to place final data.
+ for (size_t i = 0; i < subgraph->outputs().size(); i++) {
+ int output = subgraph->outputs()[i];
+ TfLiteTensor* tensor = subgraph->tensor(output);
+
+ // Workaround to pass bool type under NNAPI
+ // ANEURALNETWORKS_TENSOR_BOOL8 tensor element size is 8 bits
+ if (tensor->type == kTfLiteBool)
+ {
+ CHECK_NN(ANeuralNetworksExecution_setOutput(
+ execution, i, nullptr, output_boolean_tensors[i], tensor->bytes * sizeof(uint8_t) / sizeof(bool)));
+ }
+ else
+ {
+ CHECK_NN(ANeuralNetworksExecution_setOutput(
+ execution, i, nullptr, tensor->data.raw, tensor->bytes));
+ }
+ }
+
+ // The state_out of previous invocation need to be mapped to state_in of
+ // current invocation.
+ for (size_t i = 0; i < model_states_outputs_.size(); i++) {
+ int state_tensor_idx = model_states_outputs_[i];
+ TfLiteTensor* tensor = subgraph->tensor(state_tensor_idx);
+ // Here we are using a deep copy for state_in tensors so that we are not
+ // reading and writing into the same buffer during a invocation.
+ // TODO(miaowang): using double shared buffer to minimize the copies.
+ CHECK_NN(ANeuralNetworksExecution_setInput(
+ execution, i + subgraph->inputs().size(), nullptr, tensor->data.raw,
+ tensor->bytes));
+ // Tell NNAPI where to output the state_out.
+ CHECK_NN(ANeuralNetworksExecution_setOutput(
+ execution, i + subgraph->outputs().size(), nullptr, tensor->data.raw,
+ tensor->bytes));
+ }
+
+ // Currently use blocking compute.
+ ANeuralNetworksEvent* event = nullptr;
+ CHECK_NN(ANeuralNetworksExecution_startCompute(execution, &event));
+ CHECK_NN(ANeuralNetworksEvent_wait(event));
+ ANeuralNetworksEvent_free(event);
+ ANeuralNetworksExecution_free(execution);
+
+ // Tell nn api where to place final data.
+ for (size_t i = 0; i < subgraph->inputs().size(); i++) {
+ int input = subgraph->inputs()[i];
+ TfLiteTensor* tensor = subgraph->tensor(input);
+
+ if (tensor->type == kTfLiteBool)
+ {
+ uint8_t* temp_tensor = input_boolean_tensors[i];
+ input_boolean_tensors[i] = nullptr;
+ delete temp_tensor;
+ }
+ }
+ for (size_t i = 0; i < subgraph->outputs().size(); i++) {
+ int output = subgraph->outputs()[i];
+ TfLiteTensor* tensor = subgraph->tensor(output);
+
+ if (tensor->type == kTfLiteBool)
+ {
+ uint8_t* temp_tensor = output_boolean_tensors[i];
+ size_t elements = tensor->bytes / sizeof(bool);
+ for (size_t idx = 0; idx < elements; idx++)
+ {
+ tensor->data.b[idx] = ((temp_tensor[idx] == 0x00) ? false : true);
+ }
+ output_boolean_tensors[i] = nullptr;
+ delete temp_tensor;
+ }
+ }
+
+#if 0
+ printf("From the NN API:\n");
+ TfLiteTensor* tensor = subgraph->tensor(subgraph->outputs()[0]);
+ if (float* data =
+ subgraph->typed_tensor<float>(subgraph->outputs()[0])) {
+ size_t num = tensor->bytes / sizeof(float);
+ for (float* p = data; p < data + num; p++) {
+ printf(" %f", *p);
+ }
+ printf("\n");
+ }
+#endif
+
+ return kTfLiteOk;
+}
+
+bool NNAPIDelegate::IsSupported() { return nnfw::NNAPIExists(); }
+
+} // namespace tflite
+} // namespace nnfw
+
+// clang-format on
diff --git a/runtime/libs/tflite/port/1.13.1/src/nnapi_delegate_ex_AddOpsAndParams_lambda.inc b/runtime/libs/tflite/port/1.13.1/src/nnapi_delegate_ex_AddOpsAndParams_lambda.inc
new file mode 100644
index 000000000..39355b106
--- /dev/null
+++ b/runtime/libs/tflite/port/1.13.1/src/nnapi_delegate_ex_AddOpsAndParams_lambda.inc
@@ -0,0 +1,153 @@
+// This file is included from AddOpsAndParams defined in nnapi_delegate.cc
+// and contains lambda for extened implementation to original Tensorflow Lite.
+ auto add_scalar_bool8 = [&nn_model, &augmented_inputs,
+ &next_id](bool value) {
+ // Fix to use strict build option
+ int8_t casted_value = (value ? 1 : 0);
+ ANeuralNetworksOperandType operand_type{}; operand_type.type = ANEURALNETWORKS_BOOL;
+ CHECK_NN(ANeuralNetworksModel_addOperand(nn_model, &operand_type))
+ CHECK_NN(ANeuralNetworksModel_setOperandValue(nn_model, next_id, &casted_value,
+ sizeof(int8_t)))
+ augmented_inputs.push_back(next_id++);
+ };
+
+ auto add_resize_bilinear_params = [&add_scalar_int32, &subgraph, &augmented_inputs](void* data) {
+ auto builtin = reinterpret_cast<TfLiteResizeBilinearParams*>(data);
+ if (builtin->align_corners) {
+ FATAL("Resize bilinear does not support align corners in NNAPI");
+ }
+
+ TfLiteTensor* tensor = subgraph->tensor(augmented_inputs.back());
+ assert(tensor->type == kTfLiteInt32);
+ assert(tensor->bytes == sizeof(int)*2);
+ augmented_inputs.pop_back();
+
+ int height = ((int*)(tensor->data.raw))[1];
+ int width = ((int*)(tensor->data.raw))[0];
+ add_scalar_int32(height);
+ add_scalar_int32(width);
+ };
+
+ auto add_transpose_conv_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteTransposeConvParams*>(data);
+ add_scalar_int32(builtin->padding);
+ add_scalar_int32(builtin->stride_width);
+ add_scalar_int32(builtin->stride_height);
+ };
+
+ auto add_lrn_params = [&add_scalar_int32,
+ &add_scalar_float32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteLocalResponseNormParams*>(data);
+ add_scalar_int32(builtin->radius);
+ add_scalar_float32(builtin->bias);
+ add_scalar_float32(builtin->alpha);
+ add_scalar_float32(builtin->beta);
+ };
+
+ auto add_strided_slice_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteStridedSliceParams*>(data);
+ add_scalar_int32(builtin->begin_mask);
+ add_scalar_int32(builtin->end_mask);
+ // ellipsis_mask and new_axis_mask are not supported on nn runtime
+ // cf) tflite interpreter supports both operations
+ if (builtin->ellipsis_mask) {
+ FATAL("STRIDE_SLICE does not support ellipsis_mask in NNAPI");
+ }
+ if (builtin->new_axis_mask) {
+ FATAL("STRIDE_SLICE does not support new_axis_mask in NNAPI");
+ }
+ add_scalar_int32(builtin->shrink_axis_mask);
+ };
+
+ auto add_gather_params = [&add_scalar_int32, &augmented_inputs](void* data) {
+ auto builtin = reinterpret_cast<TfLiteGatherParams*>(data);
+ if (builtin->axis != 0) {
+ FATAL("GATHER does not support axis>0 in NNAPI");
+ }
+
+ auto indices_index = augmented_inputs.back();
+ augmented_inputs.pop_back();
+ add_scalar_int32(builtin->axis);
+ augmented_inputs.push_back(indices_index);
+ };
+
+ auto add_pack_ex_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLitePackParams*>(data);
+ add_scalar_int32(builtin->values_count);
+ add_scalar_int32(builtin->axis);
+ };
+
+ auto add_unpack_ex_params = [&add_scalar_int32](void* data) {
+ auto builtin = reinterpret_cast<TfLiteUnpackParams*>(data);
+ add_scalar_int32(builtin->num);
+ add_scalar_int32(builtin->axis);
+ };
+
+ auto check_batch_to_space_params = [subgraph, &node, &augmented_inputs]() {
+
+ //If there are 3 inputs, check if crops is having default values {0, 0, 0, 0}
+ //Else unsupported by NNAPI
+
+ if(augmented_inputs.size() == 3)
+ {
+ const uint32_t crops_buffer_index = node.inputs->data[2];
+ const TfLiteTensor* crops = subgraph->tensor(crops_buffer_index);
+ const int *crops_value = crops->data.i32;
+
+ //Check if crops is having default values {0, 0, 0, 0}
+ if(crops_value[0] != 0 || crops_value[1] != 0 || crops_value[2] != 0 || crops_value[3] != 0)
+ {
+ FATAL("BATCH_TO_SPACE_ND does not support Explicit crops in NNAPI");
+ }
+ else
+ {
+ //Restrict crops input and pass only other two inputs
+ augmented_inputs.pop_back();
+ }
+ }
+ };
+
+ auto add_split_params = [&add_scalar_int32, &augmented_inputs](void* data) {
+ // swap 1st and 2nd operand order
+ auto input_tensor = augmented_inputs[1];
+ auto axis = augmented_inputs[0];
+ augmented_inputs[0] = input_tensor;
+ augmented_inputs[1] = axis;
+
+ auto builtin = reinterpret_cast<TfLiteSplitParams*>(data);
+ add_scalar_int32(builtin->num_splits);
+ };
+
+ auto check_arg_max_input = [&subgraph, &augmented_inputs](void *data) {
+ auto params = reinterpret_cast<TfLiteArgMaxParams*>(data);
+ if (params->output_type != kTfLiteInt32)
+ {
+ FATAL("Cannot handle output type in NNAPI");
+ }
+
+ TfLiteTensor* axis_tensor = subgraph->tensor(augmented_inputs.back());
+ assert(axis_tensor->type == kTfLiteInt32);
+
+ int64_t count = 1;
+ for (int i = 0; i < axis_tensor->dims->size; ++i) {
+ count *= axis_tensor->dims->data[i];
+ }
+ assert(count == 1);
+ };
+
+ auto add_reducer_params = [&add_scalar_bool8](void* data) {
+ auto builtin = reinterpret_cast<TfLiteReducerParams*>(data);
+ if (builtin == nullptr)
+ {
+ add_scalar_bool8(0);
+ }
+ else
+ {
+ add_scalar_bool8(builtin->keep_dims);
+ }
+ };
+
+ auto add_one_hot_params = [&add_scalar_int32](void* data) {
+ const auto* builtin = reinterpret_cast<TfLiteOneHotParams*>(data);
+ add_scalar_int32(builtin->axis);
+ };
diff --git a/runtime/libs/tflite/port/CMakeLists.txt b/runtime/libs/tflite/port/CMakeLists.txt
new file mode 100644
index 000000000..82c83f722
--- /dev/null
+++ b/runtime/libs/tflite/port/CMakeLists.txt
@@ -0,0 +1,7 @@
+# We may need to support multiple tensorflow version
+# Example)
+# For ubuntu: tensorflow lite v1.13.1
+# For tizen: tensorflow lite v1.9
+set(SUPPORT_TFLITE_VERSION "1.13.1" CACHE STRING "Supporting TensorFlow lite version")
+
+add_subdirectories()
diff --git a/runtime/libs/tflite/src/Diff.cpp b/runtime/libs/tflite/src/Diff.cpp
new file mode 100644
index 000000000..39f994352
--- /dev/null
+++ b/runtime/libs/tflite/src/Diff.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/Diff.h"
+
+#include "misc/fp32.h"
+
+#include "misc/tensor/IndexFormatter.h"
+#include "misc/tensor/Zipper.h"
+#include "misc/tensor/Comparator.h"
+
+#include <iostream>
+#include <cassert>
+
+class DiffSummary : public nnfw::misc::tensor::Comparator::Observer
+{
+public:
+ DiffSummary()
+ : max_abs_diff_index(0), max_abs_diff_expected{0.0f}, max_abs_diff_obtained{0.0f},
+ max_abs_diff_value{0.0f}, max_rel_diff_index(0), max_rel_diff_expected{0.0f},
+ max_rel_diff_obtained{0.0f}, max_rel_diff_value{0.0f}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void notify(const nnfw::misc::tensor::Index &index, float expected, float obtained) override;
+
+public:
+ nnfw::misc::tensor::Index max_abs_diff_index;
+ float max_abs_diff_expected;
+ float max_abs_diff_obtained;
+ float max_abs_diff_value;
+
+ nnfw::misc::tensor::Index max_rel_diff_index;
+ float max_rel_diff_expected;
+ float max_rel_diff_obtained;
+ float max_rel_diff_value;
+};
+
+void DiffSummary::notify(const nnfw::misc::tensor::Index &index, float expected, float obtained)
+{
+ const auto abs_diff_value = std::fabs(expected - obtained);
+
+ if (max_abs_diff_value < abs_diff_value)
+ {
+ max_abs_diff_index = index;
+ max_abs_diff_value = abs_diff_value;
+ max_abs_diff_expected = expected;
+ max_abs_diff_obtained = obtained;
+ }
+
+ const auto rel_diff_value = nnfw::misc::fp32::relative_diff(expected, obtained);
+
+ if (max_rel_diff_value < rel_diff_value)
+ {
+ max_rel_diff_index = index;
+ max_rel_diff_value = rel_diff_value;
+ max_rel_diff_expected = expected;
+ max_rel_diff_obtained = obtained;
+ }
+}
+
+template <typename T>
+bool TfLiteInterpMatchApp::compareSingleTensorView(const nnfw::tflite::TensorView<T> &expected,
+ const nnfw::tflite::TensorView<T> &obtained,
+ int id) const
+{
+ std::vector<nnfw::misc::tensor::Diff<T>> diffs;
+ assert(expected.shape() == obtained.shape());
+
+ using nnfw::misc::tensor::Index;
+ using nnfw::misc::tensor::zip;
+
+ zip(expected.shape(), expected, obtained)
+ << [&](const Index &index, T expected_value, T obtained_value) {
+ if (expected_value != obtained_value)
+ {
+ diffs.emplace_back(index, expected_value, obtained_value);
+ }
+ };
+
+ // TODO Unify summary generation code
+ if (diffs.size() == 0)
+ {
+ std::cout << " Tensor #" << id << ": MATCHED" << std::endl;
+ }
+ else
+ {
+ std::cout << " Tensor #" << id << ": UNMATCHED" << std::endl;
+ std::cout << " " << diffs.size() << " diffs are detected" << std::endl;
+ }
+
+ if (diffs.size() > 0 && _verbose != 0)
+ {
+ std::cout << " ---- Details ---" << std::endl;
+ for (const auto &diff : diffs)
+ {
+ std::cout << " Diff at [" << nnfw::misc::tensor::IndexFormatter(diff.index) << "]"
+ << std::endl;
+ std::cout << " expected: " << diff.expected << std::endl;
+ std::cout << " obtained: " << diff.obtained << std::endl;
+ }
+ }
+
+ return diffs.size() == 0;
+}
+
+template <>
+bool TfLiteInterpMatchApp::compareSingleTensorView<float>(
+ const nnfw::tflite::TensorView<float> &expected,
+ const nnfw::tflite::TensorView<float> &obtained, int id) const
+{
+ DiffSummary summary;
+
+ assert(expected.shape() == obtained.shape());
+ auto diffs = _comparator.compare(expected.shape(), expected, obtained, &summary);
+
+ // TODO Unify summary generation code
+ if (diffs.size() == 0)
+ {
+ std::cout << " Tensor #" << id << ": MATCHED" << std::endl;
+ }
+ else
+ {
+ std::cout << " Tensor #" << id << ": UNMATCHED" << std::endl;
+ std::cout << " " << diffs.size() << " diffs are detected" << std::endl;
+ }
+
+ // Print out max_diff
+ if (summary.max_abs_diff_value > 0)
+ {
+ std::cout << " Max absolute diff at ["
+ << nnfw::misc::tensor::IndexFormatter(summary.max_abs_diff_index) << "]" << std::endl;
+ std::cout << " expected: " << summary.max_abs_diff_expected << std::endl;
+ std::cout << " obtained: " << summary.max_abs_diff_obtained << std::endl;
+ std::cout << " absolute diff: " << summary.max_abs_diff_value << std::endl;
+ }
+
+ if (summary.max_rel_diff_value > 0)
+ {
+ const auto tolerance_level = summary.max_rel_diff_value / FLT_EPSILON;
+
+ std::cout << " Max relative diff at ["
+ << nnfw::misc::tensor::IndexFormatter(summary.max_rel_diff_index) << "]" << std::endl;
+ std::cout << " expected: " << summary.max_rel_diff_expected << std::endl;
+ std::cout << " obtained: " << summary.max_rel_diff_obtained << std::endl;
+ std::cout << " relative diff: " << summary.max_rel_diff_value << std::endl;
+ std::cout << " (tolerance level = " << tolerance_level << ")" << std::endl;
+ }
+
+ if (diffs.size() > 0)
+ {
+ if (_verbose != 0)
+ {
+ std::cout << " ---- Details ---" << std::endl;
+ for (const auto &diff : diffs)
+ {
+ const auto absolute_diff = std::fabs(diff.expected - diff.obtained);
+ const auto relative_diff = nnfw::misc::fp32::relative_diff(diff.expected, diff.obtained);
+ const auto tolerance_level = relative_diff / FLT_EPSILON;
+
+ std::cout << " Diff at [" << nnfw::misc::tensor::IndexFormatter(diff.index) << "]"
+ << std::endl;
+ std::cout << " expected: " << diff.expected << std::endl;
+ std::cout << " obtained: " << diff.obtained << std::endl;
+ std::cout << " absolute diff: " << absolute_diff << std::endl;
+ std::cout << " relative diff: " << relative_diff << std::endl;
+ std::cout << " (tolerance level = " << tolerance_level << ")" << std::endl;
+ }
+ }
+
+ return false;
+ }
+ return true;
+}
+
+#include <map>
+
+bool TfLiteInterpMatchApp::run(::tflite::Interpreter &interp, ::tflite::Interpreter &nnapi) const
+{
+ assert(interp.outputs() == nnapi.outputs());
+
+ bool all_matched = true;
+
+ using Comparator = std::function<bool(int id, ::tflite::Interpreter &, ::tflite::Interpreter &)>;
+
+ std::map<TfLiteType, Comparator> comparators;
+
+ comparators[kTfLiteUInt8] = [this](int id, ::tflite::Interpreter &interp,
+ ::tflite::Interpreter &nnapi) {
+ const auto expected = nnfw::tflite::TensorView<uint8_t>::make(interp, id);
+ const auto obtained = nnfw::tflite::TensorView<uint8_t>::make(nnapi, id);
+
+ return compareSingleTensorView(expected, obtained, id);
+ };
+
+ comparators[kTfLiteInt32] = [this](int id, ::tflite::Interpreter &interp,
+ ::tflite::Interpreter &nnapi) {
+ const auto expected = nnfw::tflite::TensorView<int32_t>::make(interp, id);
+ const auto obtained = nnfw::tflite::TensorView<int32_t>::make(nnapi, id);
+
+ return compareSingleTensorView(expected, obtained, id);
+ };
+
+ comparators[kTfLiteFloat32] = [this](int id, ::tflite::Interpreter &interp,
+ ::tflite::Interpreter &nnapi) {
+ const auto expected = nnfw::tflite::TensorView<float>::make(interp, id);
+ const auto obtained = nnfw::tflite::TensorView<float>::make(nnapi, id);
+
+ return compareSingleTensorView(expected, obtained, id);
+ };
+
+ comparators[kTfLiteBool] = [this](int id, ::tflite::Interpreter &interp,
+ ::tflite::Interpreter &nnapi) {
+ const auto expected = nnfw::tflite::TensorView<bool>::make(interp, id);
+ const auto obtained = nnfw::tflite::TensorView<bool>::make(nnapi, id);
+
+ return compareSingleTensorView(expected, obtained, id);
+ };
+
+ for (const auto &id : interp.outputs())
+ {
+ assert(interp.tensor(id)->type == nnapi.tensor(id)->type);
+
+ auto it = comparators.find(interp.tensor(id)->type);
+
+ if (it == comparators.end())
+ {
+ throw std::runtime_error{"Not supported output type"};
+ }
+
+ const auto &comparator = it->second;
+
+ if (!comparator(id, interp, nnapi))
+ {
+ all_matched = false;
+ }
+ }
+
+ return all_matched;
+}
diff --git a/runtime/libs/tflite/src/FeatureView.cpp b/runtime/libs/tflite/src/FeatureView.cpp
new file mode 100644
index 000000000..fdf5a4b00
--- /dev/null
+++ b/runtime/libs/tflite/src/FeatureView.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/FeatureView.h"
+#include "tflite/TensorUtils.h"
+
+#include <cassert>
+
+namespace nnfw
+{
+namespace tflite
+{
+
+nnfw::misc::feature::Shape getFeatureShape(const TfLiteTensor *tensor)
+{
+ nnfw::misc::feature::Shape shape{tensor->dims->data[3], tensor->dims->data[1],
+ tensor->dims->data[2]};
+
+ return shape;
+}
+
+FeatureView<float>::FeatureView(::tflite::Interpreter &interp, const InputIndex &index)
+{
+ const auto tensor_index = interp.inputs().at(index.asInt());
+ auto tensor_ptr = interp.tensor(tensor_index);
+
+ assert(isFloatTensor(tensor_ptr));
+ assert(isFeatureTensor(tensor_ptr));
+
+ _shape = getFeatureShape(tensor_ptr);
+ _base = interp.typed_tensor<float>(tensor_index);
+}
+
+FeatureView<float>::FeatureView(::tflite::Interpreter &interp, const OutputIndex &index)
+{
+ const auto tensor_index = interp.outputs().at(index.asInt());
+ auto tensor_ptr = interp.tensor(tensor_index);
+
+ assert(isFloatTensor(tensor_ptr));
+ assert(isFeatureTensor(tensor_ptr));
+
+ _shape = getFeatureShape(tensor_ptr);
+ _base = interp.typed_tensor<float>(tensor_index);
+}
+
+float FeatureView<float>::at(uint32_t ch, uint32_t row, uint32_t col) const
+{
+ return *(_base + getElementOffset(ch, row, col));
+}
+
+float &FeatureView<float>::at(uint32_t ch, uint32_t row, uint32_t col)
+{
+ return *(_base + getElementOffset(ch, row, col));
+}
+
+} // namespace tflite
+} // namespace nnfw
diff --git a/runtime/libs/tflite/src/Quantization.cpp b/runtime/libs/tflite/src/Quantization.cpp
new file mode 100644
index 000000000..9c162c342
--- /dev/null
+++ b/runtime/libs/tflite/src/Quantization.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/Quantization.h"
+
+TfLiteQuantizationParams make_default_quantization(void)
+{
+ return TfLiteQuantizationParams{0.0f, 0};
+}
diff --git a/runtime/libs/tflite/src/RandomTestRunner.cpp b/runtime/libs/tflite/src/RandomTestRunner.cpp
new file mode 100644
index 000000000..f7fccbf3b
--- /dev/null
+++ b/runtime/libs/tflite/src/RandomTestRunner.cpp
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/RandomTestRunner.h"
+#include "tflite/Diff.h"
+#include "tflite/TensorLogger.h"
+#include "tflite/ext/nnapi_delegate.h"
+
+#include <misc/tensor/IndexIterator.h>
+#include <misc/tensor/Object.h>
+#include <misc/EnvVar.h>
+#include <misc/fp32.h>
+
+#include <cassert>
+#include <map>
+#include <functional>
+#include <iostream>
+
+namespace nnfw
+{
+namespace tflite
+{
+
+using namespace std::placeholders;
+
+void RandomTestRunner::compile(const nnfw::tflite::Builder &builder)
+{
+ _tfl_interp = builder.build();
+ _nnapi = builder.build();
+
+ _tfl_interp->UseNNAPI(false);
+
+ // Allocate Tensors
+ _tfl_interp->AllocateTensors();
+ _nnapi->AllocateTensors();
+
+ assert(_tfl_interp->inputs() == _nnapi->inputs());
+
+ using ::tflite::Interpreter;
+ using Initializer = std::function<void(int id, Interpreter *, Interpreter *)>;
+
+ std::map<TfLiteType, Initializer> initializers;
+ std::map<TfLiteType, Initializer> reseters;
+
+ // Generate singed 32-bit integer (s32) input
+ initializers[kTfLiteInt32] = [&](int id, Interpreter *tfl_interp, Interpreter *nnapi) {
+ assert(_tfl_interp->tensor(id)->type == kTfLiteInt32);
+ assert(_nnapi->tensor(id)->type == kTfLiteInt32);
+
+ auto tfl_interp_view = nnfw::tflite::TensorView<int32_t>::make(*tfl_interp, id);
+ auto nnapi_view = nnfw::tflite::TensorView<int32_t>::make(*nnapi, id);
+
+ assert(tfl_interp_view.shape() == nnapi_view.shape());
+
+ int32_t value = 0;
+
+ nnfw::misc::tensor::iterate(tfl_interp_view.shape())
+ << [&](const nnfw::misc::tensor::Index &ind) {
+ // TODO Generate random values
+ tfl_interp_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ ++value;
+ };
+ };
+
+ // Generate singed 32-bit integer (s32) input
+ reseters[kTfLiteInt32] = [&](int id, Interpreter *tfl_interp, Interpreter *nnapi) {
+ assert(_tfl_interp->tensor(id)->type == kTfLiteInt32);
+ assert(_nnapi->tensor(id)->type == kTfLiteInt32);
+
+ auto tfl_interp_view = nnfw::tflite::TensorView<int32_t>::make(*tfl_interp, id);
+ auto nnapi_view = nnfw::tflite::TensorView<int32_t>::make(*nnapi, id);
+
+ assert(tfl_interp_view.shape() == nnapi_view.shape());
+
+ int32_t value = 0;
+
+ nnfw::misc::tensor::iterate(tfl_interp_view.shape())
+ << [&](const nnfw::misc::tensor::Index &ind) {
+ // TODO Generate random values
+ tfl_interp_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ };
+ };
+
+ initializers[kTfLiteUInt8] = [&](int id, Interpreter *tfl_interp, Interpreter *nnapi) {
+ assert(_tfl_interp->tensor(id)->type == kTfLiteUInt8);
+ assert(_nnapi->tensor(id)->type == kTfLiteUInt8);
+
+ auto tfl_interp_view = nnfw::tflite::TensorView<uint8_t>::make(*tfl_interp, id);
+ auto nnapi_view = nnfw::tflite::TensorView<uint8_t>::make(*nnapi, id);
+
+ assert(tfl_interp_view.shape() == nnapi_view.shape());
+
+ auto fp = static_cast<uint8_t (nnfw::misc::RandomGenerator::*)(
+ const ::nnfw::misc::tensor::Shape &, const ::nnfw::misc::tensor::Index &)>(
+ &nnfw::misc::RandomGenerator::generate<uint8_t>);
+ const nnfw::misc::tensor::Object<uint8_t> data(tfl_interp_view.shape(),
+ std::bind(fp, _randgen, _1, _2));
+ assert(tfl_interp_view.shape() == data.shape());
+
+ nnfw::misc::tensor::iterate(tfl_interp_view.shape())
+ << [&](const nnfw::misc::tensor::Index &ind) {
+ const auto value = data.at(ind);
+
+ tfl_interp_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ };
+ };
+
+ reseters[kTfLiteUInt8] = [&](int id, Interpreter *tfl_interp, Interpreter *nnapi) {
+ assert(_tfl_interp->tensor(id)->type == kTfLiteUInt8);
+ assert(_nnapi->tensor(id)->type == kTfLiteUInt8);
+
+ auto tfl_interp_view = nnfw::tflite::TensorView<uint8_t>::make(*tfl_interp, id);
+ auto nnapi_view = nnfw::tflite::TensorView<uint8_t>::make(*nnapi, id);
+
+ assert(tfl_interp_view.shape() == nnapi_view.shape());
+
+ auto fp = static_cast<uint8_t (nnfw::misc::RandomGenerator::*)(
+ const ::nnfw::misc::tensor::Shape &, const ::nnfw::misc::tensor::Index &)>(
+ &nnfw::misc::RandomGenerator::generate<uint8_t>);
+ const nnfw::misc::tensor::Object<uint8_t> data(tfl_interp_view.shape(),
+ std::bind(fp, _randgen, _1, _2));
+ assert(tfl_interp_view.shape() == data.shape());
+
+ uint8_t value = 0;
+
+ nnfw::misc::tensor::iterate(tfl_interp_view.shape())
+ << [&](const nnfw::misc::tensor::Index &ind) {
+ tfl_interp_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ };
+ };
+
+ initializers[kTfLiteFloat32] = [&](int id, Interpreter *tfl_interp, Interpreter *nnapi) {
+ assert(_tfl_interp->tensor(id)->type == kTfLiteFloat32);
+ assert(_nnapi->tensor(id)->type == kTfLiteFloat32);
+
+ auto tfl_interp_view = nnfw::tflite::TensorView<float>::make(*tfl_interp, id);
+ auto nnapi_view = nnfw::tflite::TensorView<float>::make(*nnapi, id);
+
+ assert(tfl_interp_view.shape() == nnapi_view.shape());
+
+ auto fp = static_cast<float (nnfw::misc::RandomGenerator::*)(
+ const ::nnfw::misc::tensor::Shape &, const ::nnfw::misc::tensor::Index &)>(
+ &nnfw::misc::RandomGenerator::generate<float>);
+ const nnfw::misc::tensor::Object<float> data(tfl_interp_view.shape(),
+ std::bind(fp, _randgen, _1, _2));
+
+ assert(tfl_interp_view.shape() == data.shape());
+
+ nnfw::misc::tensor::iterate(tfl_interp_view.shape())
+ << [&](const nnfw::misc::tensor::Index &ind) {
+ const auto value = data.at(ind);
+
+ tfl_interp_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ };
+ };
+
+ reseters[kTfLiteFloat32] = [&](int id, Interpreter *tfl_interp, Interpreter *nnapi) {
+ assert(_tfl_interp->tensor(id)->type == kTfLiteFloat32);
+ assert(_nnapi->tensor(id)->type == kTfLiteFloat32);
+
+ auto tfl_interp_view = nnfw::tflite::TensorView<float>::make(*tfl_interp, id);
+ auto nnapi_view = nnfw::tflite::TensorView<float>::make(*nnapi, id);
+
+ assert(tfl_interp_view.shape() == nnapi_view.shape());
+
+ auto fp = static_cast<float (nnfw::misc::RandomGenerator::*)(
+ const ::nnfw::misc::tensor::Shape &, const ::nnfw::misc::tensor::Index &)>(
+ &nnfw::misc::RandomGenerator::generate<float>);
+ const nnfw::misc::tensor::Object<float> data(tfl_interp_view.shape(),
+ std::bind(fp, _randgen, _1, _2));
+
+ assert(tfl_interp_view.shape() == data.shape());
+
+ float value = 0;
+
+ nnfw::misc::tensor::iterate(tfl_interp_view.shape())
+ << [&](const nnfw::misc::tensor::Index &ind) {
+ tfl_interp_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ };
+ };
+
+ initializers[kTfLiteBool] = [&](int id, Interpreter *tfl_interp, Interpreter *nnapi) {
+ assert(_tfl_interp->tensor(id)->type == kTfLiteBool);
+ assert(_nnapi->tensor(id)->type == kTfLiteBool);
+
+ auto tfl_interp_view = nnfw::tflite::TensorView<bool>::make(*tfl_interp, id);
+ auto nnapi_view = nnfw::tflite::TensorView<bool>::make(*nnapi, id);
+
+ assert(tfl_interp_view.shape() == nnapi_view.shape());
+
+ auto fp = static_cast<bool (nnfw::misc::RandomGenerator::*)(
+ const ::nnfw::misc::tensor::Shape &, const ::nnfw::misc::tensor::Index &)>(
+ &nnfw::misc::RandomGenerator::generate<bool>);
+ const nnfw::misc::tensor::Object<bool> data(tfl_interp_view.shape(),
+ std::bind(fp, _randgen, _1, _2));
+
+ assert(tfl_interp_view.shape() == data.shape());
+
+ nnfw::misc::tensor::iterate(tfl_interp_view.shape())
+ << [&](const nnfw::misc::tensor::Index &ind) {
+ const auto value = data.at(ind);
+
+ tfl_interp_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ };
+ };
+
+ reseters[kTfLiteBool] = [&](int id, Interpreter *tfl_interp, Interpreter *nnapi) {
+ assert(_tfl_interp->tensor(id)->type == kTfLiteBool);
+ assert(_nnapi->tensor(id)->type == kTfLiteBool);
+
+ auto tfl_interp_view = nnfw::tflite::TensorView<bool>::make(*tfl_interp, id);
+ auto nnapi_view = nnfw::tflite::TensorView<bool>::make(*nnapi, id);
+
+ assert(tfl_interp_view.shape() == nnapi_view.shape());
+
+ auto fp = static_cast<bool (nnfw::misc::RandomGenerator::*)(
+ const ::nnfw::misc::tensor::Shape &, const ::nnfw::misc::tensor::Index &)>(
+ &nnfw::misc::RandomGenerator::generate<bool>);
+ const nnfw::misc::tensor::Object<bool> data(tfl_interp_view.shape(),
+ std::bind(fp, _randgen, _1, _2));
+
+ assert(tfl_interp_view.shape() == data.shape());
+
+ bool value = false;
+
+ nnfw::misc::tensor::iterate(tfl_interp_view.shape())
+ << [&](const nnfw::misc::tensor::Index &ind) {
+ tfl_interp_view.at(ind) = value;
+ nnapi_view.at(ind) = value;
+ };
+ };
+
+ // Fill IFM with random numbers
+ for (const auto id : _tfl_interp->inputs())
+ {
+ assert(_tfl_interp->tensor(id)->type == _nnapi->tensor(id)->type);
+
+ auto it = initializers.find(_tfl_interp->tensor(id)->type);
+
+ if (it == initializers.end())
+ {
+ throw std::runtime_error{"Not supported input type"};
+ }
+
+ it->second(id, _tfl_interp.get(), _nnapi.get());
+ }
+
+ // Fill OFM with 0
+ for (const auto id : _tfl_interp->outputs())
+ {
+ assert(_tfl_interp->tensor(id)->type == _nnapi->tensor(id)->type);
+
+ auto it = reseters.find(_tfl_interp->tensor(id)->type);
+
+ if (it == reseters.end())
+ {
+ throw std::runtime_error{"Not supported input type"};
+ }
+
+ it->second(id, _tfl_interp.get(), _nnapi.get());
+ }
+}
+
+int RandomTestRunner::run(size_t running_count)
+{
+ std::cout << "[NNAPI TEST] Run T/F Lite Interpreter without NNAPI" << std::endl;
+ _tfl_interp->Invoke();
+
+ nnfw::tflite::NNAPIDelegate d;
+
+ for (size_t i = 1; i <= running_count; ++i)
+ {
+ std::cout << "[NNAPI TEST #" << i << "] Run T/F Lite Interpreter with NNAPI" << std::endl;
+
+ char *env = getenv("UPSTREAM_DELEGATE");
+
+ if (env && !std::string(env).compare("1"))
+ {
+ _nnapi->UseNNAPI(true);
+ _nnapi->Invoke();
+ }
+ else
+ {
+ // WARNING
+ // primary_subgraph: Experimental interface. Return 1st sugbraph
+ // Invoke() will call BuildGraph() internally
+ if (d.Invoke(&_nnapi.get()->primary_subgraph()))
+ {
+ throw std::runtime_error{"Failed to BuildGraph"};
+ }
+ }
+
+ // Compare OFM
+ std::cout << "[NNAPI TEST #" << i << "] Compare the result" << std::endl;
+
+ const auto tolerance = _param.tolerance;
+
+ auto equals = [tolerance](float lhs, float rhs) {
+ // NOTE Hybrid approach
+ // TODO Allow users to set tolerance for absolute_epsilon_equal
+ if (nnfw::misc::fp32::absolute_epsilon_equal(lhs, rhs))
+ {
+ return true;
+ }
+
+ return nnfw::misc::fp32::epsilon_equal(lhs, rhs, tolerance);
+ };
+
+ nnfw::misc::tensor::Comparator comparator(equals);
+ TfLiteInterpMatchApp app(comparator);
+
+ app.verbose() = _param.verbose;
+
+ bool res = app.run(*_tfl_interp, *_nnapi);
+
+ if (!res)
+ {
+ return 255;
+ }
+
+ std::cout << "[NNAPI TEST #" << i << "] PASSED" << std::endl << std::endl;
+
+ if (_param.tensor_logging)
+ nnfw::tflite::TensorLogger::get().save(_param.log_path, *_tfl_interp);
+ }
+
+ return 0;
+}
+
+RandomTestRunner RandomTestRunner::make(uint32_t seed)
+{
+ RandomTestParam param;
+
+ param.verbose = nnfw::misc::EnvVar("VERBOSE").asInt(0);
+ param.tolerance = nnfw::misc::EnvVar("TOLERANCE").asInt(1);
+ param.tensor_logging = nnfw::misc::EnvVar("TENSOR_LOGGING").asBool(false);
+ param.log_path = nnfw::misc::EnvVar("TENSOR_LOGGING").asString("tensor_log.txt");
+
+ return RandomTestRunner{seed, param};
+}
+
+} // namespace tflite
+} // namespace nnfw
diff --git a/runtime/libs/tflite/src/TensorShapeUtils.cpp b/runtime/libs/tflite/src/TensorShapeUtils.cpp
new file mode 100644
index 000000000..689b6151b
--- /dev/null
+++ b/runtime/libs/tflite/src/TensorShapeUtils.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/TensorShapeUtils.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+nnfw::misc::tensor::Shape broadcast(const nnfw::misc::tensor::Shape &lhs_shape,
+ const nnfw::misc::tensor::Shape &rhs_shape)
+{
+ const uint32_t lhs_rank = lhs_shape.rank();
+ const uint32_t rhs_rank = rhs_shape.rank();
+ const uint32_t out_rank = std::max(lhs_rank, rhs_rank);
+ const uint32_t lhs_rank_diff = out_rank - lhs_rank;
+ const uint32_t rhs_rank_diff = out_rank - rhs_rank;
+
+ nnfw::misc::tensor::Shape out_shape(out_rank);
+
+ for (uint32_t axis = 0; axis < out_rank; ++axis)
+ {
+ out_shape.dim(axis) = std::max(axis < lhs_rank_diff ? 1 : lhs_shape.dim(axis - lhs_rank_diff),
+ axis < rhs_rank_diff ? 1 : rhs_shape.dim(axis - rhs_rank_diff));
+ }
+
+ return out_shape;
+}
+
+} // namespace tflite
+} // namespace nnfw
diff --git a/runtime/libs/tflite/src/TensorView.test.cpp b/runtime/libs/tflite/src/TensorView.test.cpp
new file mode 100644
index 000000000..c710b3c33
--- /dev/null
+++ b/runtime/libs/tflite/src/TensorView.test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/TensorView.h"
+
+#include <cassert>
+
+void int_test(void)
+{
+ int value[6] = {1, 2, 3, 4, 5, 6};
+
+ const nnfw::misc::tensor::Shape shape{2, 3};
+ const nnfw::tflite::TensorView<int> view{shape, value};
+
+ assert(view.at(nnfw::misc::tensor::Index{0, 0}) == 1);
+ assert(view.at(nnfw::misc::tensor::Index{0, 1}) == 2);
+ assert(view.at(nnfw::misc::tensor::Index{0, 2}) == 3);
+ assert(view.at(nnfw::misc::tensor::Index{1, 0}) == 4);
+ assert(view.at(nnfw::misc::tensor::Index{1, 1}) == 5);
+ assert(view.at(nnfw::misc::tensor::Index{1, 2}) == 6);
+}
+
+int main(int argc, char **argv)
+{
+ float value[6] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
+
+ const nnfw::misc::tensor::Shape shape{2, 3};
+ const nnfw::tflite::TensorView<float> view{shape, value};
+
+ assert(view.at(nnfw::misc::tensor::Index{0, 0}) == 1.0f);
+ assert(view.at(nnfw::misc::tensor::Index{0, 1}) == 2.0f);
+ assert(view.at(nnfw::misc::tensor::Index{0, 2}) == 3.0f);
+ assert(view.at(nnfw::misc::tensor::Index{1, 0}) == 4.0f);
+ assert(view.at(nnfw::misc::tensor::Index{1, 1}) == 5.0f);
+ assert(view.at(nnfw::misc::tensor::Index{1, 2}) == 6.0f);
+
+ int_test();
+
+ return 0;
+}
diff --git a/runtime/libs/tflite/src/interp/FlatBufferBuilder.cpp b/runtime/libs/tflite/src/interp/FlatBufferBuilder.cpp
new file mode 100644
index 000000000..f54e67202
--- /dev/null
+++ b/runtime/libs/tflite/src/interp/FlatBufferBuilder.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/interp/FlatBufferBuilder.h"
+
+#include "tflite/ext/kernels/register.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+std::unique_ptr<::tflite::Interpreter> FlatBufferBuilder::build(void) const
+{
+ std::unique_ptr<::tflite::Interpreter> interpreter;
+
+ nnfw::tflite::BuiltinOpResolver resolver;
+
+ ::tflite::InterpreterBuilder builder(_model, resolver);
+
+ builder(&interpreter);
+
+ return interpreter;
+}
+
+} // namespace tflite
+} // namespace nnfw
diff --git a/runtime/libs/tflite/src/interp/FunctionBuilder.cpp b/runtime/libs/tflite/src/interp/FunctionBuilder.cpp
new file mode 100644
index 000000000..599a4f393
--- /dev/null
+++ b/runtime/libs/tflite/src/interp/FunctionBuilder.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite/interp/FunctionBuilder.h"
+
+namespace nnfw
+{
+namespace tflite
+{
+
+std::unique_ptr<::tflite::Interpreter> FunctionBuilder::build(void) const
+{
+ auto res = std::unique_ptr<::tflite::Interpreter>{new ::tflite::Interpreter};
+
+ _fn(*res);
+
+ return res;
+}
+
+} // namespace tflite
+} // namespace nnfw
diff --git a/runtime/nnapi-header/CMakeLists.txt b/runtime/nnapi-header/CMakeLists.txt
new file mode 100644
index 000000000..fe9aebe5d
--- /dev/null
+++ b/runtime/nnapi-header/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(nnfw-nnapi-header INTERFACE)
+target_include_directories(nnfw-nnapi-header INTERFACE include)
+
+set(NNFW_NNAPI_HEADERS ${CMAKE_CURRENT_LIST_DIR}/include/NeuralNetworks.h
+ ${CMAKE_CURRENT_LIST_DIR}/include/NeuralNetworksEx.h
+ ${CMAKE_CURRENT_LIST_DIR}/include/NeuralNetworksExtensions.h)
+
+install(FILES ${NNFW_NNAPI_HEADERS} DESTINATION include/nnfw)
diff --git a/runtime/nnapi-header/include/NeuralNetworks.h b/runtime/nnapi-header/include/NeuralNetworks.h
new file mode 100644
index 000000000..0c54d7582
--- /dev/null
+++ b/runtime/nnapi-header/include/NeuralNetworks.h
@@ -0,0 +1,8166 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NeuralNetworks
+ * @{
+ */
+
+/**
+ * @file NeuralNetworks.h
+ */
+
+#ifndef ANDROID_FRAMEWORKS_ML_NN_RUNTIME_NEURAL_NETWORKS_H
+#define ANDROID_FRAMEWORKS_ML_NN_RUNTIME_NEURAL_NETWORKS_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit).
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+// For compatibility with android, check __ANDROID__ is defined
+#ifndef __ANDROID__
+#define __ANDROID_API__ 30
+#define __INTRODUCED_IN(api_level)
+typedef struct AHardwareBuffer AHardwareBuffer;
+#else
+#include <android/hardware_buffer.h>
+#endif // __ANDROID__
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Operand types.
+ *
+ * The type of an operand in a model.
+ *
+ * Types prefaced with ANEURALNETWORKS_TENSOR_* must be used for tensor data (i.e., tensors
+ * with at least one dimension). Types not prefaced by ANEURALNETWORKS_TENSOR_* represent
+ * scalar values and must have no dimensions.
+ *
+ * Although we define many types, most operators accept just a few
+ * types. Most used are {@link ANEURALNETWORKS_TENSOR_FLOAT32},
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * and {@link ANEURALNETWORKS_INT32}.
+ *
+ * Available since API level 27.
+ */
+typedef enum {
+ /** A 32 bit floating point scalar value. */
+ ANEURALNETWORKS_FLOAT32 = 0,
+ /** A signed 32 bit integer scalar value. */
+ ANEURALNETWORKS_INT32 = 1,
+ /** An unsigned 32 bit integer scalar value. */
+ ANEURALNETWORKS_UINT32 = 2,
+ /** A tensor of 32 bit floating point values. */
+ ANEURALNETWORKS_TENSOR_FLOAT32 = 3,
+ /** A tensor of 32 bit integer values. */
+ ANEURALNETWORKS_TENSOR_INT32 = 4,
+ /**
+ * A tensor of 8 bit unsigned integers that represent real numbers.
+ *
+ * Attached to this tensor are two numbers that can be used to convert the
+ * 8 bit integer to the real value and vice versa. These two numbers are:
+ * - scale: a 32 bit floating point value greater than zero.
+ * - zeroPoint: a 32 bit integer, in range [0, 255].
+ *
+ * The formula is:
+ * real_value = (integer_value - zeroPoint) * scale.
+ */
+ ANEURALNETWORKS_TENSOR_QUANT8_ASYMM = 5,
+ /**
+ * An 8 bit boolean scalar value.
+ *
+ * Values of this operand type are either true or false. A zero value
+ * represents false; any other value represents true.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_BOOL = 6,
+ /**
+ * A tensor of 16 bit signed integers that represent real numbers.
+ *
+ * Attached to this tensor is a number representing real value scale that is
+ * used to convert the 16 bit number to a real value in the following way:
+ * realValue = integerValue * scale.
+ *
+ * scale is a 32 bit floating point with value greater than zero.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TENSOR_QUANT16_SYMM = 7,
+ /**
+ * A tensor of IEEE 754 16 bit floating point values.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TENSOR_FLOAT16 = 8,
+ /**
+ * A tensor of 8 bit boolean values.
+ *
+ * Values of this operand type are either true or false. A zero value
+ * represents false; any other value represents true.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TENSOR_BOOL8 = 9,
+ /**
+ * An IEEE 754 16 bit floating point scalar value.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_FLOAT16 = 10,
+ /**
+ * A tensor of 8 bit signed integers that represent real numbers.
+ *
+ * This tensor is associated with additional fields that can
+ * be used to convert the 8 bit signed integer to the real value and vice versa.
+ * These fields are:
+ * - channelDim: a 32 bit unsigned integer indicating channel dimension.
+ * - scales: an array of positive 32 bit floating point values.
+ * The size of the scales array must be equal to dimensions[channelDim].
+ *
+ * {@link ANeuralNetworksModel_setOperandSymmPerChannelQuantParams} must be used
+ * to set the parameters for an Operand of this type.
+ *
+ * The channel dimension of this tensor must not be unknown (dimensions[channelDim] != 0).
+ *
+ * The formula is:
+ * realValue[..., C, ...] =
+ * integerValue[..., C, ...] * scales[C]
+ * where C is an index in the Channel dimension.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL = 11,
+ /**
+ * A tensor of 16 bit unsigned integers that represent real numbers.
+ *
+ * Attached to this tensor are two numbers that can be used to convert the
+ * 16 bit integer to the real value and vice versa. These two numbers are:
+ * - scale: a 32 bit floating point value greater than zero.
+ * - zeroPoint: a 32 bit integer, in range [0, 65535].
+ *
+ * The formula is:
+ * real_value = (integer_value - zeroPoint) * scale.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TENSOR_QUANT16_ASYMM = 12,
+ /**
+ * A tensor of 8 bit signed integers that represent real numbers.
+ *
+ * Attached to this tensor is a number representing real value scale that is
+ * used to convert the 8 bit number to a real value in the following way:
+ * realValue = integerValue * scale.
+ *
+ * scale is a 32 bit floating point with value greater than zero.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TENSOR_QUANT8_SYMM = 13,
+ /**
+ * A tensor of 8 bit signed integers that represent real numbers.
+ *
+ * Attached to this tensor are two numbers that can be used to convert the
+ * 8 bit integer to the real value and vice versa. These two numbers are:
+ * - scale: a 32 bit floating point value greater than zero.
+ * - zeroPoint: a 32 bit integer, in range [-128, 127].
+ *
+ * The formula is:
+ * real_value = (integer_value - zeroPoint) * scale.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED = 14,
+
+ /**
+ * A reference to a model.
+ *
+ * {@link ANeuralNetworksModel_setOperandValueFromModel} must be used to set
+ * the value for an Operand of this type.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_MODEL = 15,
+} OperandCode;
+
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ *
+ * Available since API level 27.
+ */
+typedef enum {
+ // Operations below are available since API level 27.
+
+ /**
+ * Adds two tensors, element-wise.
+ *
+ * Takes two input tensors of identical {@link OperandCode} and compatible
+ * dimensions. The output is the sum of both input tensors, optionally
+ * modified by an activation function.
+ *
+ * Two dimensions are compatible when:
+ * 1. they are equal, or
+ * 2. one of them is 1
+ *
+ * The size of the output is the maximum size along each dimension of the
+ * input operands. It starts with the trailing dimensions, and works its
+ * way forward.
+ *
+ * Example:
+ *
+ * input1.dimension = {4, 1, 2}
+ * input2.dimension = {5, 4, 3, 1}
+ * output.dimension = {5, 4, 3, 2}
+ *
+ * Since API level 29, generic zero-sized input tensor is supported. Zero
+ * dimension is only compatible with 0 or 1. The size of the output
+ * dimension is zero if either of corresponding input dimension is zero.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode}, and compatible dimensions
+ * as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scales and zeroPoint can be different from input0 scale and zeroPoint.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * For a {@link ANEURALNETWORKS_TENSOR_INT32} tensor,
+ * the {@link FuseCode} must be "NONE".
+ *
+ * Outputs:
+ * * 0: The sum, a tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_ADD = 0,
+
+ /**
+ * Performs a 2-D average pooling operation.
+ *
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
+ *
+ * output[b, i, j, channel] =
+ * sum_{di, dj}(
+ * input[b, strides[1] * i + di, strides[2] * j + dj, channel]
+ * ) / sum(1)
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * width.
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * height.
+ * * 9: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 10: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * {@link PaddingCode} values.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * width.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * height.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 7: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_AVERAGE_POOL_2D = 1,
+
+ /**
+ * Concatenates the input tensors along the given dimension.
+ *
+ * The input tensors must have identical {@link OperandCode} and the same
+ * dimensions except the dimension along the concatenation axis.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * (full support since API level 29, see the input section)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0 ~ n-1: The list of n input tensors, of shape
+ * [D0, D1, ..., Daxis(i), ..., Dm].
+ * Before API level 29, all input tensors of
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * must have the same scale and zeroPoint as the output tensor.
+ * Input tensors of
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ * are allowed to have different scale and zeroPoint.
+ * Since API level 29, zero-sized tensors are supported.
+ * * n: An {@link ANEURALNETWORKS_INT32} scalar, specifying the
+ * concatenation axis.
+ *
+ * Outputs:
+ * * 0: The output, a tensor of the same {@link OperandCode} as the input
+ * tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
+ * Since API level 29, for a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor,
+ * the scale and zeroPoint values can be different from
+ * input tensors. Before API level 29 they have to be the same as for the input tensors.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_CONCATENATION = 2,
+
+ /**
+ * Performs a 2-D convolution operation.
+ *
+ * The CONV_2D op sweeps a 2-D filter that can mix channels together over a
+ * batch of images, applying the filter to each window of each image of the
+ * appropriate size.
+ *
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
+ *
+ * output[b, i, j, channel] =
+ * sum_{di, dj, k} (
+ * input[b, strides[1] * i + di, strides[2] * j + dj, k] *
+ * filter[channel, di, dj, k]
+ * ) + bias[channel]
+ *
+ * Supported tensor {@link OperandCode} configurations:
+ * * 32 bit floating point:
+ * * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} for input, filter, output, and bias.
+ *
+ * * Quantized:
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} for input, filter, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * Available since API level 29:
+ * * 16 bit floating point:
+ * * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} for input, filter, output, and bias.
+ *
+ * * Quantized with symmetric per channel quantization for the filter:
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} for input, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
+ * Available since API level 30:
+ * * Quantized signed (since API level 30):
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized signed with filter symmetric per channel quantization (since API level 30):
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: A 4-D tensor, of shape
+ * [depth_out, filter_height, filter_width, depth_in], specifying the
+ * filter.
+ * For tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}
+ * the channel dimension (ANeuralNetworksSymmPerChannelQuantParams::channelDim)
+ * must be set to 0.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint
+ * of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 9: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 10: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ * * 11: An optional {@link ANEURALNETWORKS_INT32} scalar, specifying the dilation
+ * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+ * cells between each filter element on width dimension. If this input is set,
+ * input 12 (dilation factor for height) must be specified as well.
+ * Available since API level 29.
+ * * 12: An optional {@link ANEURALNETWORKS_INT32} scalar, specifying the dilation
+ * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+ * cells between each filter element on height dimension. If this input is set,
+ * input 11 (dilation factor for width) must be specified as well.
+ * Available since API level 29.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: A 4-D tensor, of shape
+ * [depth_out, filter_height, filter_width, depth_in], specifying the
+ * filter.
+ * For tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}
+ * the channel dimension (ANeuralNetworksSymmPerChannelQuantParams::channelDim)
+ * must be set to 0.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same
+ * type.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint
+ * of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * {@link PaddingCode} values.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 7: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ * * 8: An optional {@link ANEURALNETWORKS_INT32} scalar, specifying the dilation
+ * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+ * cells between each filter element on width dimension. If this input is set,
+ * input 9 (dilation factor for height) must be specified as well.
+ * Available since API level 29.
+ * * 9: An optional {@link ANEURALNETWORKS_INT32} scalar, specifying the dilation
+ * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+ * cells between each filter element on height dimension. If this input is set,
+ * input 8 (dilation factor for width) must be specified as well.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth_out].
+ * Before API level 29, for output tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * the following condition must be satisfied: output_scale > input_scale * filter_scale
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_CONV_2D = 3,
+
+ /**
+ * Performs a depthwise 2-D convolution operation.
+ *
+ * Given an input tensor of shape [batches, height, width, depth_in] and a
+ * filter tensor of shape [1, filter_height, filter_width, depth_out]
+ * containing depth_out convolutional filters of depth 1, DEPTHWISE_CONV
+ * applies a different filter to each input channel (expanding from 1
+ * channel to channel_multiplier channels for each), then concatenates the
+ * results together.
+ *
+ * The output has depth_out = depth_in * depth_multiplier channels.
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
+ *
+ * output[b, i, j, k * channel_multiplier + q] =
+ * sum_{di, dj} (
+ * input[b, strides[1] * i + di, strides[2] * j + dj, k] *
+ * filter[1, di, dj, k * channel_multiplier + q]
+ * ) + bias[k * channel_multiplier + q]
+ *
+ * Supported tensor {@link OperandCode} configurations:
+ * * 32 bit floating point:
+ * * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} for input, filter, output, and bias.
+ *
+ * * Quantized:
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} for input, filter, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * Available since API level 29:
+ * * 16 bit floating point:
+ * * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} for input, filter, output, and bias.
+ *
+ * * Quantized with symmetric per channel quantization for the filter:
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} for input, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
+ * Available since API level 30:
+ * * Quantized signed (since API level 30):
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized signed with filter symmetric per channel quantization (since API level 30):
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
+ * specifying the filter.
+ * For tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}
+ * the channel dimension (ANeuralNetworksSymmPerChannelQuantParams::channelDim)
+ * must be set to 3.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint
+ * of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 9: An {@link ANEURALNETWORKS_INT32} scalar, specifying the depthwise
+ * multiplier.
+ * * 10: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 11: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ * * 12: An optional {@link ANEURALNETWORKS_INT32} scalar, specifying the dilation
+ * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+ * cells between each filter element on width dimension. If this input is set,
+ * input 13 (dilation factor for height) must be specified as well.
+ * Available since API level 29.
+ * * 13: An optional {@link ANEURALNETWORKS_INT32} scalar, specifying the dilation
+ * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+ * cells between each filter element on height dimension. If this input is set,
+ * input 12 (dilation factor for width) must be specified as well.
+ * Available since API level 29.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
+ * specifying the filter.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same type.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint
+ * of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * {@link PaddingCode} values.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the depthwise
+ * multiplier.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 8: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ * * 9: An optional {@link ANEURALNETWORKS_INT32} scalar, specifying the dilation
+ * factor for width. Defaults to 1. If set to k > 1, there will be k-1 skipped
+ * cells between each filter element on width dimension. If this input is set,
+ * input 10 (dilation factor for height) must be specified as well.
+ * Available since API level 29.
+ * * 10: An optional {@link ANEURALNETWORKS_INT32} scalar, specifying the dilation
+ * factor for height. Defaults to 1. If set to k > 1, there will be k-1 skipped
+ * cells between each filter element on height dimension. If this input is set,
+ * input 9 (dilation factor for width) must be specified as well.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth_out]. Before API level 29, for
+ * output tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * the following condition must be satisfied:
+ * output_scale > input_scale * filter_scale
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_DEPTHWISE_CONV_2D = 4,
+
+ /**
+ * Rearranges data from depth into blocks of spatial data.
+ *
+ * More specifically, this op outputs a copy of the input tensor where
+ * values from the depth dimension are moved in spatial blocks to the height
+ * and width dimensions. The value block_size indicates the input block size
+ * and how the data is moved.
+ *
+ * Chunks of data of size block_size * block_size from depth are rearranged
+ * into non-overlapping blocks of size block_size x block_size.
+ *
+ * The width of the output tensor is input_depth * block_size, whereas the
+ * height is input_height * block_size. The depth of the input tensor must
+ * be divisible by block_size * block_size
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Inputs:
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the block_size.
+ * block_size must be >=1 and block_size * block_size must be a divisor
+ * of the input depth.
+ * * 2: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape [batch, height*block_size,
+ * width*block_size, depth/(block_size*block_size)].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_DEPTH_TO_SPACE = 5,
+
+ /**
+ * Dequantizes the input tensor.
+ *
+ * The formula is:
+ *
+ * output = (input - zeroPoint) * scale.
+ *
+ * Supported input tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported output tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}.
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * Since API level 29, this tensor may be zero-sized.
+ *
+ * Outputs:
+ * * 0: A tensor with the same shape as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_DEQUANTIZE = 6,
+
+ /**
+ * Looks up sub-tensors in the input tensor.
+ *
+ * This operator takes for input a tensor of values (Values) and
+ * a one-dimensional tensor of selection indices (Lookups).
+ * The output tensor is the concatenation of sub-tensors of Values as
+ * selected by Lookups.
+ *
+ * Think of Values as being sliced along its first dimension:
+ * The entries in Lookups select which slices are concatenated together
+ * to create the output tensor.
+ *
+ * For example, if Values has shape of [40, 200, 300] and
+ * Lookups has shape of [3], all three values found in Lookups are
+ * expected to be between 0 and 39. The resulting tensor must
+ * have shape of [3, 200, 300].
+ *
+ * If a value in Lookups is out of bounds, the operation must fail
+ * and an error must be reported.
+ *
+ * Supported value tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 30)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported value tensor rank: from 2
+ *
+ * Inputs:
+ * * 0: Lookups. A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}.
+ * The values are indices into the first dimension of Values.
+ * * 1: Values. An n-D tensor, where n >= 2, from which sub-tensors are
+ * extracted.
+ *
+ * Output:
+ * * 0: A n-D tensor with the same rank and shape as the Values
+ * tensor, except for the first dimension which has the same size
+ * as Lookups' only dimension.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input1.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_EMBEDDING_LOOKUP = 7,
+
+ /**
+ * Computes element-wise floor() on the input tensor.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor, of the same {@link OperandCode} and dimensions as
+ * the input tensor.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_FLOOR = 8,
+
+ /**
+ * Denotes a fully (densely) connected layer, which connects all elements
+ * in the input tensor with each element in the output tensor.
+ *
+ * This layer implements the operation:
+ *
+ * outputs = activation(inputs * weights’ + bias)
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4.
+ *
+ * Inputs:
+ * * 0: A tensor of at least rank 2, specifying the input. If rank is
+ * greater than 2, then it gets flattened to a 2-D Tensor. The
+ * (flattened) 2-D Tensor is reshaped (if necessary) to
+ * [batch_size, input_size], where "input_size" corresponds to the
+ * number of inputs to the layer, matching the second dimension of
+ * weights, and "batch_size" is calculated by dividing the number of
+ * elements by "input_size".
+ * Since API level 29, zero batch_size is supported for this tensor.
+ * * 1: A 2-D tensor, specifying the weights, of shape
+ * [num_units, input_size], where "num_units" corresponds to the number
+ * of output nodes.
+ * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input
+ * tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32}, the bias should
+ * also be of {@link ANEURALNETWORKS_TENSOR_FLOAT32}.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Outputs:
+ * * 0: The output tensor, of shape [batch_size, num_units]. Before API level 29, for
+ * output tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, the following
+ * condition must be satisfied: output_scale > input_scale * filter_scale.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_FULLY_CONNECTED = 9,
+
+ /**
+ * Looks up sub-tensors in the input tensor using a key-value map.
+ *
+ * This operator takes for input a tensor of values (Values),
+ * a one-dimensional tensor of selection values (Lookups) and
+ * a one-dimensional tensor that maps these values to Values
+ * indexes. The output tensor is the concatenation of sub-tensors of
+ * Values as selected by Lookups via Keys.
+ *
+ * Think of Values as being sliced along its outer-most dimension.
+ * The output is a concatenation of selected slices, with one slice
+ * for each entry of Lookups. The slice selected is the one at the
+ * same index as the Maps entry that matches the value in Lookups.
+ *
+ * For a hit, the corresponding sub-tensor of Values is included
+ * in the Output tensor. For a miss, the corresponding sub-tensor in
+ * Output must have zero values.
+ *
+ * For example, if Values has shape of [40, 200, 300],
+ * Keys should have a shape of [40]. If Lookups tensor has shape
+ * of [3], three slices are being concatenated, so the resulting tensor
+ * must have the shape of [3, 200, 300]. If the first entry in Lookups
+ * has the value 123456, that value must be located in Keys tensor.
+ * If the sixth entry of Keys contains 123456, the sixth slice of Values
+ * must be selected. If no entry in Keys has 123456, a slice of zeroes
+ * must be concatenated.
+ *
+ * Supported value tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ *
+ * Supported value tensor rank: from 2
+ *
+ * Inputs:
+ * * 0: Lookups. A 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor with
+ * shape [ k ].
+ * * 1: Keys. A 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor with shape
+ * [ n ]; Keys and Values pair represent a map, i.e., the ith element
+ * in Keys (Keys[i]) is the key to select the ith sub-tensor in Values
+ * (Values[i]), where 0 <= i <= n-1. Keys tensor *MUST* be sorted in
+ * ascending order.
+ * * 2: Values. A tensor with shape of [ n, … ]; i.e., the first dimension
+ * must be n.
+ *
+ * Outputs:
+ * * 0: Output. A tensor with shape [ k …].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor,
+ * the scale and zeroPoint must be the same as input2.
+ * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup
+ * hits (True) or not (False).
+ * Stored as {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} with offset 0
+ * and scale 1.0f.
+ * A non-zero byte represents True, a hit. A zero indicates otherwise.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_HASHTABLE_LOOKUP = 10,
+
+ /**
+ * Applies L2 normalization along the axis dimension.
+ *
+ * The values in the output tensor are computed as:
+ *
+ * output[batch, row, col, channel] =
+ * input[batch, row, col, channel] /
+ * sqrt(sum_{c} pow(input[batch, row, col, c], 2))
+ *
+ * By default the axis dimension is the last dimension of the input tensor.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ * Tensors with rank less than 4 are only supported since API level 29.
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the tensor to be normalized.
+ * * 1: An optional {@link ANEURALNETWORKS_INT32} scalar, default to -1,
+ * specifying the dimension normalization would be performed on.
+ * Negative index is used to specify axis from the end (e.g. -1 for
+ * the last axis). Must be in the range [-n, n).
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} and same shape as input0.
+ * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * the scale must be 1.f / 128 and the zeroPoint must be 128.
+ * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the scale must be 1.f / 128 and the zeroPoint must be 0.
+ *
+ * NOTE: Before API level 30, if the elements along an axis are all zeros,
+ * the result is undefined. Since API level 30, if the elements along an axis
+ * are all zeros, the result is logical zero.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_L2_NORMALIZATION = 11,
+
+ /**
+ * Performs an 2-D L2 pooling operation.
+ *
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
+ *
+ * output[b, i, j, c] =
+ * sqrt(sum_{di, dj} pow(input[b, strides[1] * i + di, strides[2] * j + dj, c], 2) /
+ * sum(1))
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * width.
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * height.
+ * * 9: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 10: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * {@link PaddingCode} values.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * width.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * height.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 7: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth].
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_L2_POOL_2D = 12,
+
+ /**
+ * Applies Local Response Normalization along the depth dimension.
+ *
+ * The 4-D input tensor is treated as a 3-D array of 1-D vectors (along the
+ * last dimension), and each vector is normalized independently. Within a
+ * given vector, each component is divided by the weighted, squared sum of
+ * inputs within depth_radius.
+ *
+ * The output is calculated using this formula:
+ *
+ * sqr_sum[a, b, c, d] = sum(
+ * pow(input[a, b, c, d - depth_radius : d + depth_radius + 1], 2))
+ * output = input / pow((bias + alpha * sqr_sum), beta)
+ *
+ * For input tensor with rank less than 4, independently normalizes each
+ * 1-D slice along specified dimension.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ * Tensors with rank less than 4 are only supported since API level 29.
+ *
+ * Inputs:
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the radius of
+ * the normalization window.
+ * * 2: A scalar, specifying the bias, must not be zero.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the bias
+ * value must be of {@link ANEURALNETWORKS_FLOAT16}.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32}, the bias
+ * value must be of {@link ANEURALNETWORKS_FLOAT32}.
+ * * 3: A scalar, specifying the scale factor, alpha.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the
+ * alpha value must be of {@link ANEURALNETWORKS_FLOAT16}.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32}, the
+ * alpha value must be of {@link ANEURALNETWORKS_FLOAT32}.
+ * * 4: A scalar, specifying the exponent, beta.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the beta
+ * value must be of {@link ANEURALNETWORKS_FLOAT16}.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32}, the beta
+ * value must be of {@link ANEURALNETWORKS_FLOAT32}.
+ * * 5: An optional {@link ANEURALNETWORKS_INT32} scalar, default to -1,
+ * specifying the dimension normalization would be performed on.
+ * Negative index is used to specify axis from the end (e.g. -1 for
+ * the last axis). Must be in the range [-n, n).
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION = 13,
+
+ /**
+ * Computes sigmoid activation on the input tensor element-wise.
+ *
+ * The output is calculated using this formula:
+ *
+ * output = 1 / (1 + exp(-input))
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4.
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input.
+ * Since API level 29, this tensor may be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * the scale must be 1.f / 256 and the zeroPoint must be 0.
+ * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the scale must be 1.f / 256 and the zeroPoint must be -128.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_LOGISTIC = 14,
+
+ /**
+ * Projects an input to a bit vector via locality senstive hashing.
+ *
+ * Supported input tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ *
+ * Supported input tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: Hash functions. Dim.size == 2, DataType: Float.
+ * Tensor[0].Dim[0]: Number of hash functions.
+ * Tensor[0].Dim[1]: Number of projected output bits generated by each
+ * hash function.
+ * If the projection type is Sparse:
+ * Tensor[0].Dim[1] + ceil(log2(Tensor[0].Dim[0])) <= 32
+ *
+ * * 1: Input. Dim.size >= 1, no restriction on DataType.
+ * * 2: Weight. Optional. Dim.size == 1, DataType: Float.
+ * If not set, each input element is considered to have the same weight
+ * of 1.0.
+ * Tensor[1].Dim[0] == Tensor[2].Dim[0]
+ * * 3: Type:
+ * Sparse:
+ * Value LSHProjectionType_SPARSE(=3) (since API level 29).
+ * Computed bit vector is considered to be sparse.
+ * Each output element is an int32 made up of multiple bits
+ * computed from hash functions.
+ *
+ * NOTE: To avoid collisions across hash functions, an offset value
+ * of k * (1 << Tensor[0].Dim[1]) will be added to each signature,
+ * where k is the index of the hash function.
+ *
+ * Value LSHProjectionType_SPARSE_DEPRECATED(=1).
+ * Legacy behavior that does not include the offset value.
+ *
+ * Dense:
+ * Value LSHProjectionType_DENSE(=2).
+ * Computed bit vector is considered to be dense. Each output
+ * element represents a bit and can take the value of either
+ * 0 or 1.
+ *
+ * Outputs:
+ * * 0: If the projection type is Sparse:
+ * Output.Dim == { Tensor[0].Dim[0] }
+ * A tensor of int32 that represents hash signatures.
+ *
+ * If the projection type is Dense:
+ * Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] }
+ * A flattened tensor that represents projected bit vectors.
+ *
+ * Available since API level 27.
+ * The offset value for sparse projections was added in API level 29.
+ */
+ ANEURALNETWORKS_LSH_PROJECTION = 15,
+
+ /**
+ * Performs a single time step in a Long Short-Term Memory (LSTM) layer
+ *
+ * The LSTM operation is described by the following equations.
+ *
+ * \f{eqnarray*}{
+ * i_t =& \sigma(W_{xi}x_t+W_{hi}h_{t-1}+W_{ci}C_{t-1}+b_i) & \\
+ * f_t =& \sigma(W_{xf}x_t+W_{hf}h_{t-1}+W_{cf}C_{t-1}+b_f) & \\
+ * C_t =& clip(f_t \odot C_{t-1} + i_t \odot
+ * g(W_{xc}x_t+W_{hc}h_{t-1}+b_c),\ t_{cell}) & \\
+ * o_t =& \sigma(W_{xo}x_t+W_{ho}h_{t-1}+W_{co}C_t+b_o) & \\
+ * & & \\
+ * & clip(W_{proj}(o_t \odot g(C_t))+b_{proj},\ t_{proj})
+ * & if\ there\ is\ a\ projection; \\
+ * h_t =& & \\
+ * & o_t \odot g(C_t) & otherwise. \\
+ * \f}
+ * Where:
+ * * \f$x_t\f$ is the input,
+ * * \f$i_t\f$ is the input gate,
+ * * \f$f_t\f$ is the forget gate,
+ * * \f$C_t\f$ is the cell state,
+ * * \f$o_t\f$ is the output,
+ * * \f$h_t\f$ is the output state,
+ * * \f$\sigma\f$ is the logistic sigmoid function,
+ * * \f$g\f$ is the cell input and cell output activation function, usually
+ * \f$tahn\f$,
+ * * \f$W_{xi}\f$ is the input-to-input weight matrix,
+ * * \f$W_{hi}\f$ is the recurrent to input weight matrix,
+ * * \f$W_{ci}\f$ is the cell-to-input weight matrix,
+ * * \f$b_i\f$ is the input gate bias,
+ * * \f$W_{xf}\f$ is the input-to-forget weight matrix,
+ * * \f$W_{hf}\f$ is the recurrent-to-forget weight matrix,
+ * * \f$W_{cf}\f$ is the cell-to-forget weight matrix,
+ * * \f$b_f\f$ is the forget gate bias,
+ * * \f$W_{xc}\f$ is the input-to-cell weight matrix,
+ * * \f$W_{hc}\f$ is the recurrent-to-cell weight matrix,
+ * * \f$b_c\f$ is the cell bias,
+ * * \f$W_{xo}\f$ is the input-to-output weight matrix,
+ * * \f$W_{ho}\f$ is the recurrent-to-output weight matrix,
+ * * \f$W_{co}\f$ is the cell-to-output weight matrix,
+ * * \f$b_o\f$ is the output gate bias,
+ * * \f$W_{proj}\f$ is the projection weight matrix,
+ * * \f$b_{proj}\f$ is the projection bias,
+ * * \f$t_{cell}\f$ is the threshold for clipping the cell state, and
+ * * \f$t_{proj}\f$ is the threshold for clipping the projected output.
+ * * \f$\odot\f$ is the
+ * <a href="https://en.wikipedia.org/wiki/Hadamard_product_(matrices)">
+ * Hadamard product</a> that takes two matrices and produces another
+ * matrix, each element of which is the product of the corresponding
+ * elements of the input matrices.
+ *
+ * Since API level 29 LSTM supports layer normalization.
+ * In case layer normalization is used, the inputs to internal activation
+ * functions (sigmoid and \f$g\f$) are normalized, rescaled and recentered
+ * following an approach from section 3.1 from
+ * https://arxiv.org/pdf/1607.06450.pdf
+ *
+ * The operation has the following independently optional inputs:
+ * * The cell-to-input weights (\f$W_{ci}\f$), cell-to-forget weights
+ * (\f$W_{cf}\f$) and cell-to-output weights (\f$W_{co}\f$) either all
+ * have values or neither of them have values (i.e., all set to null). If
+ * they have values, the peephole optimization is used.
+ * * The input-to-input weights (\f$W_{xi}\f$), recurrent-to-input weights
+ * (\f$W_{hi}\f$) and input gate bias (\f$b_i\f$) either all have values,
+ * or none of them have values. If they have no values, coupling of input
+ * and forget gates (CIFG) is used, in which case the input gate
+ * (\f$i_t\f$) is calculated using the following equation instead.
+ * \f{eqnarray*}{
+ * i_t = 1 - f_t
+ * \f}
+ * In case peephole optimization is used and CIFG is not used
+ * cell-to-input (\f$W_{ci}\f$) weights must be present. Otherwise, the
+ * cell-to-input weights must have no value.
+ * * The projection weights (\f$W_{proj}\f$) is required only for the
+ * recurrent projection layer, and should otherwise have no value.
+ * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a
+ * value if the recurrent projection layer exists, and should otherwise
+ * have no value.
+ * * (API level 29 or later) The four layer normalization weights either all have
+ * values or none of them have values. Additionally, if CIFG is used,
+ * input layer normalization weights tensor is omitted and the other layer
+ * normalization weights either all have values or none of them have
+ * values. Layer normalization is used when the values of all the layer
+ * normalization weights are present.
+ *
+ * References:
+ *
+ * The default non-peephole non-CIFG implementation is based on:
+ * http://www.bioinf.jku.at/publications/older/2604.pdf
+ * S. Hochreiter and J. Schmidhuber. "Long Short-Term Memory". Neural
+ * Computation, 9(8):1735-1780, 1997.
+ *
+ * The peephole implementation and projection layer is based on:
+ * https://research.google.com/pubs/archive/43905.pdf
+ * Hasim Sak, Andrew Senior, and Francoise Beaufays. "Long short-term memory
+ * recurrent neural network architectures for large scale acoustic
+ * modeling." INTERSPEECH, 2014.
+ * (However, the concept of peephole optimization was introduced in work
+ * prior to this paper.)
+ *
+ * The coupling of input and forget gate (CIFG) is based on:
+ * http://arxiv.org/pdf/1503.04069.pdf
+ * Greff et al. "LSTM: A Search Space Odyssey"
+ *
+ * The layer normalization is based on:
+ * https://arxiv.org/pdf/1607.06450.pdf
+ * Jimmy Ba et al. "Layer Normalization"
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * All input and output tensors must be of the same type.
+ *
+ * Inputs:
+ * * 0: The input (\f$x_t\f$).
+ * A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+ * corresponds to the batching dimension, and “input_size” is the size
+ * of the input.
+ * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
+ * A 2-D tensor of shape [num_units, input_size], where “num_units”
+ * corresponds to the number of cell units.
+ * * 2: The input-to-forget weights (\f$W_{xf}\f$).
+ * A 2-D tensor of shape [num_units, input_size].
+ * * 3: The input-to-cell weights (\f$W_{xc}\f$).
+ * A 2-D tensor of shape [num_units, input_size].
+ * * 4: The input-to-output weights (\f$W_{xo}\f$).
+ * A 2-D tensor of shape [num_units, input_size].
+ * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional.
+ * A 2-D tensor of shape [num_units, output_size], where “output_size”
+ * corresponds to either the number of cell units (i.e., “num_units”),
+ * or the second dimension of the “projection_weights”, if defined.
+ * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$).
+ * A 2-D tensor of shape [num_units, output_size].
+ * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$).
+ * A 2-D tensor of shape [num_units, output_size].
+ * * 8: The recurrent-to-output weights (\f$W_{ho}\f$).
+ * A 2-D tensor of shape [num_units, output_size].
+ * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional.
+ * A 1-D tensor of shape [num_units].
+ * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional.
+ * A 1-D tensor of shape [num_units].
+ * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional.
+ * A 1-D tensor of shape [num_units].
+ * * 12:The input gate bias (\f$b_i\f$). Optional.
+ * A 1-D tensor of shape [num_units].
+ * * 13:The forget gate bias (\f$b_f\f$).
+ * A 1-D tensor of shape [num_units].
+ * * 14:The cell bias (\f$b_c\f$).
+ * A 1-D tensor of shape [num_units].
+ * * 15:The output gate bias (\f$b_o\f$).
+ * A 1-D tensor of shape [num_units].
+ * * 16:The projection weights (\f$W_{proj}\f$). Optional.
+ * A 2-D tensor of shape [output_size, num_units].
+ * * 17:The projection bias (\f$b_{proj}\f$). Optional.
+ * A 1-D tensor of shape [output_size].
+ * * 18:The output state (in) (\f$h_{t-1}\f$).
+ * A 2-D tensor of shape [batch_size, output_size].
+ * * 19:The cell state (in) (\f$C_{t-1}\f$).
+ * A 2-D tensor of shape [batch_size, num_units].
+ * * 20:The activation function (\f$g\f$).
+ * A value indicating the activation function:
+ * <ul>
+ * <li>0: None;
+ * <li>1: Relu;
+ * <li>3: Relu6;
+ * <li>4: Tanh;
+ * <li>6: Sigmoid.
+ * </ul>
+ * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such
+ * that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+ * then clipping is disabled.
+ * Until API level 29 this scalar must be of type {@link
+ * ANEURALNETWORKS_FLOAT32}. Since API level 29, if all the input
+ * tensors have type {@link ANEURALNETWORKS_TENSOR_FLOAT32}, this
+ * scalar must be of the type {@link ANEURALNETWORKS_FLOAT32},
+ * otherwise if all the input tensors have the type {@link
+ * ANEURALNETWORKS_TENSOR_FLOAT16}, this scalar must be of type {@link
+ * ANEURALNETWORKS_FLOAT16}.
+ * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the
+ * projection layer, such that values are bound within
+ * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+ * Until API level 29 this scalar must be of type {@link
+ * ANEURALNETWORKS_FLOAT32}. Since API level 29, if all the input
+ * tensors have type {@link ANEURALNETWORKS_TENSOR_FLOAT32}, this
+ * scalar must be of the type {@link ANEURALNETWORKS_FLOAT32},
+ * otherwise if all the input tensors have the type {@link
+ * ANEURALNETWORKS_TENSOR_FLOAT16}, this scalar must be of type {@link
+ * ANEURALNETWORKS_FLOAT16}.
+ * Since API level 29 there are additional inputs to this op:
+ * * 23:The input layer normalization weights.
+ * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+ * to activation at input gate.
+ * * 24:The forget layer normalization weights.
+ * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+ * to activation at forget gate.
+ * * 25:The cell layer normalization weights.
+ * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+ * to activation at cell gate.
+ * * 26:The output layer normalization weights.
+ * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+ * to activation at output gate.
+ *
+ * Outputs:
+ * * 0: The scratch buffer.
+ * A 2-D tensor of shape [batch_size, num_units * 3] with CIFG, or
+ * [batch_size, num_units * 4] without CIFG.
+ * * 1: The output state (out) (\f$h_t\f$).
+ * A 2-D tensor of shape [batch_size, output_size].
+ * * 2: The cell state (out) (\f$C_t\f$).
+ * A 2-D tensor of shape [batch_size, num_units].
+ * * 3: The output (\f$o_t\f$).
+ * A 2-D tensor of shape [batch_size, output_size]. This is effectively
+ * the same as the current “output state (out)” value.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_LSTM = 16,
+
+ /**
+ * Performs an 2-D max pooling operation.
+ *
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
+ *
+ * output[b, i, j, channel] =
+ * max_{di, dj} (
+ * input[b, strides[1] * i + di, strides[2] * j + dj, channel]
+ * )
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * width.
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * height.
+ * * 9: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 10: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * {@link PaddingCode} values.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * width.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the filter
+ * height.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 7: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_MAX_POOL_2D = 17,
+
+ /**
+ * Multiplies two tensors, element-wise.
+ *
+ * Takes two input tensors of identical {@link OperandCode} and compatible
+ * dimensions. The output is the product of both input tensors, optionally
+ * modified by an activation function.
+ *
+ * Two dimensions are compatible when:
+ * 1. they are equal, or
+ * 2. one of them is 1
+ *
+ * The size of the resulting output is the maximum size along each dimension
+ * of the input operands. It starts with the trailing dimensions, and works
+ * its way forward.
+ *
+ * Since API level 29, generic zero-sized input tensor is supported. Zero
+ * dimension is only compatible with 0 or 1. The size of the output
+ * dimension is zero if either of corresponding input dimension is zero.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode}, and compatible dimensions
+ * as input0.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * For a {@link ANEURALNETWORKS_TENSOR_INT32} tensor,
+ * the {@link FuseCode} must be "NONE".
+ *
+ * Outputs:
+ * * 0: The product, a tensor of the same {@link OperandCode} as input0.
+ * For output tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the following condition must be satisfied:
+ * output_scale > input1_scale * input2_scale.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_MUL = 18,
+
+ /**
+ * Computes rectified linear activation on the input tensor element-wise.
+ *
+ * The output is calculated using this formula:
+ *
+ * output = max(0, input)
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4.
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input.
+ * Since API level 29, this tensor may be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_RELU = 19,
+
+ /**
+ * Computes rectified linear 1 activation on the input tensor element-wise.
+ *
+ * The output is calculated using this formula:
+ *
+ * output = min(1.f, max(-1.f, input))
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4.
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input.
+ * Since API level 29, this tensor may be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of the same shape as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_RELU1 = 20,
+
+ /**
+ * Computes rectified linear 6 activation on the input tensor element-wise.
+ *
+ * The output is calculated using this formula:
+ *
+ * output = min(6, max(0, input))
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4.
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input.
+ * Since API level 29, this tensor may be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_RELU6 = 21,
+
+ /**
+ * Reshapes a tensor.
+ *
+ * Given tensor, this operation returns a tensor that has the same values as
+ * tensor, but with a newly specified shape.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4.
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the tensor to be reshaped.
+ * * 1: A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, defining the
+ * shape of the output tensor. The number of elements implied by shape
+ * must be the same as the number of elements in the input tensor.
+ *
+ * If one component of shape is the special value -1, the size of that
+ * dimension is computed so that the total size remains constant. In
+ * particular, a shape of [-1] flattens into 1-D. At most one component
+ * of shape can be -1.
+ *
+ * Outputs:
+ * * 0: The output tensor, of shape specified by the input shape.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_RESHAPE = 22,
+
+ /**
+ * Resizes images to given size using the bilinear interpretation.
+ *
+ * Resized images must be distorted if their output aspect ratio is not the
+ * same as input aspect ratio. The corner pixels of output may not be the
+ * same as corner pixels of input.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Both resizing by shape and resizing by scale are supported.
+ *
+ * Inputs (resizing by shape):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the output
+ * width of the output tensor.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the output
+ * height of the output tensor.
+ * * 3: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ * * 4: Align corners. An optional {@link ANEURALNETWORKS_BOOL}
+ * scalar, default to false. If True, the centers of the 4 corner
+ * pixels of the input and output tensors are aligned, preserving the
+ * values at the corner pixels.
+ * Available since API level 30.
+ * * 5: Half pixel centers. An optional {@link ANEURALNETWORKS_BOOL}
+ * scalar, default to false. If True, the pixel centers are assumed to
+ * be at (0.5, 0.5). This is the default behavior of image.resize in
+ * TF 2.0. If this parameter is True, then align_corners parameter
+ * must be False.
+ * Available since API level 30.
+ *
+ * Inputs (resizing by scale, since API level 29):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input. Zero batches is supported for this tensor.
+ * * 1: A scalar, specifying width_scale, the scaling factor of the width
+ * dimension from the input tensor to the output tensor. The output
+ * width is calculated as new_width = floor(width * width_scale).
+ * The scalar must be of {@link ANEURALNETWORKS_FLOAT16} if input0 is
+ * of {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} otherwise.
+ * * 2: A scalar, specifying height_scale, the scaling factor of the height
+ * dimension from the input tensor to the output tensor. The output
+ * height is calculated as new_height = floor(height * height_scale).
+ * The scalar must be of {@link ANEURALNETWORKS_FLOAT16} if input0 is
+ * of {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} otherwise.
+ * * 3: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * * 4: Align corners. An optional {@link ANEURALNETWORKS_BOOL}
+ * scalar, default to false. If True, the centers of the 4 corner
+ * pixels of the input and output tensors are aligned, preserving the
+ * values at the corner pixels.
+ * Available since API level 30.
+ * * 5: Half pixel centers. An optional {@link ANEURALNETWORKS_BOOL}
+ * scalar, default to false. If True, the pixel centers are assumed to
+ * be at (0.5, 0.5). This is the default behavior of image.resize in
+ * TF 2.0. If this parameter is True, then align_corners parameter
+ * must be False.
+ * Available since API level 30.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, new_height, new_width, depth].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_RESIZE_BILINEAR = 23,
+
+ /**
+ * A basic recurrent neural network layer.
+ *
+ * This layer implements the operation:
+ * outputs = state = activation(inputs * input_weights +
+ * state * recurrent_weights + bias)
+ *
+ * Where:
+ * * “input_weights” is a weight matrix that multiplies the inputs;
+ * * “recurrent_weights” is a weight matrix that multiplies the current
+ * “state” which itself is the output from the previous time step
+ * computation;
+ * * “bias” is a bias vector (added to each output vector in the batch);
+ * * “activation” is the function passed as the “fused_activation_function”
+ * argument (if not “NONE”).
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * The input tensors must all be the same type.
+ *
+ * Inputs:
+ * * 0: input.
+ * A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+ * corresponds to the batching dimension, and “input_size” is the size
+ * of the input.
+ * * 1: weights.
+ * A 2-D tensor of shape [num_units, input_size], where “num_units”
+ * corresponds to the number of units.
+ * * 2: recurrent_weights.
+ * A 2-D tensor of shape [num_units, num_units], with columns
+ * corresponding to the weights from each unit.
+ * * 3: bias.
+ * A 1-D tensor of shape [num_units].
+ * * 4: hidden state (in).
+ * A 2-D tensor of shape [batch_size, num_units].
+ * * 5: fused_activation_function.
+ * An optional {@link FuseCode} value indicating the
+ * activation function. If “NONE” is specified then it results in a
+ * linear activation.
+ *
+ * Outputs:
+ * * 0: hidden state (out).
+ * A 2-D tensor of shape [batch_size, num_units].
+ *
+ * * 1: output.
+ * A 2-D tensor of shape [batch_size, num_units]. This is effectively
+ * the same as the current state value.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_RNN = 24,
+
+ /**
+ * Computes the softmax activation on the input tensor element-wise, per
+ * batch, by normalizing the input vector so the maximum coefficient is
+ * zero.
+ *
+ * The output is calculated using this formula:
+ *
+ * output[batch, i] =
+ * exp((input[batch, i] - max(input[batch, :])) * beta) /
+ * sum_{k}{exp((input[batch, k] - max(input[batch, :])) * beta)}
+ *
+ * For input tensor with rank other than 2, the activation will be applied
+ * independently on each 1-D slice along specified dimension.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4.
+ * Tensors with rank other than 2 or 4 are only supported since API level 29.
+ *
+ * Inputs:
+ * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
+ * Since API level 29, this tensor may be zero-sized.
+ * * 1: A scalar, specifying the positive scaling factor for the exponent,
+ * beta. If input0 is of {@link ANEURALNETWORKS_TENSOR_FLOAT32},
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, the scalar
+ * must be of {@link ANEURALNETWORKS_FLOAT32}.
+ * If input0 is of {@link ANEURALNETWORKS_TENSOR_FLOAT16}, then the
+ * scalar must be of {@link ANEURALNETWORKS_FLOAT16}.
+ * * 2: An optional {@link ANEURALNETWORKS_INT32} scalar, default to -1,
+ * specifying the dimension the activation would be performed on.
+ * Negative index is used to specify axis from the end (e.g. -1 for
+ * the last axis). Must be in the range [-n, n).
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * the scale must be 1.f / 256 and the zeroPoint must be 0.
+ * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the scale must be 1.f / 256 and the zeroPoint must be -128.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_SOFTMAX = 25,
+
+ /**
+ * Rearranges blocks of spatial data, into depth.
+ *
+ * More specifically, this op outputs a copy of the input tensor where
+ * values from the height and width dimensions are moved to the depth
+ * dimension. The value block_size indicates the input block size and how
+ * the data is moved.
+ *
+ * Chunks of data of size block_size * block_size from depth are rearranged
+ * into non-overlapping blocks of size block_size x block_size.
+ *
+ * The depth of the output tensor is input_depth * block_size * block_size.
+ * The input tensor's height and width must be divisible by block_size.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Inputs:
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the block_size.
+ * block_size must be >=1 and block_size must be a divisor of both the
+ * input height and width.
+ * * 2: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape [batches, height/block_size,
+ * width/block_size, depth_in*block_size*block_size].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_SPACE_TO_DEPTH = 26,
+
+ /**
+ * SVDF op is a kind of stateful layer derived from the notion that a
+ * densely connected layer that's processing a sequence of input frames can
+ * be approximated by using a singular value decomposition of each of its
+ * nodes. The implementation is based on:
+ *
+ * https://research.google.com/pubs/archive/43813.pdf
+ *
+ * P. Nakkiran, R. Alvarez, R. Prabhavalkar, C. Parada.
+ * “Compressing Deep Neural Networks using a Rank-Constrained Topology”.
+ * INTERSPEECH, 2015.
+ *
+ * It processes the incoming input using a 2-stage filtering mechanism:
+ * * stage 1 performs filtering on the "features" dimension, whose outputs
+ * get pushed into a memory of fixed-size memory_size.
+ * * stage 2 performs filtering on the "time" dimension of the memory_size
+ * memoized outputs of stage 1.
+ *
+ * Specifically, for rank 1, this layer implements the operation:
+ *
+ * memory = push(conv1d(inputs, weights_feature, feature_dim,
+ * "ANEURALNETWORKS_PADDING_VALID"));
+ * outputs = activation(memory * weights_time + bias);
+ *
+ * Where:
+ * * “weights_feature” is a weights matrix that processes the inputs (by
+ * convolving the input with every “feature filter”), and whose outputs
+ * get pushed, stacked in order, into the fixed-size “memory” (the oldest
+ * entry gets dropped);
+ * * “weights_time” is a weights matrix that processes the “memory” (by a
+ * batched matrix multiplication on the num_units);
+ * * “bias” is an optional bias vector (added to each output vector in the
+ * batch); and
+ * * “activation” is the function passed as the “fused_activation_function”
+ * argument (if not “NONE”).
+ *
+ * Each rank adds a dimension to the weights matrices by means of stacking
+ * the filters.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * All input tensors must be the same type.
+ *
+ * Inputs:
+ * * 0: input.
+ * A 2-D tensor of shape [batch_size, input_size], where “batch_size”
+ * corresponds to the batching dimension, and “input_size” is the size
+ * of the input.
+ * * 1: weights_feature.
+ * A 2-D tensor of shape [num_units, input_size], where “num_units”
+ * corresponds to the number of units.
+ * * 2: weights_time.
+ * A 2-D tensor of shape [num_units, memory_size], where “memory_size”
+ * corresponds to the fixed-size of the memory.
+ * * 3: bias.
+ * An optional 1-D tensor of shape [num_units].
+ * * 4: state (in).
+ * A 2-D tensor of shape [batch_size, (memory_size - 1) * num_units * rank].
+ * * 5: rank.
+ * The rank of the SVD approximation.
+ * * 6: fused_activation_function.
+ * An optional {@link FuseCode} value indicating the
+ * activation function. If “NONE” is specified then it results in a
+ * linear activation.
+ *
+ * Outputs:
+ * * 0: state (out).
+ * A 2-D tensor of the same {@link OperandCode} as the inputs, with shape
+ * [batch_size, (memory_size - 1) * num_units * rank].
+ * * 1: output.
+ * A 2-D tensor of the same {@link OperandCode} as the inputs, with shape
+ * [batch_size, num_units].
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_SVDF = 27,
+
+ /**
+ * Computes hyperbolic tangent of input tensor element-wise.
+ *
+ * The output is calculated using this formula:
+ *
+ * output = tanh(input)
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4.
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input.
+ * Since API level 29, this tensor may be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * the scale must be 1.f / 128 and the zeroPoint must be 128.
+ * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the scale must be 1.f / 128 and the zeroPoint must be 0.
+ *
+ * Available since API level 27.
+ */
+ ANEURALNETWORKS_TANH = 28,
+
+ // Operations below are available since API level 28.
+
+ /**
+ * BatchToSpace for N-dimensional tensors.
+ *
+ * This operation reshapes the batch dimension (dimension 0) into M + 1
+ * dimensions of shape block_shape + [batch], interleaves these blocks back
+ * into the grid defined by the spatial dimensions [1, ..., M], to obtain a
+ * result with the same rank as the input.
+ *
+ * This is the reverse of SpaceToBatch.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the tensor to be reshaped
+ * * 1: A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the block
+ * sizes for each spatial dimension of the input tensor. All values
+ * must be >= 1.
+ * * 2: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_BATCH_TO_SPACE_ND = 29,
+
+ /**
+ * Element-wise division of two tensors.
+ *
+ * Takes two input tensors of identical {@link OperandCode} and compatible
+ * dimensions. The output is the result of dividing the first input tensor
+ * by the second, optionally modified by an activation function.
+ *
+ * For inputs of {@link ANEURALNETWORKS_TENSOR_INT32}, performs
+ * "floor division" ("//" in Python). For example,
+ * 5 // 2 = 2
+ * -5 // 2 = -3
+ *
+ * Two dimensions are compatible when:
+ * 1. they are equal, or
+ * 2. one of them is 1
+ *
+ * The size of the output is the maximum size along each dimension of the
+ * input operands. It starts with the trailing dimensions, and works its way
+ * forward.
+ *
+ * Example:
+ * input1.dimension = {4, 1, 2}
+ * input2.dimension = {5, 4, 3, 1}
+ * output.dimension = {5, 4, 3, 2}
+ *
+ * Since API level 29, generic zero-sized input tensor is supported. Zero
+ * dimension is only compatible with 0 or 1. The size of the output
+ * dimension is zero if either of corresponding input dimension is zero.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the first input.
+ * * 1: A tensor of the same {@link OperandCode}, and compatible dimensions
+ * as input0.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * For a {@link ANEURALNETWORKS_TENSOR_INT32} tensor,
+ * the {@link FuseCode} must be "NONE".
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_DIV = 30,
+
+ /**
+ * Computes the mean of elements across dimensions of a tensor.
+ *
+ * Reduces the input tensor along the given dimensions to reduce. Unless
+ * keep_dims is true, the rank of the tensor is reduced by 1 for each entry
+ * in axis. If keep_dims is true, the reduced dimensions are retained with
+ * length 1.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input.
+ * * 1: A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The dimensions
+ * to reduce. Must be in the range
+ * [-rank(input_tensor), rank(input_tensor)).
+ *
+ * NOTE: When the operation was introduced, the documentation
+ * incorrectly stated that if dimensions were empty, the operation
+ * would reduce across all dimensions. This behavior was never
+ * implemented.
+ *
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, keep_dims. If positive,
+ * retains reduced dimensions with length 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ * If all dimensions are reduced and keep_dims is false, the output
+ * shape is [1].
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_MEAN = 31,
+
+ /**
+ * Pads a tensor.
+ *
+ * This operation pads a tensor according to the specified paddings.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ * (full support since API level 29, see the output section)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the tensor to be padded.
+ * * 1: A 2-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the paddings
+ * for each spatial dimension of the input tensor. The shape of the
+ * tensor must be {rank(input0), 2}.
+ * padding[i, 0] specifies the number of elements to be padded in the
+ * front of dimension i.
+ * padding[i, 1] specifies the number of elements to be padded after the
+ * end of dimension i.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0. The
+ * output tensor has the same rank as input0, and each
+ * dimension of the output tensor has the same size as the
+ * corresponding dimension of the input tensor plus the size
+ * of the padding:
+ * output0.dimension[i] =
+ * padding[i, 0] + input0.dimension[i] + padding[i, 1]
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * NOTE: Before API level 29, the pad value for
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} is undefined.
+ * Since API level 29, the pad value is always the logical zero.
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_PAD = 32,
+
+ /**
+ * SpaceToBatch for N-Dimensional tensors.
+ *
+ * This operation divides "spatial" dimensions [1, ..., M] of the input into
+ * a grid of blocks of shape block_shape, and interleaves these blocks with
+ * the "batch" dimension (0) such that in the output, the spatial dimensions
+ * [1, ..., M] correspond to the position within the grid, and the batch
+ * dimension combines both the position within a spatial block and the
+ * original batch position. Prior to division into blocks, the spatial
+ * dimensions of the input are optionally zero padded according to paddings.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ * (full support since API level 29, see the output section)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ * NCHW is supported since API level 29.
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the input.
+ * * 1: A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the block
+ * sizes for each spatial dimension of the input tensor. All values
+ * must be >= 1.
+ * * 2: A 2-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the paddings
+ * for each spatial dimension of the input tensor. All values must be
+ * >= 0. The shape of the tensor must be {M, 2}, where M is the number
+ * of spatial dimensions.
+ * padding[i, 0] specifies the number of element to be padded in the
+ * front of dimension i.
+ * padding[i, 1] specifies the number of element to be padded after the
+ * end of dimension i.
+ * * 3: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * Available since API level 29.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * NOTE: Before API level 29, the pad value for
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} is undefined.
+ * Since API level 29, the pad value is always the logical zero.
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_SPACE_TO_BATCH_ND = 33,
+
+ /**
+ * Removes dimensions of size 1 from the shape of a tensor.
+ *
+ * Given a tensor input, this operation returns a tensor of the same
+ * {@link OperandCode} with all dimensions of size 1 removed. If you don't
+ * want to remove all size 1 dimensions, you can remove specific size 1
+ * dimensions by specifying the axes (input1).
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, the tensor to be squeezed.
+ * * 1: An optional 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The
+ * dimensions to squeeze. If specified only squeezes the dimensions
+ * listed. Otherwise, squeezes all dimensions. The dimension index
+ * starts at 0. An error must be reported if squeezing a dimension that
+ * is not 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0. Contains the
+ * same data as input, but has one or more dimensions of size 1
+ * removed.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ * If all input dimensions are equal to 1 and are to be squeezed, the
+ * output shape is [1].
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_SQUEEZE = 34,
+
+ /**
+ * Extracts a strided slice of a tensor.
+ *
+ * Roughly speaking, this op extracts a slice of size (end - begin) / stride
+ * from the given input tensor. Starting at the location specified by begin
+ * the slice continues by adding stride to the index until all dimensions
+ * are not less than end. Note that a stride can be negative, which causes a
+ * reverse slice.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the tensor to be sliced.
+ * * 1: begin, a 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The
+ * starts of the dimensions of the input tensor to be sliced. The
+ * length must be of rank(input0).
+ * * 2: end, a 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The
+ * ends of the dimensions of the input tensor to be sliced. The length
+ * must be of rank(input0).
+ * * 3: strides, a 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The
+ * strides of the dimensions of the input tensor to be sliced. The
+ * length must be of rank(input0). The entries must be non-zero.
+ * * 4: begin_mask, an {@link ANEURALNETWORKS_INT32} scalar. If the ith bit
+ * of begin_mask is set, begin[i] is ignored and the fullest possible
+ * range in that dimension is used instead.
+ * * 5: end_mask, an {@link ANEURALNETWORKS_INT32} scalar. If the ith bit of
+ * end_mask is set, end[i] is ignored and the fullest possible range in
+ * that dimension is used instead.
+ * * 6: shrink_axis_mask, an {@link ANEURALNETWORKS_INT32} scalar. If the
+ * ith bit of shrink_axis_mask is set, the ith dimension specification
+ * shrinks the dimensionality by 1, taking on the value at index
+ * begin[i]. In this case, the ith specification must define a
+ * slice of size 1, e.g. begin[i] = x, end[i] = x + 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0 and rank (n - k),
+ * where k is the number of bits set in shrink_axis_mask.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ * If shrink_axis_mask is true for all input dimensions, the output
+ * shape is [1].
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_STRIDED_SLICE = 35,
+
+ /**
+ * Element-wise subtraction of two tensors.
+ *
+ * Takes two input tensors of identical {@link OperandCode} and compatible
+ * dimensions. The output is the result of subtracting the second input
+ * tensor from the first one, optionally modified by an activation function.
+ *
+ * Two dimensions are compatible when:
+ * 1. they are equal, or
+ * 2. one of them is 1
+ *
+ * The size of the output is the maximum size along each dimension of the
+ * input operands. It starts with the trailing dimensions, and works its way
+ * forward.
+ *
+ * Example:
+ * input1.dimension = {4, 1, 2}
+ * input2.dimension = {5, 4, 3, 1}
+ * output.dimension = {5, 4, 3, 2}
+ *
+ * Since API level 29, generic zero-sized input tensor is supported. Zero
+ * dimension is only compatible with 0 or 1. The size of the output
+ * dimension is zero if either of corresponding input dimension is zero.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the first input.
+ * * 1: A tensor of the same {@link OperandCode}, and compatible dimensions
+ * as input0.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * For a {@link ANEURALNETWORKS_TENSOR_INT32} tensor,
+ * the {@link FuseCode} must be "NONE".
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_SUB = 36,
+
+ /**
+ * Transposes the input tensor, permuting the dimensions according to the
+ * perm tensor.
+ *
+ * The returned tensor's dimension i corresponds to the input dimension
+ * perm[i]. If perm is not given, it is set to (n-1...0), where n is the
+ * rank of the input tensor. Hence by default, this operation performs a
+ * regular matrix transpose on 2-D input Tensors.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29)
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the tensor to be transposed.
+ * Since API level 29, this tensor may be zero-sized.
+ * * 1: An optional 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32},
+ * the permutation of the dimensions of the input tensor.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 28.
+ */
+ ANEURALNETWORKS_TRANSPOSE = 37,
+
+ // Operations below are available since API level 29.
+
+ /**
+ * Computes the absolute value of a tensor, element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30)
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_ABS = 38,
+
+ /**
+ * Returns the index of the largest element along an axis.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: An n-D tensor specifying the input. Must be non-empty.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar specifying the axis to
+ * reduce across. Negative index is used to specify axis from the
+ * end (e.g. -1 for the last axis). Must be in the range [-n, n).
+ *
+ * Outputs:
+ * * 0: An (n - 1)-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor.
+ * If input is 1-dimensional, the output shape is [1].
+ *
+ * Available since API level 29.
+ */
+ // There is no underscore in ARG_MAX to avoid name conflict with
+ // the macro defined in libc/kernel/uapi/linux/limits.h.
+ ANEURALNETWORKS_ARGMAX = 39,
+
+ /**
+ * Returns the index of the smallest element along an axis.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: An n-D tensor specifying the input. Must be non-empty.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar specifying the axis to
+ * reduce across. Negative index is used to specify axis from the
+ * end (e.g. -1 for the last axis). Must be in the range [-n, n).
+ *
+ * Outputs:
+ * * 0: An (n - 1)-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor.
+ * If input is 1-dimensional, the output shape is [1].
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_ARGMIN = 40, // See ARGMAX for naming discussion.
+
+ /**
+ * Transform axis-aligned bounding box proposals using bounding box deltas.
+ *
+ * Given the positions of bounding box proposals and the corresponding
+ * bounding box deltas for each class, return the refined bounding box
+ * regions. The resulting bounding boxes are cliped against the edges of
+ * the image.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}
+ *
+ * Inputs:
+ * * 0: A 2-D Tensor of shape [num_rois, 4], specifying the locations of the
+ * bounding box proposals, each line with format [x1, y1, x2, y2].
+ * For tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM},
+ * the zeroPoint must be 0 and the scale must be 0.125. Zero num_rois
+ * is supported for this tensor.
+ * * 1: A 2-D Tensor of shape [num_rois, num_classes * 4], specifying the
+ * bounding box delta for each region of interest and each class. The
+ * bounding box deltas are organized in the following order
+ * [dx, dy, dw, dh], where dx and dy is the relative correction factor
+ * for the center position of the bounding box with respect to the width
+ * and height, dw and dh is the log-scale relative correction factor
+ * for the width and height. For input0 of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, this tensor should be
+ * of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}. Zero num_rois is
+ * supported for this tensor.
+ * * 2: An 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape
+ * [num_rois], specifying the batch index of each box. Boxes with
+ * the same batch index are grouped together. Zero num_rois is
+ * supported for this tensor.
+ * * 3: A 2-D Tensor of shape [batches, 2], specifying the information of
+ * each image in the batch, each line with format
+ * [image_height, image_width].
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0, with shape
+ * [num_rois, num_classes * 4], specifying the coordinates of each
+ * output bounding box for each class, with format [x1, y1, x2, y2].
+ * For type of {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, the
+ * scale must be 0.125 and the zero point must be 0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_AXIS_ALIGNED_BBOX_TRANSFORM = 41,
+
+ /**
+ * A recurrent neural network layer that applies an LSTM cell to a
+ * sequence of inputs in forward and backward directions.
+ *
+ * The op supports cross-linking via an auxiliary input. Regular cell feeds
+ * one input into the two RNN cells in the following way:
+ *
+ * INPUT (INPUT_REVERSED)
+ * | |
+ * ---------------------
+ * | FW_LSTM BW_LSTM |
+ * ---------------------
+ * | |
+ * FW_OUT BW_OUT
+ *
+ * An op with cross-linking takes two inputs and feeds them into the RNN
+ * cells in the following way:
+ *
+ * AUX_INPUT (AUX_INPUT_REVERSED)
+ * | |
+ * INPUT | (INPUT_R'D.)|
+ * | | | |
+ * -----------------------
+ * | \ / \ / |
+ * | FW_LSTM BW_LSTM |
+ * -----------------------
+ * | |
+ * FW_OUT BW_OUT
+ *
+ * The cross-linking mode is enabled iff auxiliary input and auxiliary
+ * weights are present. While stacking this op on top of itself, this
+ * allows to connect both forward and backward outputs from previous cell
+ * to the next cell's input.
+ *
+ * Since API level 30 parallel linking mode is supported. The mode is
+ * enabled if auxiliary input is present but auxiliary weights are omitted.
+ * In this case, the cell feeds inputs into the RNN in the following way:
+ *
+ * INPUT (AUX_INPUT_REVERSED)
+ * | |
+ * ---------------------
+ * | FW_LSTM BW_LSTM |
+ * ---------------------
+ * | |
+ * FW_OUT BW_OUT
+ *
+ * While stacking this op on top of itself, this allows to connect both
+ * forward and backward outputs from previous cell to the next cell's
+ * corresponding inputs.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: 3, either time-major or batch-major.
+ *
+ * All input and output tensors must be of the same type.
+ *
+ * Inputs:
+ * * 0: The input.
+ * A 3-D tensor of shape:
+ * If time-major: [max_time, batch_size, input_size]
+ * If batch-major: [batch_size, max_time, input_size]
+ * where "max_time" is the number of timesteps (sequence length),
+ * "batch_size" corresponds to the batching dimension, and
+ * "input_size" is the size of the input.
+ * * 1: The forward input-to-input weights. Optional.
+ * A 2-D tensor of shape [fw_num_units, input_size], where “fw_num_units”
+ * corresponds to the number of forward cell units.
+ * * 2: The forward input-to-forget weights.
+ * A 2-D tensor of shape [fw_num_units, input_size].
+ * * 3: The forward input-to-cell weights.
+ * A 2-D tensor of shape [fw_num_units, input_size].
+ * * 4: The forward input-to-output weights.
+ * A 2-D tensor of shape [fw_num_units, input_size].
+ * * 5: The forward recurrent-to-input weights. Optional.
+ * A 2-D tensor of shape [fw_num_units, fw_output_size], where “fw_output_size”
+ * corresponds to either the number of cell units (i.e., fw_num_units),
+ * or the second dimension of the “fw_projection_weights”, if defined.
+ * * 6: The forward recurrent-to-forget weights.
+ * A 2-D tensor of shape [fw_num_units, fw_output_size].
+ * * 7: The forward recurrent-to-cell weights.
+ * A 2-D tensor of shape [fw_num_units, fw_output_size].
+ * * 8: The forward recurrent-to-output weights.
+ * A 2-D tensor of shape [fw_num_units, fw_output_size].
+ * * 9: The forward cell-to-input weights. Optional.
+ * A 1-D tensor of shape [fw_num_units].
+ * * 10: The forward cell-to-forget weights. Optional.
+ * A 1-D tensor of shape [fw_num_units].
+ * * 11: The forward cell-to-output weights. Optional.
+ * A 1-D tensor of shape [fw_num_units].
+ * * 12: The forward input gate bias. Optional.
+ * A 1-D tensor of shape [fw_num_units].
+ * * 13: The forward forget gate bias.
+ * A 1-D tensor of shape [fw_num_units].
+ * * 14: The forward cell gate bias.
+ * A 1-D tensor of shape [fw_num_units].
+ * * 15: The forward output gate bias.
+ * A 1-D tensor of shape [fw_num_units].
+ * * 16: The forward projection weights. Optional.
+ * A 2-D tensor of shape [fw_output_size, fw_num_units].
+ * * 17: The forward projection bias. Optional.
+ * A 1-D tensor of shape [fw_output_size].
+ * * 18: The backward input-to-input weights. Optional.
+ * A 2-D tensor of shape [bw_num_units, input_size], where “bw_num_units”
+ * corresponds to the number of backward cell units.
+ * * 19: The backward input-to-forget weights.
+ * A 2-D tensor of shape [bw_num_units, input_size].
+ * * 20: The backward input-to-cell weights.
+ * A 2-D tensor of shape [bw_num_units, input_size].
+ * * 21: The backward input-to-output weights.
+ * A 2-D tensor of shape [bw_num_units, input_size].
+ * * 22: The backward recurrent-to-input weights. Optional.
+ * A 2-D tensor of shape [bw_num_units, bw_output_size], where “bw_output_size”
+ * corresponds to either the number of cell units (i.e., “bw_num_units”),
+ * or the second dimension of the “bw_projection_weights”, if defined.
+ * * 23: The backward recurrent-to-forget weights.
+ * A 2-D tensor of shape [bw_num_units, bw_output_size].
+ * * 24: The backward recurrent-to-cell weights.
+ * A 2-D tensor of shape [bw_num_units, bw_output_size].
+ * * 25: The backward recurrent-to-output weights.
+ * A 2-D tensor of shape [bw_num_units, bw_output_size].
+ * * 26: The backward cell-to-input weights. Optional.
+ * A 1-D tensor of shape [bw_num_units].
+ * * 27: The backward cell-to-forget weights. Optional.
+ * A 1-D tensor of shape [bw_num_units].
+ * * 28: The backward cell-to-output weights. Optional.
+ * A 1-D tensor of shape [bw_num_units].
+ * * 29: The backward input gate bias. Optional.
+ * A 1-D tensor of shape [bw_num_units].
+ * * 30: The backward forget gate bias.
+ * A 1-D tensor of shape [bw_num_units].
+ * * 31: The backward cell gate bias.
+ * A 1-D tensor of shape [bw_num_units].
+ * * 32: The backward output gate bias.
+ * A 1-D tensor of shape [bw_num_units].
+ * * 33: The backward projection weights. Optional.
+ * A 2-D tensor of shape [bw_output_size, bw_num_units].
+ * * 34: The backward projection bias. Optional.
+ * A 1-D tensor of shape [bw_output_size].
+ * * 35: The forward input activation state.
+ * A 2-D tensor of shape [batch_size, bw_output_size].
+ * * 36: The forward input cell state.
+ * A 2-D tensor of shape [batch_size, bw_num_units].
+ * * 37: The backward input activation state.
+ * A 2-D tensor of shape [batch_size, bw_output_size].
+ * * 38: The backward input cell state.
+ * A 2-D tensor of shape [batch_size, bw_num_units].
+ * * 39: The auxiliary input. Optional.
+ * A 3-D tensor of shape [max_time, batch_size, aux_input_size],
+ * where “batch_size” corresponds to the batching dimension, and
+ * “aux_input_size” is the size of the auxiliary input. Optional. See
+ * the docs above for the usage modes explanation.
+ * * 40: The forward auxiliary input-to-input weights.
+ * Optional. See the docs above for the usage modes explanation.
+ * A 2-D tensor of shape [fw_num_units, aux_input_size].
+ * * 41: The forward auxiliary input-to-forget weights.
+ * Optional. See the docs above for the usage modes explanation.
+ * A 2-D tensor of shape [fw_num_units, aux_input_size].
+ * * 42: The forward auxiliary input-to-cell weights.
+ * Optional. See the docs above for the usage modes explanation.
+ * A 2-D tensor of shape [fw_num_units, aux_input_size].
+ * * 43: The forward auxiliary input-to-output weights.
+ * Optional. See the docs above for the usage modes explanation.
+ * A 2-D tensor of shape [fw_num_units, aux_input_size].
+ * * 44: The backward auxiliary input-to-input weights.
+ * Optional. See the docs above for the usage modes explanation.
+ * A 2-D tensor of shape [bw_num_units, aux_input_size].
+ * * 45: The backward auxiliary input-to-forget weights.
+ * Optional. See the docs above for the usage modes explanation.
+ * A 2-D tensor of shape [bw_num_units, aux_input_size].
+ * * 46: The backward auxiliary input-to-cell weights.
+ * Optional. See the docs above for the usage modes explanation.
+ * A 2-D tensor of shape [bw_num_units, aux_input_size].
+ * * 47: The backward auxiliary input-to-output weights.
+ * Optional. See the docs above for the usage modes explanation.
+ * A 2-D tensor of shape [bw_num_units, aux_input_size].
+ * * 48: The activation function.
+ * A value indicating the activation function:
+ * <ul>
+ * <li>0: None;
+ * <li>1: Relu;
+ * <li>3: Relu6;
+ * <li>4: Tanh;
+ * <li>6: Sigmoid.
+ * </ul>
+ * * 49: The clipping threshold for the cell state, such
+ * that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+ * then clipping is disabled.
+ * If all the input tensors have type {@link ANEURALNETWORKS_TENSOR_FLOAT32},
+ * this scalar must be of the type {@link ANEURALNETWORKS_FLOAT32},
+ * otherwise if all the input tensors have the type
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16}, this scalar must be
+ * of type {@link ANEURALNETWORKS_FLOAT16}.
+ * * 50: The clipping threshold for the output from the
+ * projection layer, such that values are bound within
+ * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+ * If all the input tensors have type {@link ANEURALNETWORKS_TENSOR_FLOAT32},
+ * this scalar must be of the type {@link ANEURALNETWORKS_FLOAT32},
+ * otherwise if all the input tensors have the type
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16}, this scalar must be
+ * of type {@link ANEURALNETWORKS_FLOAT16}.
+ * * 51: merge_outputs
+ * An {@link ANEURALNETWORKS_BOOL} scalar specifying if the outputs
+ * from forward and backward cells should be merged.
+ * * 52: time_major
+ * An {@link ANEURALNETWORKS_BOOL} scalar specifying the shape format
+ * of input and output tensors.
+ * * 53: The forward input layer normalization weights. Optional.
+ * A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+ * to activation at input gate.
+ * * 54: The forward forget layer normalization weights. Optional.
+ * A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+ * to activation at forget gate.
+ * * 55: The forward cell layer normalization weights. Optional.
+ * A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+ * to activation at cell gate.
+ * * 56: The forward output layer normalization weights. Optional.
+ * A 1-D tensor of shape [fw_num_units]. Used to rescale normalized inputs
+ * to activation at output gate.
+ * * 57: The backward input layer normalization weights. Optional.
+ * A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+ * to activation at input gate.
+ * * 58: The backward forget layer normalization weights. Optional.
+ * A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+ * to activation at forget gate.
+ * * 59: The backward cell layer normalization weights. Optional.
+ * A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+ * to activation at cell gate.
+ * * 60: The backward output layer normalization weights. Optional.
+ * A 1-D tensor of shape [bw_num_units]. Used to rescale normalized inputs
+ * to activation at output gate.
+ *
+ * Outputs:
+ * * 0: The forward output.
+ * A 3-D tensor of shape:
+ * If time-major and not merge_outputs:
+ * [max_time, batch_size, fw_output_size]
+ * If time-major and merge_outputs:
+ * [max_time, batch_size, fw_output_size + bw_output_size]
+ * If batch-major and not merge_outputs:
+ * [batch_size, max_time, fw_output_size]
+ * If batch-major and merge_outputs:
+ * [batch_size, max_time, fw_output_size + bw_output_size]
+ * * 1: The backward output. Unused if merge_outputs is true.
+ * A 3-D tensor of shape:
+ * If time-major: [max_time, batch_size, bw_output_size]
+ * If batch-major: [batch_size, max_time, bw_output_size]
+ * * 2: The forward activation state output.
+ * A 2-D tensor of shape [batch_size, fw_output_size] containing an
+ * activation state from the last time step in the sequence. This
+ * output is optional and can be omitted. If this output is present
+ * then outputs 3-5 must be present as well.
+ * Available since API level 30.
+ * * 3: The forward cell state output.
+ * A tensor of shape [batch_size, fw_cell_size] containing a cell state
+ * from the last time step in the sequence. This output is optional
+ * and can be omitted. If this output is present
+ * then outputs 2, 4, 5 must be present as well.
+ * Available since API level 30.
+ * * 4: The backward activation state output.
+ * A 2-D tensor of shape [batch_size, bw_output_size] containing an
+ * activation state from the last time step in the sequence. This
+ * output is optional and can be omitted. If this output is present
+ * then outputs 2, 3, 5 must be present as well.
+ * Available since API level 30.
+ * * 5: The backward cell state output.
+ * A tensor of shape [batch_size, bw_cell_size] containing a cell state
+ * from the last time step in the sequence. This output is optional
+ * and can be omitted. If this output is present
+ * then outputs 2-4 must be present as well.
+ * Available since API level 30.
+ *
+ * Available since API level 29.
+ *
+ * Important: As of API level 29, there is no way to get the output state tensors out and NNAPI
+ * does not maintain internal states. This operator does not support the usage pattern in which
+ * multiple cells are chained and state tensors are propagated.
+ */
+ ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_LSTM = 42,
+
+ /**
+ * A recurrent neural network layer that applies a basic RNN cell to a
+ * sequence of inputs in forward and backward directions.
+ *
+ * This Op unrolls the input along the sequence dimension, and implements
+ * the following operation for each element in the sequence s =
+ * 1...sequence_length:
+ * fw_outputs[s] = fw_state = activation(inputs[s] * fw_input_weights’ +
+ * fw_state * fw_recurrent_weights’ + fw_bias)
+ *
+ * And for each element in sequence t = sequence_length : 1
+ * bw_outputs[t] = bw_state = activation(inputs[t] * bw_input_weights’ +
+ * bw_state * bw_recurrent_weights’ + bw_bias)
+ *
+ * Where:
+ * * “{fw,bw}_input_weights” is a weight matrix that multiplies the inputs;
+ * * “{fw,bw}_recurrent_weights” is a weight matrix that multiplies the
+ * current “state” which itself is the output from the previous time step
+ * computation;
+ * * “{fw,bw}_bias” is a bias vector (added to each output vector in the
+ * batch);
+ * * “activation” is the function passed as the “fused_activation_function”
+ * argument (if not “NONE”).
+ *
+ * The op supports cross-linking via an auxiliary input. Regular cell feeds
+ * one input into the two RNN cells in the following way:
+ *
+ * INPUT (INPUT_REVERSED)
+ * | |
+ * ---------------------
+ * | FW_RNN BW_RNN |
+ * ---------------------
+ * | |
+ * FW_OUT BW_OUT
+ *
+ * An op with cross-linking takes two inputs and feeds them into the RNN
+ * cells in the following way:
+ *
+ * AUX_INPUT (AUX_INPUT_REVERSED)
+ * | |
+ * INPUT | (INPUT_R'D.)|
+ * | | | |
+ * -----------------------
+ * | \ / \ / |
+ * | FW_RNN BW_RNN |
+ * -----------------------
+ * | |
+ * FW_OUT BW_OUT
+ *
+ * The cross-linking mode is enabled iff auxiliary input and auxiliary
+ * weights are present. While stacking this op on top of itself, this
+ * allows to connect both forward and backward outputs from previous cell
+ * to the next cell's input.
+ *
+ * Since API level 30 parallel linking mode is supported. The mode is
+ * enabled if auxiliary input is present but auxiliary weights are omitted.
+ * In this case, the cell feeds inputs into the RNN in the following way:
+ *
+ * INPUT (AUX_INPUT_REVERSED)
+ * | |
+ * ---------------------
+ * | FW_RNN BW_RNN |
+ * ---------------------
+ * | |
+ * FW_OUT BW_OUT
+ *
+ * While stacking this op on top of itself, this allows to connect both
+ * forward and backward outputs from previous cell to the next cell's
+ * corresponding inputs.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * The input tensors must all be the same type.
+ *
+ * Inputs:
+ * * 0: input.
+ * A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+ * it is set to true, then the input has a shape [maxTime, batchSize,
+ * inputSize], otherwise the input has a shape [batchSize, maxTime,
+ * inputSize].
+ * * 1: fwWeights.
+ * A 2-D tensor of shape [fwNumUnits, inputSize].
+ * * 2: fwRecurrentWeights.
+ * A 2-D tensor of shape [fwNumUnits, fwNumUnits].
+ * * 3: fwBias.
+ * A 1-D tensor of shape [fwNumUnits].
+ * * 4: fwHiddenState.
+ * A 2-D tensor of shape [batchSize, fwNumUnits]. Specifies a hidden
+ * state input for the first time step of the computation.
+ * * 5: bwWeights.
+ * A 2-D tensor of shape [bwNumUnits, inputSize].
+ * * 6: bwRecurrentWeights.
+ * A 2-D tensor of shape [bwNumUnits, bwNumUnits].
+ * * 7: bwBias.
+ * A 1-D tensor of shape [bwNumUnits].
+ * * 8: bwHiddenState
+ * A 2-D tensor of shape [batchSize, bwNumUnits]. Specifies a hidden
+ * state input for the first time step of the computation.
+ * * 9: auxInput.
+ * A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+ * it is set to true, then the input has a shape [maxTime, batchSize,
+ * auxInputSize], otherwise the input has a shape [batchSize, maxTime,
+ * auxInputSize]. Can be omitted. See the docs above for the usage
+ * modes explanation.
+ * * 10:fwAuxWeights.
+ * A 2-D tensor of shape [fwNumUnits, auxInputSize]. Can be omitted.
+ * See the docs above for the usage modes explanation.
+ * * 11:bwAuxWeights.
+ * A 2-D tensor of shape [bwNumUnits, auxInputSize]. Can be omitted.
+ * See the docs above for the usage modes explanation.
+ * * 12:fusedActivationFunction.
+ * A {@link FuseCode} value indicating the activation function. If
+ * “NONE” is specified then it results in a linear activation.
+ * * 13:timeMajor
+ * An {@link ANEURALNETWORKS_BOOL} scalar specifying the shape format
+ * of input and output tensors.
+ * * 14:mergeOutputs
+ * An {@link ANEURALNETWORKS_BOOL} scalar specifying if the outputs
+ * from forward and backward cells are separate (if set to false) or
+ * concatenated (if set to true).
+ * Outputs:
+ * * 0: fwOutput.
+ * A 3-D tensor. The first two dimensions of the shape are defined by
+ * the input 6 (timeMajor) and the third dimension is defined by the
+ * input 14 (mergeOutputs). If timeMajor is set to true, then the first
+ * two dimensions are [maxTime, batchSize], otherwise they are set to
+ * [batchSize, maxTime]. If mergeOutputs is set to true, then the third
+ * dimension is equal to (fwNumUnits + bwNumUnits), otherwise it is set
+ * to fwNumUnits.
+ * * 1: bwOutput.
+ * A 3-D tensor. If the input 14 (mergeOutputs) is set to true, then
+ * this tensor is not produced. The shape is defined by the input 6
+ * (timeMajor). If it is set to true, then the shape is set to
+ * [maxTime, batchSize, bwNumUnits], otherwise the shape is set to
+ * [batchSize, maxTime, bwNumUnits].
+ * * 2: The forward hidden state output.
+ * A 2-D tensor of shape [batchSize, fwNumUnits] containing a hidden
+ * state from the last time step in the sequence. This output is
+ * optional and can be omitted. If this output is present then output
+ * 3 must be present as well.
+ * Available since API level 30.
+ * * 3: The backward hidden state output.
+ * A 2-D tensor of shape [batchSize, bwNumUnits] containing a hidden
+ * state from the last time step in the sequence. This output is
+ * optional and can be omitted. If this output is present then output
+ * 2 must be present as well.
+ * Available since API level 30.
+ *
+ * Available since API level 29.
+ *
+ * Important: As of API level 29, there is no way to get the output state tensors out and NNAPI
+ * does not maintain internal states. This operator does not support the usage pattern in which
+ * multiple cells are chained and state tensors are propagated.
+ */
+ ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_RNN = 43,
+
+ /**
+ * Greedily selects a subset of bounding boxes in descending order of score.
+ *
+ * This op applies NMS algorithm to each class. In each loop of execution,
+ * the box with maximum score gets selected and removed from the pending set.
+ * The scores of the rest of boxes are lowered according to the
+ * intersection-over-union (IOU) overlapping with the previously selected
+ * boxes and a specified NMS kernel method. Any boxes with score less
+ * than a threshold are removed from the pending set.
+ *
+ * Three NMS kernels are supported:
+ * * Hard: score_new = score_old * (1 if IoU < threshold else 0)
+ * * Linear: score_new = score_old * (1 if IoU < threshold else 1 - IoU)
+ * * Gaussian: score_new = score_old * exp(- IoU^2 / sigma)
+ *
+ * Axis-aligned bounding boxes are represented by its upper-left corner
+ * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid
+ * bounding box should satisfy x1 <= x2 and y1 <= y2.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Inputs:
+ * * 0: A 2-D Tensor of shape [num_rois, num_classes], specifying the score
+ * of each bounding box proposal. The boxes are grouped by batches in the
+ * first dimension. Zero num_rois is supported for this tensor.
+ * * 1: A 2-D Tensor specifying the bounding boxes of shape
+ * [num_rois, num_classes * 4], organized in the order [x1, y1, x2, y2].
+ * The boxes are grouped by batches in the first dimension. The sequential
+ * order of the boxes corresponds with input0. For input0 of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, this tensor should be of
+ * {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, with zeroPoint of 0 and
+ * scale of 0.125.
+ * For input0 of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * this tensor should be of {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM},
+ * with zeroPoint of -128 and scale of 0.125.
+ * Zero num_rois is supported for this tensor.
+ * * 2: A 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape
+ * [num_rois], specifying the batch index of each box. Boxes with
+ * the same batch index are grouped together.
+ * * 3: An {@link ANEURALNETWORKS_FLOAT32} scalar, score_threshold. Boxes
+ * with scores lower than the threshold are filtered before sending
+ * to the NMS algorithm.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the maximum
+ * number of selected bounding boxes for each image. Set to a negative
+ * value for unlimited number of output bounding boxes.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the NMS
+ * kernel method, options are 0:hard, 1:linear, 2:gaussian.
+ * * 6: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the IoU
+ * threshold in hard and linear NMS kernel. This field is ignored if
+ * gaussian kernel is selected.
+ * * 7: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the sigma in
+ * gaussian NMS kernel. This field is ignored if gaussian kernel is
+ * not selected.
+ * * 8: An {@link ANEURALNETWORKS_FLOAT32} scalar, nms_score_threshold.
+ * Boxes with scores lower than the threshold are dropped during the
+ * score updating phase in soft NMS.
+ *
+ * Outputs:
+ * * 0: A 1-D Tensor of the same {@link OperandCode} as input0, with shape
+ * [num_output_rois], specifying the score of each output box. The boxes
+ * are grouped by batches, but the sequential order in each batch is not
+ * guaranteed. For type of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * guaranteed. For type of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * or {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the scale and zero point must be the same as input0.
+ * * 1: A 2-D Tensor of the same {@link OperandCode} as input1, with shape
+ * [num_output_rois, 4], specifying the coordinates of each
+ * output bounding box with the same format as input1. The sequential
+ * order of the boxes corresponds with output0. For type of
+ * {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, the scale must be
+ * 0.125 and the zero point must be 0.
+ * * 2: A 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape
+ * [num_output_rois], specifying the class of each output box. The
+ * sequential order of the boxes corresponds with output0.
+ * * 3: A 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape
+ * [num_output_rois], specifying the batch index of each box. Boxes
+ * with the same batch index are grouped together.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_BOX_WITH_NMS_LIMIT = 44,
+
+ /**
+ * Casts a tensor to a type.
+ *
+ * This operation ignores the scale and zeroPoint of quanized tensors,
+ * e.g. it treats a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} input
+ * as a tensor of uint8 values.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * Since API level 30, casting tensors of the following
+ * {@link OperandCode} to the same {@link OperandCode} is supported:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: A tensor with the same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_CAST = 45,
+
+ /**
+ * Shuffle the channels of the input tensor.
+ *
+ * Given an input tensor and a integer value of num_groups, CHANNEL_SHUFFLE
+ * divide the channel dimension into num_groups groups, and reorganize the
+ * channels by grouping channels with the same index in each group.
+ *
+ * Along the channel dimension, the output is calculated using this formula:
+ *
+ * output_channel[k * num_groups + g] = input_channel[g * group_size + k]
+ *
+ * where group_size = num_channels / num_groups
+ *
+ * The number of channels must be divisible by num_groups.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the tensor to be shuffled.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the number of
+ * groups.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the dimension
+ * channel shuffle would be performed on. Negative index is used to
+ * specify axis from the end (e.g. -1 for the last axis). Must be in
+ * the range [-n, n).
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} and same shape as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_CHANNEL_SHUFFLE = 46,
+
+ /**
+ * Apply postprocessing steps to bounding box detections.
+ *
+ * Bounding box detections are generated by applying transformation on a set
+ * of predefined anchors with the bounding box deltas from bounding box
+ * regression. A final step of hard NMS is applied to limit the number of
+ * returned boxes.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Inputs:
+ * * 0: A 3-D Tensor of shape [batches, num_anchors, num_classes], specifying
+ * the score of each anchor with each class. Class 0 for each
+ * [batches, num_anchors, 0] is background and will be ignored.
+ * * 1: A 3-D Tensor of shape [batches, num_anchors, length_box_encoding], with
+ * the first four values in length_box_encoding specifying the bounding
+ * box deltas. The box deltas are encoded in the order of [dy, dx, dh, dw],
+ * where dy and dx is the linear-scale relative correction factor for the
+ * center position of the bounding box with respect to the width and height,
+ * dh and dw is the log-scale relative correction factor for the width and
+ * height. All the entries in length_box_encoding beyond the first four
+ * values are ignored in this operation.
+ * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each
+ * predefined anchor, with format [ctr_y, ctr_x, h, w], where ctr_y and
+ * ctr_x are the center position of the box, and h and w are the height
+ * and the width.
+ * * 3: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the scaling
+ * factor for dy in bounding box deltas.
+ * * 4: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the scaling
+ * factor for dx in bounding box deltas.
+ * * 5: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the scaling
+ * factor for dh in bounding box deltas.
+ * * 6: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the scaling
+ * factor for dw in bounding box deltas.
+ * * 7: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to use regular
+ * multi-class NMS algorithm that do NMS separately for each class,
+ * set to false for a faster algorithm that only do one single NMS
+ * using the highest class score..
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, max_num_detections, specifying
+ * the maximum number of boxes for the output. Boxes with the lowest
+ * scores are discarded to meet the limit.
+ * * 9: An {@link ANEURALNETWORKS_INT32} scalar, only used when input7 is
+ * set to false, specifying the maximum number of classes per detection.
+ * * 10: An {@link ANEURALNETWORKS_INT32} scalar, only used when input7 is
+ * set to true, specifying the maximum number of detections when
+ * applying NMS algorithm for each single class.
+ * * 11: A scalar, score_threshold. Boxes with scores lower than the
+ * threshold are filtered before sending to the NMS algorithm. The
+ * scalar must be of {@link ANEURALNETWORKS_FLOAT16} if input0 is of
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} if input0 is of
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32}.
+ * * 12: A scalar, specifying the IoU threshold for hard NMS. The scalar
+ * must be of {@link ANEURALNETWORKS_FLOAT16} if input0 is of
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} if input0 is of
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32}.
+ * * 13: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to include
+ * background class in the list of label map for the output, set
+ * to false to not include the background. When the background
+ * class is included, it has label 0 and the output classes start
+ * at 1 in the label map, otherwise, the output classes start at 0.
+ *
+ * Outputs:
+ * * 0: A 2-D tensor of the same {@link OperandCode} as input0, with shape
+ * [batches, max_num_detections], specifying the score of each output
+ * detections.
+ * * 1: A 3-D tensor of shape [batches, max_num_detections, 4], specifying the
+ * coordinates of each output bounding box, with format
+ * [y1, x1, y2, x2].
+ * * 2: A 2-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape
+ * [batches, max_num_detections], specifying the class label for each
+ * output detection.
+ * * 3: An 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape [batches],
+ * specifying the number of valid output detections for each batch.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_DETECTION_POSTPROCESSING = 47,
+
+ /**
+ * For input tensors x and y, computes x == y elementwise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * This operation supports broadcasting.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode} and dimensions compatible
+ * with input0.
+ *
+ * Outputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_EQUAL = 48,
+
+ /**
+ * Computes exponential of x element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_EXP = 49,
+
+ /**
+ * Inserts a dimension of 1 into a tensor's shape.
+ *
+ * Given a tensor input, this operation inserts a dimension of 1 at the
+ * given dimension index of input's shape. The dimension index starts at
+ * zero; if you specify a negative dimension index, it is counted backward
+ * from the end.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: An n-D tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar specifying the dimension
+ * index to expand. Must be in the range [-(n + 1), (n + 1)).
+ *
+ * Outputs:
+ * * 0: An (n + 1)-D tensor with the same {@link OperandCode} and data as
+ * input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_EXPAND_DIMS = 50,
+
+ /**
+ * Gathers values along an axis.
+ *
+ * Produces an output tensor with shape
+ * input0.dimension[:axis] + indices.dimension + input0.dimension[axis + 1:]
+ * where:
+ * # Vector indices (output is rank(input0)).
+ * output[a_0, ..., a_n, i, b_0, ..., b_n] =
+ * input0[a_0, ..., a_n, indices[i], b_0, ..., b_n]
+ *
+ * # Higher rank indices (output is rank(input0) + rank(indices) - 1).
+ * output[a_0, ..., a_n, i, ..., j, b_0, ... b_n] =
+ * input0[a_0, ..., a_n, indices[i, ..., j], b_0, ..., b_n]
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: An n-D tensor from which to gather values.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar specifying the axis.
+ * Negative index is used to specify axis from the end
+ * (e.g. -1 for the last axis). Must be in the range [-n, n).
+ * * 2: A k-D tensor {@link ANEURALNETWORKS_TENSOR_INT32} of indices.
+ * The values must be in the bounds of the corresponding dimensions
+ * of input0.
+ *
+ * Outputs:
+ * * 0: An (n + k - 1)-D tensor with the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_GATHER = 51,
+
+ /**
+ * Generate aixs-aligned bounding box proposals.
+ *
+ * Bounding box proposals are generated by applying transformation on a set
+ * of predefined anchors with the bounding box deltas from bounding box
+ * regression. A final step of hard NMS is applied to limit the number of
+ * returned boxes.
+ *
+ * Axis-aligned bounding boxes are represented by its upper-left corner
+ * coordinate (x1,y1) and lower-right corner coordinate (x2,y2). A valid
+ * bounding box should satisfy x1 <= x2 and y1 <= y2.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Inputs:
+ * * 0: A 4-D Tensor specifying the score of each anchor at each
+ * location. With "NHWC" data layout, the tensor shape is
+ * [batches, height, width, num_anchors]. With "NCHW" data layout,
+ * the tensor shape is [batches, num_anchors, height, width].
+ * * 1: A 4-D Tensor specifying the bounding box deltas. With "NHWC" data
+ * layout, the tensor shape is [batches, height, width, num_anchors * 4].
+ * With "NCHW" data layout, the tensor shape is
+ * [batches, num_anchors * 4, height, width]. The box deltas are encoded
+ * in the order of [dx, dy, dw, dh], where dx and dy is the linear-scale
+ * relative correction factor for the center position of the bounding box
+ * with respect to the width and height, dw and dh is the log-scale
+ * relative correction factor for the width and height. The last
+ * dimensions is the channel dimension.
+ * * 2: A 2-D Tensor of shape [num_anchors, 4], specifying the shape of each
+ * predefined anchor, with format [x1, y1, x2, y2]. For input0 of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, this tensor should be of
+ * {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}, with scale of 0.125.
+ * * 3: A 2-D Tensor of shape [batches, 2], specifying the size of
+ * each image in the batch, with format [image_height, image_width].
+ * For input0 of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, this
+ * tensor should be of {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}, with
+ * scale of 0.125.
+ * * 4: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the ratio
+ * from the height of original image to the height of feature map.
+ * * 5: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the ratio
+ * from the width of original image to the width of feature map.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the maximum
+ * number of boxes before going into the hard NMS algorithm. Boxes
+ * with the lowest scores are discarded to meet the limit. Set to
+ * a non-positive value for unlimited number.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the maximum
+ * number of boxes returning from the hard NMS algorithm. Boxes
+ * with the lowest scores are discarded to meet the limit. Set to
+ * a non-positive value for unlimited number.
+ * * 8: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the IoU
+ * threshold for hard NMS.
+ * * 9: An {@link ANEURALNETWORKS_FLOAT32} scalar, min_size. Boxes with
+ * height or width lower than the absolute threshold are filtered out.
+ * * 10: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0 and input1. Set to false for NHWC.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0, of shape
+ * [num_output_rois], specifying the score of each output box.
+ * The boxes are grouped by batches, but the sequential order in
+ * each batch is not guaranteed. For type of
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, the scale and zero
+ * point must be the same as input0.
+ * * 1: A tensor of the same {@link OperandCode} as input3, of shape
+ * [num_output_rois, 4], specifying the coordinates of each output
+ * bounding box for each class, with format [x1, y1, x2, y2].
+ * The sequential order of the boxes corresponds with output0.
+ * For type of {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, the
+ * scale must be 0.125 and the zero point must be 0.
+ * * 2: A 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape
+ * [num_output_rois], specifying the batch index of each box. Boxes
+ * with the same batch index are grouped together.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_GENERATE_PROPOSALS = 52,
+
+ /**
+ * For input tensors x and y, computes x > y elementwise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * This operation supports broadcasting.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode} and dimensions compatible
+ * with input0.
+ *
+ * Outputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_GREATER = 53,
+ /**
+ * For input tensors x and y, computes x >= y elementwise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * This operation supports broadcasting.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode} and dimensions compatible
+ * with input0.
+ *
+ * Outputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_GREATER_EQUAL = 54,
+
+ /**
+ * Performs a grouped 2-D convolution operation.
+ *
+ * Given an input tensor of shape [batches, height, width, depth_in] and a
+ * filter tensor of shape [depth_out, filter_height, filter_width, depth_group]
+ * containing depth_out convolutional filters of depth depth_group, GROUPED_CONV
+ * applies a group of different filters to each input channel group, then
+ * concatenates the results together.
+ *
+ * Specifically, the input channels are divided into num_groups groups, each with
+ * depth depth_group, i.e. depth_in = num_groups * depth_group. The convolutional
+ * filters are also divided into num_groups groups, i.e. depth_out is divisible
+ * by num_groups. GROUPED_CONV applies each group of filters to the corresponding
+ * input channel group, and the result are concatenated together.
+ *
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
+ *
+ * output[b, i, j, g * channel_multiplier + q] =
+ * sum_{di, dj, dk} (
+ * input[b, strides[1] * i + di, strides[2] * j + dj,
+ * g * depth_group + dk] *
+ * filter[g * channel_multiplier + q, di, dj, dk]
+ * ) + bias[channel]
+ *
+ * where channel_multiplier = depth_out / num_groups
+ *
+ * Supported tensor {@link OperandCode} configurations:
+ * * 16 bit floating point:
+ * * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} for input, filter, output, and bias.
+ *
+ * * 32 bit floating point:
+ * * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} for input, filter, output, and bias.
+ *
+ * * Quantized:
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} for input, filter, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized signed (since API level 30):
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized with symmetric per channel quantization for the filter:
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} for input, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
+ * * Quantized signed with filter symmetric per channel quantization (since API level 30):
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ *
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input, where depth_in = num_groups * depth_group.
+ * * 1: A 4-D tensor, of shape
+ * [depth_out, filter_height, filter_width, depth_group], specifying
+ * the filter, where depth_out must be divisible by num_groups. For
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}
+ * the channel dimension (channelDim at
+ * {@link ANeuralNetworksSymmPerChannelQuantParams}) must be set to 0.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32} or
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the bias must be of the same type.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint
+ * of 0 and bias_scale == input_scale * filter_scale. For filter tensor
+ * of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+ * should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of
+ * 0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 9: An {@link ANEURALNETWORKS_INT32} scalar, specifying the number of
+ * groups.
+ * * 10: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 11: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0 and output0. Set to false for NHWC.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input, where depth_in = num_groups * depth_group.
+ * * 1: A 4-D tensor, of shape
+ * [depth_out, filter_height, filter_width, depth_group], specifying
+ * the filter, where depth_out must be divisible by num_groups. For
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}
+ * the channel dimension (ANeuralNetworksSymmPerChannelQuantParams::channelDim)
+ * must be set to 0.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32} or
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the bias must be of the same
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the bias must be of the same type.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint
+ * of 0 and bias_scale == input_scale * filter_scale. For filter tensor
+ * of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}, the bias
+ * should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of
+ * 0 and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * {@link PaddingCode} values.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the number of
+ * groups.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 8: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0 and output0. Set to false for NHWC.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth_out].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_GROUPED_CONV_2D = 55,
+
+ /**
+ * Localize the maximum keypoints from heatmaps.
+ *
+ * This operation approximates the accurate maximum keypoint scores and
+ * indices after bicubic upscaling by using Taylor expansion up to the
+ * quadratic term.
+ *
+ * The bounding box is represented by its upper-left corner coordinate
+ * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+ * A valid bounding box should satisfy x1 <= x2 and y1 <= y2.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ *
+ * Inputs:
+ * * 0: A 4-D Tensor of shape
+ * [num_boxes, heatmap_size, heatmap_size, num_keypoints],
+ * specifying the heatmaps, the height and width of heatmaps should
+ * be the same, and must be greater than or equal to 2.
+ * * 1: A 2-D Tensor of shape [num_boxes, 4], specifying the bounding boxes,
+ * each with format [x1, y1, x2, y2]. For input0 of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, this tensor should
+ * be of {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, with zeroPoint
+ * of 0 and scale of 0.125.
+ * For input0 of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, this tensor
+ * should be of {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, with
+ * zeroPoint of -128 and scale of 0.125.
+ * * 2: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0. Set to false for NHWC.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0, with shape
+ * [num_boxes, num_keypoints], specifying score of the keypoints.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint can be different from input0 scale and zeroPoint.
+ * * 1: A tensor of the same {@link OperandCode} as input1, with shape
+ * [num_boxes, num_keypoints, 2], specifying the location of
+ * the keypoints, the second dimension is organized as
+ * [keypoint_x, keypoint_y].
+ * For type of {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, the
+ * scale must be 0.125 and the zero point must be 0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_HEATMAP_MAX_KEYPOINT = 56,
+
+ /**
+ * Applies instance normalization to the input tensor.
+ *
+ * The values in the output tensor are computed as:
+ *
+ * output[b, h, w, c] =
+ * (input[b, h, w, c] - mean[b, c]) * gamma /
+ * sqrt(var[b, c] + epsilon) + beta
+ *
+ * Where the mean and variance are computed across the spatial dimensions:
+ *
+ * mean[b, c] =
+ * sum_{h, w}(input[b, h, w, c]) / sum(1)
+ *
+ * var[b, c] =
+ * sum_{h, w}(pow(input[b, h, w, c] - mean[b, c], 2)) / sum(1)
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the tensor to be normalized.
+ * * 1: A scalar, specifying gamma, the scale applied to the normalized
+ * tensor. The scalar must be of {@link ANEURALNETWORKS_FLOAT16} if
+ * input0 is of {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} if input0 is of
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32}.
+ * * 2: A scalar, specifying beta, the offset applied to the normalized
+ * tensor. The scalar must be of {@link ANEURALNETWORKS_FLOAT16} if
+ * input0 is of {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} if input0 is of
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32}.
+ * * 3: A scalar, specifying epsilon, the small value added to variance to
+ * avoid dividing by zero. The scalar must be of {@link ANEURALNETWORKS_FLOAT16} if
+ * input0 is of {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} if input0 is of
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32}.
+ * * 4: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0 and output0. Set to false for NHWC.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} and same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_INSTANCE_NORMALIZATION = 57,
+
+ /**
+ * For input tensors x and y, computes x < y elementwise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * This operation supports broadcasting.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode} and dimensions compatible
+ * with input0.
+ *
+ * Outputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_LESS = 58,
+
+ /**
+ * For input tensors x and y, computes x <= y elementwise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * This operation supports broadcasting.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode} and dimensions compatible
+ * with input0.
+ *
+ * Outputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_LESS_EQUAL = 59,
+
+ /**
+ * Computes natural logarithm of x element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_LOG = 60,
+
+ /**
+ * Returns the truth value of x AND y element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ *
+ * Supported tensor rank: from 1
+ *
+ * This operation supports broadcasting.
+ *
+ * Inputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ * * 1: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8} and dimensions
+ * compatible with input0.
+ *
+ * Outputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_LOGICAL_AND = 61,
+
+ /**
+ * Computes the truth value of NOT x element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_LOGICAL_NOT = 62,
+
+ /**
+ * Returns the truth value of x OR y element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ *
+ * Supported tensor rank: from 1
+ *
+ * This operation supports broadcasting.
+ *
+ * Inputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ * * 1: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8} and dimensions
+ * compatible with input0.
+ *
+ * Outputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_LOGICAL_OR = 63,
+
+ /**
+ * Computes the log softmax activations given logits.
+ *
+ * The output is calculated using this formula:
+ *
+ * output = logits * beta - log(reduce_sum(exp(logits * beta), axis))
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor specifying the input logits.
+ * * 1: A scalar, specifying the positive scaling factor for the exponent,
+ * beta.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the beta
+ * value must be of {@link ANEURALNETWORKS_FLOAT16}.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32}, the beta
+ * value must be of {@link ANEURALNETWORKS_FLOAT32}.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar specifying the axis to
+ * reduce across. Negative index is used to specify axis from the
+ * end (e.g. -1 for the last axis). Must be in the range [-n, n).
+ *
+ * Outputs:
+ * * 0: The output tensor of the same {@link OperandCode} and shape as
+ * input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_LOG_SOFTMAX = 64,
+
+ /**
+ * Returns the element-wise maximum of two tensors.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode} and compatible dimensions
+ * with input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor,
+ * the scales and zeroPoint can be different from input0 scale and zeroPoint.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor,
+ * the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_MAXIMUM = 65,
+
+ /**
+ * Returns the element-wise minimum of two tensors.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode} and compatible dimensions
+ * with input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor,
+ * the scales and zeroPoint can be different from input0 scale and zeroPoint.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor,
+ * the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_MINIMUM = 66,
+
+ /**
+ * Computes numerical negative value element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_NEG = 67,
+
+ /**
+ * For input tensors x and y, computes x != y elementwise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * This operation supports broadcasting.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandCode} and dimensions compatible
+ * with input0.
+ *
+ * Outputs:
+ * * 0: A tensor of {@link ANEURALNETWORKS_TENSOR_BOOL8}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_NOT_EQUAL = 68,
+
+ /**
+ * Pads a tensor with the given constant value according to the specified
+ * paddings.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the tensor to be padded.
+ * * 1: A 2-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the paddings
+ * for each spatial dimension of the input tensor. The shape of the
+ * tensor must be {rank(input0), 2}.
+ * padding[i, 0] specifies the number of elements to be padded in the
+ * front of dimension i.
+ * padding[i, 1] specifies the number of elements to be padded after
+ * the end of dimension i.
+ * * 2: An scalar specifying the value to use for padding input0.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the
+ * pad value must be of {@link ANEURALNETWORKS_FLOAT16}.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32}, the
+ * pad value must be of {@link ANEURALNETWORKS_FLOAT32}.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the pad value must be of {@link ANEURALNETWORKS_INT32}. The
+ * scale and zeroPoint are assumed to be the same as in input0.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0. The
+ * output tensor has the same rank as input0, and each
+ * dimension of the output tensor has the same size as the
+ * corresponding dimension of the input tensor plus the size
+ * of the padding:
+ * output0.dimension[i] =
+ * padding[i, 0] + input0.dimension[i] + padding[i, 1]
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_PAD_V2 = 69,
+
+ /**
+ * Computes the power of one value to another.
+ *
+ * Given a tensor base and a tensor exponent, this operation computes
+ * base^exponent elementwise.
+ *
+ * This operations supports broadcasting. The size of the output is the
+ * maximum size along each dimension of the input operands. It starts with
+ * the trailing dimensions, and works its way forward.
+ *
+ * For example:
+ * base.dimension = {4, 1, 2}
+ * exponent.dimension = {5, 4, 3, 1}
+ * output.dimension = {5, 4, 3, 2}
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: A tensor specifying the base.
+ * * 1: A tensor specifying the exponent.
+ *
+ * Outputs:
+ * * 0: An output tensor.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_POW = 70,
+
+ /**
+ * Parametric Rectified Linear Unit.
+ *
+ * It follows: f(x) = alpha * x for x < 0, f(x) = x for x >= 0, where alpha
+ * is a learned array with the same {@link OperandCode} and compatible
+ * dimensions as input x.
+ *
+ * Two dimensions are compatible when:
+ * 1. they are equal, or
+ * 2. one of them is 1
+ *
+ * The size of the output is the maximum size along each dimension of the
+ * input operands. It starts with the trailing dimensions, and works its way
+ * forward.
+ *
+ * Example:
+ * input.dimension = {4, 1, 2}
+ * alpha.dimension = {5, 4, 3, 1}
+ * output.dimension = {5, 4, 3, 2}
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input.
+ * * 1: A tensor of the same {@link OperandCode}, and compatible dimensions
+ * as input0, specifying the alpha.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scales and zeroPoint can be different from input0 scale and zeroPoint.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_PRELU = 71,
+
+ /**
+ * Quantizes the input tensor.
+ *
+ * The formula for {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} output tensor is:
+ *
+ * output = max(0, min(255, round(input / scale) + zeroPoint)
+ *
+ * The formula for {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} output
+ * tensor is:
+ *
+ * output = max(-128, min(127, round(input / scale) + zeroPoint)
+ *
+ * Supported input tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported output tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: A tensor, may be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0, but with
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or.
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_QUANTIZE = 72,
+
+ /**
+ * A version of quantized LSTM, using 16 bit quantization for internal
+ * state.
+ *
+ * There is no projection layer, so cell state size is equal to the output
+ * size.
+ *
+ * Inputs:
+ * * 0: A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [numBatches, inputSize] specifying the input to the LSTM
+ * cell. Tensor is quantized with a fixed quantization range of
+ * [-1, 127/128] (scale = 1/128, zeroPoint = 128).
+ * * 1: The input-to-input weights.
+ * A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [outputSize, inputSize] specifying input-to-input part of
+ * weights for fully-connected layer inside the LSTM cell.
+ * Quantization zero point and scale must be the same across all the
+ * weights.
+ * * 2: The input-to-forget weights.
+ * A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [outputSize, inputSize] specifying input-to-forget part of
+ * weights for fully-connected layer inside the LSTM cell.
+ * Quantization zero point and scale must be the same across all the
+ * weights.
+ * * 3: The input-to-cell weights.
+ * A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [outputSize, inputSize] specifying input-to-cell part of
+ * weights for fully-connected layer inside the LSTM cell.
+ * Quantization zero point and scale must be the same across all the
+ * weights.
+ * * 4: The input-to-output weights.
+ * A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [outputSize, inputSize] specifying input-to-output part of
+ * weights for fully-connected layer inside the LSTM cell.
+ * Quantization zero point and scale must be the same across all the
+ * weights.
+ * * 5: The recurrent-to-input weights.
+ * A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [outputSize, outputSize] specifying recurrent-to-input part
+ * of weights for fully-connected layer inside the LSTM cell.
+ * Quantization zero point and scale must be the same across all the
+ * weights.
+ * * 6: The recurrent-to-forget weights.
+ * A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [outputSize, outputSize] specifying recurrent-to-forget
+ * part of weights for fully-connected layer inside the LSTM cell.
+ * Quantization zero point and scale must be the same across all the
+ * weights.
+ * * 7: The recurrent-to-cell weights.
+ * A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [outputSize, outputSize] specifying recurrent-to-cell part
+ * of weights for fully-connected layer inside the LSTM cell.
+ * Quantization zero point and scale must be the same across all the
+ * weights.
+ * * 8: The recurrent-to-output weights.
+ * A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [outputSize, outputSize] specifying recurrent-to-output
+ * part of weights for fully-connected layer inside the LSTM cell.
+ * Quantization zero point and scale must be the same across all the
+ * weights.
+ * * 9: The input gate bias.
+ * A 1-D tensor of type {@link ANEURALNETWORKS_TENSOR_INT32} and shape
+ * [outputSize] specifying the bias for the fully-connected layer
+ * inside the LSTM cell. Bias is quantized with scale being a product
+ * of input and weights scales and zeroPoint equal to 0.
+ * * 10:The forget gate bias.
+ * A 1-D tensor of type {@link ANEURALNETWORKS_TENSOR_INT32} and shape
+ * [outputSize] specifying the bias for the fully-connected layer
+ * inside the LSTM cell. Bias is quantized with scale being a product
+ * of input and weights scales and zeroPoint equal to 0.
+ * * 11:The cell bias.
+ * A 1-D tensor of type {@link ANEURALNETWORKS_TENSOR_INT32} and shape
+ * [outputSize] specifying the bias for the fully-connected layer
+ * inside the LSTM cell. Bias is quantized with scale being a product
+ * of input and weights scales and zeroPoint equal to 0.
+ * * 12:The output gate bias.
+ * A 1-D tensor of type {@link ANEURALNETWORKS_TENSOR_INT32} and shape
+ * [outputSize] specifying the bias for the fully-connected layer
+ * inside the LSTM cell. Bias is quantized with scale being a product
+ * of input and weights scales and zeroPoint equal to 0.
+ * * 13: A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * and shape [numBatches, outputSize] specifying the cell state from the
+ * previous time step of the LSTM cell. It is quantized using a
+ * quantization range of [-2^4, 2^4 * 32767/32768] (scale = 2^4 /
+ * 32768, zeroPoint = 0).
+ * * 14: A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [numBathes, outputSize] specifying the output of the LSTM
+ * cell from previous time-step. Tensor is quantized with a fixed
+ * quantization range of [-1, 127/128] (scale = 1/128, zeroPoint =
+ * 128).
+ *
+ *
+ * Outputs:
+ * * 0: A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * and shape [numBatches, outputSize] which contains a cell state from
+ * the current time step. Tensor is quantized using a quantization
+ * range of [-2^4, 2^4 * 32767/32768] (scale = 2^4 / 32768, zeroPoint =
+ * 0).
+ * * 1: A 2-D tensor of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and shape [numBathes, outputSize] which contains the output value.
+ * Tensor is quantized with a fixed quantization range of [-1, 127/128]
+ * (scale = 1/128, zeroPoint = 128).
+ */
+ ANEURALNETWORKS_QUANTIZED_16BIT_LSTM = 73,
+
+ /**
+ * Draws samples from a multinomial distribution.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Inputs:
+ * * 0: A 2-D tensor with shape [batches, classes], specifying the
+ * unnormalized log-probabilities for all classes.
+ * * 1: A scalar {@link ANEURALNETWORKS_INT32}, specifying the number of
+ * independent samples to draw for each row slice.
+ * * 2: A 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor with shape [2],
+ * specifying seeds used to initialize the random distribution. If both
+ * provided seeds are 0, both will be randomly generated.
+ * Outputs:
+ * * 0: A 2-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor with shape
+ * [batches, samples], containing the drawn samples.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_RANDOM_MULTINOMIAL = 74,
+
+ /**
+ * Reduces a tensor by computing the "logical and" of elements along given
+ * dimensions.
+ *
+ * If keep_dims is true, the reduced dimensions are
+ * retained with length 1. Otherwise, the rank of the tensor is reduced by
+ * 1 for each entry in dimensions.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor.
+ * * 1: A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The dimensions
+ * to reduce. Dimension values must be in the range [-n, n).
+ * * 2: An {@link ANEURALNETWORKS_BOOL} scalar, keep_dims. If true,
+ * retains reduced dimensions with length 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * If all dimensions are reduced and keep_dims is false, the output
+ * shape is [1].
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_REDUCE_ALL = 75,
+
+ /**
+ * Reduces a tensor by computing the "logical or" of elements along given
+ * dimensions.
+ *
+ * If keep_dims is true, the reduced dimensions are
+ * retained with length 1. Otherwise, the rank of the tensor is reduced by
+ * 1 for each entry in dimensions.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor.
+ * * 1: A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The dimensions
+ * to reduce. Dimension values must be in the range [-n, n).
+ * * 2: An {@link ANEURALNETWORKS_BOOL} scalar, keep_dims. If true,
+ * retains reduced dimensions with length 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * If all dimensions are reduced and keep_dims is false, the output
+ * shape is [1].
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_REDUCE_ANY = 76,
+
+ /**
+ * Reduces a tensor by computing the maximum of elements along given
+ * dimensions.
+ *
+ * If keep_dims is true, the reduced dimensions are
+ * retained with length 1. Otherwise, the rank of the tensor is reduced by
+ * 1 for each entry in dimensions.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor.
+ * * 1: A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The dimensions
+ * to reduce. Dimension values must be in the range [-n, n).
+ * * 2: An {@link ANEURALNETWORKS_BOOL} scalar, keep_dims. If true,
+ * retains reduced dimensions with length 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * If all dimensions are reduced and keep_dims is false, the output
+ * shape is [1].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_REDUCE_MAX = 77,
+
+ /**
+ * Reduces a tensor by computing the minimum of elements along given
+ * dimensions.
+ *
+ * If keep_dims is true, the reduced dimensions are
+ * retained with length 1. Otherwise, the rank of the tensor is reduced by
+ * 1 for each entry in dimensions.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor.
+ * * 1: A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The dimensions
+ * to reduce. Dimension values must be in the range [-n, n).
+ * * 2: An {@link ANEURALNETWORKS_BOOL} scalar, keep_dims. If true,
+ * retains reduced dimensions with length 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * If all dimensions are reduced and keep_dims is false, the output
+ * shape is [1].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_REDUCE_MIN = 78,
+
+ /**
+ * Reduces a tensor by multiplying elements along given dimensions.
+ *
+ * If keep_dims is true, the reduced dimensions are
+ * retained with length 1. Otherwise, the rank of the tensor is reduced by
+ * 1 for each entry in dimensions.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor.
+ * * 1: A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The dimensions
+ * to reduce. Dimension values must be in the range [-n, n).
+ * * 2: An {@link ANEURALNETWORKS_BOOL} scalar, keep_dims. If true,
+ * retains reduced dimensions with length 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * If all dimensions are reduced and keep_dims is false, the output
+ * shape is [1].
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_REDUCE_PROD = 79,
+
+ /**
+ * Reduces a tensor by summing elements along given dimensions.
+ *
+ * If keep_dims is true, the reduced dimensions are
+ * retained with length 1. Otherwise, the rank of the tensor is reduced by
+ * 1 for each entry in dimensions.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor.
+ * * 1: A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The dimensions
+ * to reduce. Dimension values must be in the range [-n, n).
+ * * 2: An {@link ANEURALNETWORKS_BOOL} scalar, keep_dims. If true,
+ * retains reduced dimensions with length 1.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0.
+ * If all dimensions are reduced and keep_dims is false, the output
+ * shape is [1].
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_REDUCE_SUM = 80,
+
+ /**
+ * Select and scale the feature map of each region of interest to a unified
+ * output size by average pooling sampling points from bilinear interpolation.
+ *
+ * The region of interest is represented by its upper-left corner coordinate
+ * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+ * A spatial scaling factor is applied to map into feature map coordinate.
+ * A valid region of interest should satisfy x1 <= x2 and y1 <= y2.
+ *
+ * No rounding is applied in this operation. The sampling points are unified
+ * distributed in the pooling bin and their values are calculated by bilinear
+ * interpolation.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ *
+ * Inputs:
+ * * 0: A 4-D tensor, specifying the feature map.
+ * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of
+ * the regions of interest, each line with format [x1, y1, x2, y2].
+ * For input0 of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM},
+ * this tensor should be of {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM},
+ * with zeroPoint of 0 and scale of 0.125. Zero num_rois is
+ * supported for this tensor.
+ * * 2: An 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape
+ * [num_rois], specifying the batch index of each box. Boxes with
+ * the same batch index are grouped together. Zero num_rois is
+ * supported for this tensor.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the output
+ * height of the output tensor.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the output
+ * width of the output tensor.
+ * * 5: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the ratio
+ * from the height of original image to the height of feature map.
+ * * 6: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the ratio
+ * from the width of original image to the width of feature map.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the number of
+ * sampling points in height dimension used to compute the output.
+ * Set to 0 for adaptive value of ceil(roi_height/out_height).
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, specifying the number of
+ * sampling points in width dimension used to compute the output.
+ * Set to 0 for adaptive value of ceil(roi_width/out_width).
+ * * 9: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0 and output0. Set to false for NHWC.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0. The output
+ * shape is [num_rois, out_height, out_width, depth].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint can be different from the input0 scale and zeroPoint.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_ROI_ALIGN = 81,
+
+ /**
+ * Select and scale the feature map of each region of interest to a unified
+ * output size by max-pooling.
+ *
+ * The region of interest is represented by its upper-left corner coordinate
+ * (x1,y1) and lower-right corner coordinate (x2,y2) in the original image.
+ * A spatial scaling factor is applied to map into feature map coordinate.
+ * A valid region of interest should satisfy x1 <= x2 and y1 <= y2.
+ *
+ * Rounding is applied in this operation to ensure integer boundary for
+ * regions of interest and pooling bins.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ *
+ * Inputs:
+ * * 0: A 4-D tensor, specifying the feature map.
+ * * 1: A 2-D Tensor of shape [num_rois, 4], specifying the locations of
+ * the regions of interest, each line with format [x1, y1, x2, y2].
+ * For input0 of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * this tensor should be of {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM},
+ * with zeroPoint of 0 and scale of 0.125.
+ * * 2: An 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape
+ * [num_rois], specifying the batch index of each box. Boxes with
+ * the same batch index are grouped together.
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the output
+ * height of the output tensor.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the output
+ * width of the output tensor.
+ * * 5: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the ratio
+ * from the height of original image to the height of feature map.
+ * * 6: An {@link ANEURALNETWORKS_FLOAT32} scalar, specifying the ratio
+ * from the width of original image to the width of feature map.
+ * * 7: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0 and output0. Set to false for NHWC.
+ *
+ * Outputs:
+ * * 0: A tensor of the same {@link OperandCode} as input0. The output
+ * shape is [num_rois, out_height, out_width, depth].
+ * For input0 of type {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_ROI_POOLING = 82,
+
+ /**
+ * Computes reciprocal of square root of x element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_RSQRT = 83,
+
+ /**
+ * Using a tensor of booleans c and input tensors x and y select values
+ * elementwise from both input tensors:
+ *
+ * O[i] = C[i] ? x[i] : y[i].
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: A tensor of type {@link ANEURALNETWORKS_TENSOR_BOOL8} acting as a
+ * mask that chooses, based on the value at each element, whether the
+ * corresponding element in the output should be taken from input1 (if
+ * true) or input2 (if false).
+ * * 1: An input tensor of the same shape as input0.
+ * * 2: An input tensor of the same shape and type as input1.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scales and zeroPoint can be different from input1 scale and zeroPoint.
+ *
+ * Outputs:
+ * * 0: A tensor of the same type and shape as input1 and input2.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor,
+ * the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_SELECT = 84,
+
+ /**
+ * Computes sin of x element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_SIN = 85,
+
+ /**
+ * Extracts a slice of specified size from the input tensor starting at a
+ * specified location.
+ *
+ * The starting location is specified as a 1-D tensor containing offsets
+ * for each dimension. The size is specified as a 1-D tensor containing
+ * either size of a slice along corresponding dimension or -1. In the latter
+ * case, all the remaining elements in dimension are included in the slice.
+ *
+ * A sum of begin offset and a size of a slice must not exceed size of a
+ * corresponding dimension.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: An n-D tensor to take slice from, may be zero-sized.
+ * * 1: A 1-D tensor of type {@link ANEURALNETWORKS_TENSOR_INT32} specifying
+ * the beginning indices of the slice in each dimension.
+ * * 2: A 1-D tensor of type {@link ANEURALNETWORKS_TENSOR_INT32} specifying
+ * the size of the slice in each dimension.
+ *
+ * Outputs:
+ * * 0: An n-D tensor of the same type as the input containing the slice.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * its scale and zeroPoint has to be same as the input0 scale and zeroPoint.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_SLICE = 86,
+
+ /**
+ * Splits a tensor along a given axis into num_splits subtensors.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: An n-D tensor to split.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar specifying the axis along
+ * which to split.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar indicating the number of
+ * splits along given axis. Must evenly divide axis size.
+ *
+ * Outputs:
+ * * 0 ~ (num_splits - 1): Resulting subtensors.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_SPLIT = 87,
+
+ /**
+ * Computes square root of x element-wise.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_SQRT = 88,
+
+ /**
+ * Constructs a tensor by tiling a given tensor.
+ *
+ * This operation creates a new tensor by replicating `input` `multiples`
+ * times. The output tensor's i-th dimension has `input.dims(i) * multiples[i]`
+ * elements, and the values of `input` are replicated `multiples[i]` times
+ * along the i-th dimension.
+ * For example, tiling `[a b c d]` by `[2]` produces `[a b c d a b c d]`.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: input, an n-D tensor specifying the input.
+ * * 1: multiples, a 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}.
+ * The length of multiples must be n.
+ *
+ * Outputs:
+ * * 0: A tiled tensor of the same {@link OperandCode} and rank as `input`.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TILE = 89,
+
+ /**
+ * Finds values and indices of the k largest entries for the last dimension.
+ *
+ * Resulting values in each dimensions are sorted in descending order. If
+ * two values are equal, the one with larger index appears first.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: from 1
+ *
+ * Inputs:
+ * * 0: input, an n-D tensor specifying the input.
+ * * 1: k, an {@link ANEURALNETWORKS_INT32} scalar, specifying the number of
+ * top elements to look for along the last dimension.
+ *
+ * Outputs:
+ * * 0: An n-D tensor of the same type as the input, containing the k
+ * largest elements along each last dimensional slice.
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ * * 1: An n-D tensor of type {@link ANEURALNETWORKS_TENSOR_INT32}
+ * containing the indices of values within the last dimension of input.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TOPK_V2 = 90,
+
+ /**
+ * Performs the transpose of 2-D convolution operation.
+ *
+ * This operation is sometimes called "deconvolution" after Deconvolutional
+ * Networks, but is actually the transpose (gradient) of
+ * {@link ANEURALNETWORKS_CONV_2D} rather than an actual deconvolution.
+ *
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * Supported tensor {@link OperandCode} configurations:
+ * * 16 bit floating point:
+ * * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} for input, filter, output, and bias.
+ *
+ * * 32 bit floating point:
+ * * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} for input, filter, output, and bias.
+ *
+ * * Quantized:
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} for input, filter, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized with symmetric per channel quantization for the filter:
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} for input, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
+ * Available since API level 30:
+ * * Quantized signed (since API level 30):
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to
+ * * * input.scale * filter.scale).
+ *
+ * * Quantized signed with filter symmetric per channel quantization (since API level 30):
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
+ * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
+ * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0,
+ * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ *
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: A 4-D tensor, of shape
+ * [depth_out, filter_height, filter_width, depth_in], specifying the
+ * filter. For tensor of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
+ * dimension (ANeuralNetworksSymmPerChannelQuantParams::channelDim) must be set to 0.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32} or
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the bias must be of the
+ * same type.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias must be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
+ * * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 8: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 9: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 10: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0 and output0. Set to false for NHWC.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * Since API level 29, zero batches is supported for this tensor.
+ * * 1: A 4-D tensor, of shape
+ * [depth_out, filter_height, filter_width, depth_in], specifying the
+ * filter. For tensor of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} the channel
+ * dimension (ANeuralNetworksSymmPerChannelQuantParams::channelDim) must be set to 0.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32} or
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT16}, the bias should be of the
+ * same type.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED},
+ * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32},
+ * with zeroPoint of 0 and bias_scale == input_scale * filter_scale.
+ * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL},
+ * the bias must be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of 0
+ * and bias_scale of 0. The actual scale of each value 'i' is equal to
+ * bias_scale[i] = input_scale * filter_scale[i].
+ * * 3: An {@link ANEURALNETWORKS_TENSOR_INT32} tensor, specifying the output
+ * tensor shape.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * {@link PaddingCode} values.
+ * * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 6: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 7: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the
+ * {@link FuseCode} values. Specifies the activation to
+ * invoke on the result.
+ * * 8: An {@link ANEURALNETWORKS_BOOL} scalar, set to true to specify
+ * NCHW data layout for input0 and output0. Set to false for NHWC.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth_out].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint can be different from inputs' scale and zeroPoint.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_TRANSPOSE_CONV_2D = 91,
+
+ /**
+ * A recurrent neural network specified by an LSTM cell.
+ *
+ * Performs (fully) dynamic unrolling of input.
+ *
+ * This Op unrolls the input along the time dimension, and implements the
+ * following operation for each element in the sequence
+ * s = 1...sequence_length:
+ * outputs[s] = projection(state = activation(LSTMOp(inputs[s])))
+ *
+ * Where LSTMOp is the LSTM op as in {@link ANEURALNETWORKS_LSTM},
+ * the "projection" is an optional projection layer from state and output
+ * and the “activation” is the function passed as the
+ * “fused_activation_function” argument (if not “NONE”).
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: 3, either time-major or batch-major.
+ *
+ * All input and output tensors must be of the same type.
+ *
+ * Inputs:
+ * * 0: The input (\f$x_t\f$).
+ * A 3-D tensor of shape:
+ * If time-major: [max_time, batch_size, input_size]
+ * If batch-major: [batch_size, max_time, input_size]
+ * where “max_time” is the number of timesteps (sequence length),
+ * “batch_size” corresponds to the batching dimension, and
+ * “input_size” is the size of the input.
+ * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
+ * A 2-D tensor of shape [num_units, input_size], where “num_units”
+ * corresponds to the number of cell units.
+ * * 2: The input-to-forget weights (\f$W_{xf}\f$).
+ * A 2-D tensor of shape [num_units, input_size].
+ * * 3: The input-to-cell weights (\f$W_{xc}\f$).
+ * A 2-D tensor of shape [num_units, input_size].
+ * * 4: The input-to-output weights (\f$W_{xo}\f$).
+ * A 2-D tensor of shape [num_units, input_size].
+ * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional.
+ * A 2-D tensor of shape [num_units, output_size], where “output_size”
+ * corresponds to either the number of cell units (i.e., “num_units”),
+ * or the second dimension of the “projection_weights”, if defined.
+ * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$).
+ * A 2-D tensor of shape [num_units, output_size].
+ * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$).
+ * A 2-D tensor of shape [num_units, output_size].
+ * * 8: The recurrent-to-output weights (\f$W_{ho}\f$).
+ * A 2-D tensor of shape [num_units, output_size].
+ * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional.
+ * A 1-D tensor of shape [num_units].
+ * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional.
+ * A 1-D tensor of shape [num_units].
+ * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional.
+ * A 1-D tensor of shape [num_units].
+ * * 12:The input gate bias (\f$b_i\f$). Optional.
+ * A 1-D tensor of shape [num_units].
+ * * 13:The forget gate bias (\f$b_f\f$).
+ * A 1-D tensor of shape [num_units].
+ * * 14:The cell bias (\f$b_c\f$).
+ * A 1-D tensor of shape [num_units].
+ * * 15:The output gate bias (\f$b_o\f$).
+ * A 1-D tensor of shape [num_units].
+ * * 16:The projection weights (\f$W_{proj}\f$). Optional.
+ * A 2-D tensor of shape [output_size, num_units].
+ * * 17:The projection bias (\f$b_{proj}\f$). Optional.
+ * A 1-D tensor of shape [output_size].
+ * * 18:The output state (in) (\f$h_{t-1}\f$).
+ * A 2-D tensor of shape [batch_size, output_size].
+ * * 19:The cell state (in) (\f$C_{t-1}\f$).
+ * A 2-D tensor of shape [batch_size, num_units].
+ * * 20:The activation function (\f$g\f$).
+ * A value indicating the activation function:
+ * <ul>
+ * <li>0: None;
+ * <li>1: Relu;
+ * <li>3: Relu6;
+ * <li>4: Tanh;
+ * <li>6: Sigmoid.
+ * </ul>
+ * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such
+ * that values are bound within [-cell_clip, cell_clip]. If set to 0.0
+ * then clipping is disabled.
+ * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the
+ * projection layer, such that values are bound within
+ * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
+ * * 23:Time-major if true, batch-major if false.
+ * * 24:The input layer normalization weights. Optional.
+ * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+ * to activation at input gate.
+ * * 25:The forget layer normalization weights. Optional.
+ * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+ * to activation at forget gate.
+ * * 26:The cell layer normalization weights. Optional.
+ * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+ * to activation at cell gate.
+ * * 27:The output layer normalization weights. Optional.
+ * A 1-D tensor of shape [num_units]. Used to rescale normalized inputs
+ * to activation at output gate.
+ *
+ * Outputs:
+ * * 0: The output (\f$o_t\f$).
+ * A 3-D tensor of shape:
+ * If time-major: [max_time, batch_size, output_size]
+ * If batch-major: [batch_size, max_time, output_size]
+ * * 1: A tensor of shape [batch_size, output_size] containing a hidden
+ * state from the last time step in the sequence. This output is
+ * optional and can be omitted. If this output is present then
+ * output #2 must be present as well.
+ * Available since API level 30.
+ * * 2: A tensor of shape [batch_size, cell_size] containing a cell state
+ * from the last time step in the sequence. This output is optional
+ * and can be omitted.
+ * Available since API level 30.
+ *
+ * Available since API level 29.
+ *
+ * Important: As of API level 29, there is no way to get the output state tensors out and NNAPI
+ * does not maintain internal states. This operator does not support the usage pattern in which
+ * multiple cells are chained and state tensors are propagated.
+ */
+ ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM = 92,
+
+ /**
+ * A recurrent neural network layer that applies a basic RNN cell to a
+ * sequence of inputs.
+ *
+ * This layer unrolls the input along the sequence dimension, and implements
+ * the following operation
+ * for each element in the sequence s = 1...sequence_length:
+ * outputs[s] = state = activation(inputs[s] * input_weights’ + state *
+ * recurrent_weights’ + bias)
+ *
+ * Where:
+ * * “input_weights” is a weight matrix that multiplies the inputs;
+ * * “recurrent_weights” is a weight matrix that multiplies the current
+ * “state” which itself is the output from the previous time step
+ * computation;
+ * * “bias” is a bias vector (added to each output vector in the batch);
+ * * “activation” is the function passed as the “fused_activation_function”
+ * argument (if not “NONE”).
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * The input tensors must all be the same type.
+ *
+ * Inputs:
+ * * 0: input.
+ * A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+ * it is set to 1, then the input has a shape [maxTime, batchSize,
+ * inputSize], otherwise the input has a shape [batchSize, maxTime,
+ * inputSize].
+ * * 1: weights.
+ * A 2-D tensor of shape [numUnits, inputSize].
+ * * 2: recurrent_weights.
+ * A 2-D tensor of shape [numUnits, numUnits].
+ * * 3: bias.
+ * A 1-D tensor of shape [numUnits].
+ * * 4: hidden state
+ * A 2-D tensor of shape [batchSize, numUnits]. Specifies a hidden
+ * state input for the first time step of the computation.
+ * * 5: fusedActivationFunction.
+ * A {@link FuseCode} value indicating the activation function. If
+ * “NONE” is specified then it results in a linear activation.
+ * * 6: timeMajor
+ * An {@link ANEURALNETWORKS_INT32} scalar specifying the shape format
+ * of input and output tensors. Must be set to either 0 or 1.
+ * Outputs:
+ * * 0: output.
+ * A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+ * it is set to 1, then the output has a shape [maxTime, batchSize,
+ * numUnits], otherwise the output has a shape [batchSize, maxTime,
+ * numUnits].
+ * * 1: A tensor of shape [batchSize, numUnits] containing hidden state
+ * from the last time step in the sequence. This output is optional
+ * and can be omitted.
+ * Available since API level 30.
+ *
+ * Available since API level 29.
+ *
+ * Important: As of API level 29, there is no way to get the output state tensors out and NNAPI
+ * does not maintain internal states. This operator does not support the usage pattern in which
+ * multiple cells are chained and state tensors are propagated.
+ */
+ ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_RNN = 93,
+
+ /**
+ * Resizes images to given size using the nearest neighbor interpretation.
+ *
+ * Resized images must be distorted if their output aspect ratio is not the
+ * same as input aspect ratio. The corner pixels of output may not be the
+ * same as corner pixels of input.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30)
+ *
+ * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout.
+ * With the default data layout NHWC, the data is stored in the order of:
+ * [batch, height, width, channels]. Alternatively, the data layout could
+ * be NCHW, the data storage order of: [batch, channels, height, width].
+ *
+ * Both resizing by shape and resizing by scale are supported.
+ *
+ * Inputs (resizing by shape):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input. Zero batches is supported for this tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the output
+ * width of the output tensor.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the output
+ * height of the output tensor.
+ * * 3: An {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * * 4: Align corners. An optional {@link ANEURALNETWORKS_BOOL}
+ * scalar, default to false. If True, the centers of the 4 corner
+ * pixels of the input and output tensors are aligned, preserving the
+ * values at the corner pixels.
+ * Available since API level 30.
+ * * 5: Half pixel centers. An optional {@link ANEURALNETWORKS_BOOL}
+ * scalar, default to false. If True, the pixel centers are assumed to
+ * be at (0.5, 0.5). This is the default behavior of image.resize in
+ * TF 2.0. If this parameter is True, then align_corners parameter
+ * must be False.
+ * Available since API level 30.
+ *
+ * Inputs (resizing by scale):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input. Zero batches is supported for this tensor.
+ * * 1: A scalar, specifying width_scale, the scaling factor of the width
+ * dimension from the input tensor to the output tensor. The output
+ * width is calculated as new_width = floor(width * width_scale).
+ * The scalar must be of {@link ANEURALNETWORKS_FLOAT16} if input0 is
+ * of {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} otherwise.
+ * * 2: A scalar, specifying height_scale, the scaling factor of the height
+ * dimension from the input tensor to the output tensor. The output
+ * height is calculated as new_height = floor(height * height_scale).
+ * The scalar must be of {@link ANEURALNETWORKS_FLOAT16} if input0 is
+ * of {@link ANEURALNETWORKS_TENSOR_FLOAT16} and of
+ * {@link ANEURALNETWORKS_FLOAT32} otherwise.
+ * * 3: An {@link ANEURALNETWORKS_BOOL} scalar, default to false.
+ * Set to true to specify NCHW data layout for input0 and output0.
+ * * 4: Align corners. An optional {@link ANEURALNETWORKS_BOOL}
+ * scalar, default to false. If True, the centers of the 4 corner
+ * pixels of the input and output tensors are aligned, preserving the
+ * values at the corner pixels.
+ * Available since API level 30.
+ * * 5: Half pixel centers. An optional {@link ANEURALNETWORKS_BOOL}
+ * scalar, default to false. If True, the pixel centers are assumed to
+ * be at (0.5, 0.5). This is the default behavior of image.resize in
+ * TF 2.0. If this parameter is True, then align_corners parameter
+ * must be False.
+ * Available since API level 30.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, new_height, new_width, depth].
+ * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor,
+ * the scale and zeroPoint must be the same as input0.
+ *
+ * Available since API level 29.
+ */
+ ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR = 94,
+
+ // Operations below are available since API level 30.
+
+ /**
+ * Quantized version of {@link ANEURALNETWORKS_LSTM}.
+ *
+ * The input and the output use asymmetric quantized types, while the rest
+ * use symmetric ones.
+ *
+ * Inputs:
+ * * 0: The input to the LSTM cell.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ * Shape: [batchSize, inputSize]
+ * * 1: The input-to-input weights. Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [numUnits, inputSize]
+ * * 2: The input-to-forget weights.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [numUnits, inputSize]
+ * * 3: The input-to-cell weights.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [numUnits, inputSize]
+ * * 4: The input-to-output weights.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [numUnits, inputSize]
+ * * 5: The recurrent-to-input weights. Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [numUnits, outputSize]
+ * * 6: The recurrent-to-forget weights.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [numUnits, outputSize]
+ * * 7: The recurrent-to-cell weights.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [numUnits, outputSize]
+ * * 8: The recurrent-to-output weights.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [numUnits, outputSize]
+ * * 9: The cell-to-input weights (for peephole). Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [numUnits]
+ * * 10: The cell-to-forget weights (for peephole). Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [numUnits]
+ * * 11: The cell-to-output weights (for peephole). Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [numUnits]
+ * * 12: The input gate bias. Quantized with scale being the
+ * product of input and weights scales and zeroPoint equal to 0.
+ * Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_INT32}
+ * Shape: [numUnits]
+ * * 13: The forget gate bias. Quantized with scale being the
+ * product of input and weights scales and zeroPoint equal to 0.
+ * Type: {@link ANEURALNETWORKS_TENSOR_INT32}
+ * Shape: [numUnits]
+ * * 14: The cell bias. Quantized with scale being the
+ * product of input and weights scales and zeroPoint equal to 0.
+ * Type: {@link ANEURALNETWORKS_TENSOR_INT32}
+ * Shape: [numUnits]
+ * * 15: The output gate bias. Quantized with scale being the
+ * product of input and weights scales and zeroPoint equal to 0.
+ * Type: {@link ANEURALNETWORKS_TENSOR_INT32}
+ * Shape: [numUnits]
+ * * 16: The projection weights. Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * Shape: [outputSize, numUnits]
+ * * 17: The projection bias. Quantized with scale being the
+ * product of input and weights scales and zeroPoint equal to 0.
+ * Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_INT32}
+ * Shape: [outputSize]
+ * * 18: The output from the previous time step.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ * Shape: [batchSize, outputSize]
+ * * 19: The cell state from the previous time step.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [batchSize, numUnits]
+ * * 20: The input layer normalization weights. Used to rescale
+ * normalized inputs to activation at input gate. Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [numUnits]
+ * * 21: The forget layer normalization weights. Used to
+ * rescale normalized inputs to activation at forget gate. Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [numUnits]
+ * * 22: The cell layer normalization weights. Used to rescale
+ * normalized inputs to activation at cell gate. Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [numUnits]
+ * * 23: The output layer normalization weights. Used to
+ * rescale normalized inputs to activation at output gate. Optional.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [numUnits]
+ * * 24: The cell clip. If provided the cell state is clipped
+ * by this value prior to the cell output activation. Optional.
+ * Type: {@link ANEURALNETWORKS_FLOAT32}.
+ * * 25: The projection clip. If provided and projection is enabled,
+ * this is used for clipping the projected values. Optional.
+ * Type: {@link ANEURALNETWORKS_FLOAT32}.
+ * * 26: The scale of the intermediate result of matmul,
+ * i.e. input to layer normalization, at input gate.
+ * Type: {@link ANEURALNETWORKS_FLOAT32}.
+ * * 27: The scale of the intermediate result of matmul,
+ * i.e. input to layer normalization, at forget gate.
+ * Type: {@link ANEURALNETWORKS_FLOAT32}.
+ * * 28: The scale of the intermediate result of matmul,
+ * i.e. input to layer normalization, at cell gate.
+ * Type: {@link ANEURALNETWORKS_FLOAT32}.
+ * * 29: The scale of the intermediate result of matmul,
+ * i.e. input to layer normalization, at output gate.
+ * Type: {@link ANEURALNETWORKS_FLOAT32}.
+ * * 30: The zero point of the hidden state, i.e. input to
+ * projection.
+ * Type: {@link ANEURALNETWORKS_INT32}.
+ * * 31: The scale of the hidden state, i.e. input to
+ * projection.
+ * Type: {@link ANEURALNETWORKS_FLOAT32}.
+ *
+ * Outputs:
+ * * 0: The output state (out).
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ * Shape: [batchSize, outputSize]
+ * * 1: The cell state (out).
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * Shape: [batchSize, numUnits]
+ * * 2: The output. This is effectively the same as the current
+ * "output state (out)" value.
+ * Type: {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ * Shape: [batchSize, outputSize]
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_QUANTIZED_LSTM = 95,
+
+ /**
+ * Executes one of the two referenced models as determined by a boolean
+ * value.
+ *
+ * The inputs and outputs of the two referenced models must agree with the
+ * signature of this operation. That is, if the operation has (3 + n) inputs
+ * and m outputs, both models must have n inputs and m outputs with the same
+ * types, ranks (if specified), dimensions (if specified), scales,
+ * zeroPoints, and other operand parameters as the corresponding operation
+ * inputs and outputs.
+ *
+ * Inputs:
+ * * 0: A value of type {@link ANEURALNETWORKS_TENSOR_BOOL8} and shape [1]
+ * that determines which of the two referenced models to execute.
+ * The operand must have fully specified dimensions.
+ * * 1: A {@link ANEURALNETWORKS_MODEL} reference to the model to be
+ * executed if the condition is true.
+ * * 2: A {@link ANEURALNETWORKS_MODEL} reference to the model to be
+ * executed if the condition is false.
+ * * 3 ~ (n + 2): Inputs to be passed to the model selected for execution.
+ *
+ * Outputs:
+ * * 0 ~ (m - 1): Outputs produced by the selected model.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_IF = 96,
+
+ /**
+ * Executes the body model until the condition model outputs false.
+ *
+ * The inputs to this operation are the condition model, the body model,
+ * and operand values for the first iteration of the loop. The values are
+ * implicitly split into three groups of input-output, state-only, and
+ * input-only values, as described below.
+ *
+ * The outputs of this operation are the final values of input-output
+ * operands.
+ *
+ * Both the condition and body model receive (m + k + n) inputs.
+ * * The first m (m >= 1) inputs are input-output operands. For the first
+ * iteration, these are initialized from the corresponding inputs of the
+ * WHILE operation. In subsequent iterations, their values come from the
+ * corresponding outputs of the body model produced during the previous
+ * iteration.
+ * * The next k (k >= 0) inputs are state-only operands. They are similar to
+ * the input-output operands, except that their values are no longer
+ * available after the loop terminates.
+ * * The last n (n >= 0) inputs are input-only operands. Their values come
+ * from the corresponding inputs of the WHILE operation.
+ *
+ * The body model produces (m + k) outputs.
+ * * The first m outputs are input-output operands. They become the outputs
+ * of the WHILE operation when a termination condition is reached.
+ * * The last k outputs are state-only operands. Their values are no longer
+ * available after the loop terminates.
+ *
+ * The numbers m, k, and n are inferred by the runtime as follows:
+ * m = (WHILE operation output count)
+ * k = (body model output count) - m
+ * n = (body model input count) - m - k
+ *
+ * The pseudo-code below illustrates the flow of a WHILE operation with
+ * inputs condition, body, initial_input_output, initial_state, input_only
+ * (m = 1, k = 1, n = 1):
+ *
+ * input_output = initial_input_output
+ * state = initial_state
+ * while condition(input_output, state, input_only):
+ * input_output, state = body(input_output, state, input_only)
+ * return input_output
+ *
+ * To prevent infinite loops, there is an implicit execution timeout
+ * associated with each loop ("loop timeout duration"). See {@link
+ * ANeuralNetworksExecution_setLoopTimeout}.
+ *
+ * Inputs:
+ * * 0: A {@link ANEURALNETWORKS_MODEL} reference to the condition
+ * model. The model must have (m + k + n) inputs with
+ * the same types, ranks (if specified), dimensions (if specified),
+ * scales, zeroPoints, and other operand parameters as the
+ * corresponding inputs of the WHILE operation and exactly one output
+ * of {@link ANEURALNETWORKS_TENSOR_BOOL8} and shape [1].
+ * The output operand must have fully specified dimensions.
+ * * 1: A {@link ANEURALNETWORKS_MODEL} reference to the body model.
+ * The model must have (m + k + n) inputs and (m + k) outputs with
+ * the same types, ranks (if specified), dimensions (if specified),
+ * scales, zeroPoints, and other operand parameters as the
+ * corresponding inputs and outputs of the WHILE operation.
+ * * (m inputs): Initial values for input-output operands.
+ * * (k inputs): Initial values for state-only operands.
+ * * (n inputs): Values for input-only operands.
+ *
+ * Outputs:
+ * * 0 ~ (m - 1): Outputs produced by the loop.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_WHILE = 97,
+
+ /**
+ * Computes exponential linear activation on the input tensor element-wise.
+ *
+ * The output is calculated using the following formula:
+ *
+ * ELU(x) = max(0, x) + min(0, alpha * (exp(x) - 1))
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input. May be zero-sized.
+ * * 1: A scalar, specifying the alpha parameter.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT16},
+ * the alpha value must be of {@link ANEURALNETWORKS_FLOAT16}.
+ * For input tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32},
+ * the alpha value must be of {@link ANEURALNETWORKS_FLOAT32}.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape and type as input0.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_ELU = 98,
+
+ /**
+ * Computes hard-swish activation on the input tensor element-wise.
+ *
+ * Hard swish activation is introduced in
+ * https://arxiv.org/pdf/1905.02244.pdf
+ *
+ * The output is calculated using the following formula:
+ *
+ * h-swish(x) = x * max(0, min(6, (x + 3))) / 6
+
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A tensor, specifying the input. May be zero-sized.
+ *
+ * Outputs:
+ * * 0: The output tensor of same shape and type as input0.
+ * Scale and zero point of this tensor may be different from the input
+ * tensor's parameters.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_HARD_SWISH = 99,
+
+ /**
+ * Creates a tensor filled with a scalar value.
+ *
+ * Supported output tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: A 1-D tensor, specifying the desired output tensor shape.
+ * * 1: A scalar, specifying the value to fill the output tensors with.
+ * For output tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT16},
+ * the scalar must be of {@link ANEURALNETWORKS_FLOAT16}.
+ * For output tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32},
+ * the scalar must be of {@link ANEURALNETWORKS_FLOAT32}.
+ * For output tensor of {@link ANEURALNETWORKS_TENSOR_INT32},
+ * the scalar must be of {@link ANEURALNETWORKS_INT32}.
+ *
+ * Outputs:
+ * * 0: The output tensor.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_FILL = 100,
+
+ /**
+ * Returns the rank of a tensor.
+ *
+ * The rank of a tensor is the number of dimensions in it. Also known as
+ * "order", "degree", "ndims".
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT16}
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT16_SYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_BOOL8}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}
+ *
+ * Supported tensor rank: from 1.
+ *
+ * Inputs:
+ * * 0: The input tensor.
+ *
+ * Outputs:
+ * * 0: A scalar of {@link ANEURALNETWORKS_INT32}, specifying the rank
+ * of the input tensor.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_RANK = 101,
+} OperationCode;
+
+/**
+ * Fused activation function types.
+ *
+ *
+ * Available since API level 27.
+ */
+typedef enum {
+ /** NO fused activation function. */
+ ANEURALNETWORKS_FUSED_NONE = 0,
+ /** Fused ReLU activation function. */
+ ANEURALNETWORKS_FUSED_RELU = 1,
+ /** Fused ReLU1 activation function. */
+ ANEURALNETWORKS_FUSED_RELU1 = 2,
+ /** Fused ReLU6 activation function. */
+ ANEURALNETWORKS_FUSED_RELU6 = 3,
+} FuseCode;
+
+/**
+ * Implicit padding algorithms.
+ *
+ *
+ * Available since API level 27.
+ */
+typedef enum {
+ /**
+ * SAME padding.
+ * Padding on both ends are the "same":
+ * padding_to_beginning = total_padding / 2
+ * padding_to_end = (total_padding + 1)/2.
+ * i.e., for even number of padding, padding to both ends are exactly
+ * the same; for odd number of padding, padding to the ending is bigger
+ * than the padding to the beginning by 1.
+ *
+ * total_padding is a function of input, stride, dilation and filter size.
+ * It could be computed as follows:
+ * out_size = (input + stride - 1) / stride
+ * effective_filter_size = (filter_size - 1) * dilation + 1
+ * needed_input = (out_size - 1) * stride + effective_filter_size
+ * total_padding = max(0, needed_input - input_size)
+ * The computation is the same for the horizontal and vertical directions.
+ */
+ ANEURALNETWORKS_PADDING_SAME = 1,
+
+ /**
+ * VALID padding.
+ * No padding. When the input size is not evenly divisible by
+ * the filter size, the input at the end that could not fill
+ * the whole filter tile will simply be ignored.
+ */
+ ANEURALNETWORKS_PADDING_VALID = 2,
+} PaddingCode;
+
+/**
+ * Execution preferences.
+ *
+ * Available since API level 27.
+ */
+typedef enum {
+ /**
+ * Prefer executing in a way that minimizes battery drain.
+ * This is desirable for compilations that will be executed often.
+ */
+ ANEURALNETWORKS_PREFER_LOW_POWER = 0,
+ /**
+ * Prefer returning a single answer as fast as possible, even if this causes
+ * more power consumption.
+ */
+ ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER = 1,
+ /**
+ * Prefer maximizing the throughput of successive frames, for example when
+ * processing successive frames coming from the camera.
+ */
+ ANEURALNETWORKS_PREFER_SUSTAINED_SPEED = 2,
+} PreferenceCode;
+
+/**
+ * Device types.
+ *
+ * The type of NNAPI device.
+ */
+typedef enum {
+ /** The device type cannot be provided. */
+ ANEURALNETWORKS_DEVICE_UNKNOWN = 0,
+ /** The device does not fall into any category below. */
+ ANEURALNETWORKS_DEVICE_OTHER = 1,
+ /** The device runs NNAPI models on single or multi-core CPU. */
+ ANEURALNETWORKS_DEVICE_CPU = 2,
+ /** The device can run NNAPI models and also accelerate graphics APIs such
+ * as OpenGL ES and Vulkan. */
+ ANEURALNETWORKS_DEVICE_GPU = 3,
+ /** Dedicated accelerator for Machine Learning workloads. */
+ ANEURALNETWORKS_DEVICE_ACCELERATOR = 4,
+} DeviceTypeCode;
+
+/**
+ * Result codes.
+ *
+ * <p>Any NNAPI function can return any result code, including result codes not
+ * currently documented. Any value other than {@link ANEURALNETWORKS_NO_ERROR}
+ * indicates a failure of some kind.</p>
+ *
+ * <p>Additional information about the nature of a failure can be obtained from
+ * the device log after enabling NNAPI debugging by setting the debug.nn.vlog
+ * property to 1, e.g., by calling "adb shell setprop debug.nn.vlog 1".</p>
+ *
+ * Available since API level 27.
+ */
+typedef enum {
+ /**
+ * Operation was succesful.
+ */
+ ANEURALNETWORKS_NO_ERROR = 0,
+
+ /**
+ * Failure caused by not enough available memory.
+ */
+ ANEURALNETWORKS_OUT_OF_MEMORY = 1,
+
+ ANEURALNETWORKS_INCOMPLETE = 2,
+
+ /**
+ * Failure caused by unexpected null argument.
+ */
+ ANEURALNETWORKS_UNEXPECTED_NULL = 3,
+
+ /**
+ * Failure caused by invalid function arguments, invalid model definition,
+ * invalid execution definition or invalid data at execution time.
+ */
+ ANEURALNETWORKS_BAD_DATA = 4,
+
+ /**
+ * Failure caused by failed model execution.
+ */
+ ANEURALNETWORKS_OP_FAILED = 5,
+
+ /**
+ * Failure caused by object being in the wrong state.
+ */
+ ANEURALNETWORKS_BAD_STATE = 6,
+
+ /**
+ * Failure caused by not being able to map a file into memory.
+ * This may be caused by a file descriptor not being mappable, or an AHardwareBuffer
+ * not supported by the device.
+ * Mitigate by reading its content into memory.
+ */
+ ANEURALNETWORKS_UNMAPPABLE = 7,
+
+ /**
+ * Failure caused by insufficient buffer size provided to a model output.
+ */
+ ANEURALNETWORKS_OUTPUT_INSUFFICIENT_SIZE = 8,
+
+ /**
+ * Failure caused by a device not being available.
+ */
+ ANEURALNETWORKS_UNAVAILABLE_DEVICE = 9,
+
+ /**
+ * Failure because a deadline could not be met for a task, but future
+ * deadlines may still be met for the same task after a short delay.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_MISSED_DEADLINE_TRANSIENT = 10,
+
+ /**
+ * Failure because a deadline could not be met for a task, and future
+ * deadlines will likely also not be met for the same task even after a
+ * short delay.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_MISSED_DEADLINE_PERSISTENT = 11,
+
+ /**
+ * Failure because of a resource limitation within the driver, but future
+ * calls for the same task may still succeed after a short delay.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_RESOURCE_EXHAUSTED_TRANSIENT = 12,
+
+ /**
+ * Failure because of a resource limitation within the driver, and future
+ * calls for the same task will likely also fail even after a short
+ * delay.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_RESOURCE_EXHAUSTED_PERSISTENT = 13,
+
+ /**
+ * Failure indicating an object is in a dead state.
+ *
+ * Available since API level 30.
+ */
+ ANEURALNETWORKS_DEAD_OBJECT = 14,
+} ResultCode;
+
+/**
+ * For {@link ANeuralNetworksModel_setOperandValue}, values with a
+ * length smaller or equal to this will be immediately copied into
+ * the model. The size is in bytes.
+ *
+ * Available since API level 27.
+ */
+enum { ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES = 128 };
+
+/**
+ * For {@link ANeuralNetworksCompilation_setCaching}, specify the size
+ * of the cache token required from the application. The size is in bytes.
+ *
+ * Available since API level 29.
+ */
+enum { ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN = 32 };
+
+/**
+ * Different duration measurements.
+ *
+ * Durations are measured in nanoseconds.
+ *
+ * Available since API level 29.
+ */
+typedef enum {
+ // Execution time on hardware (not driver, which runs on host processor).
+ ANEURALNETWORKS_DURATION_ON_HARDWARE = 0,
+ // Execution time in driver (including time on hardware). Excludes overhead
+ // such as that of the runtime itself and the IPC needed for the runtime to
+ // communicate with the driver.
+ ANEURALNETWORKS_DURATION_IN_DRIVER = 1,
+ // Execution time on hardware, after all dependencies have been signaled.
+ // If no dependencies specified (for example, if the execution was scheduled other
+ // than with {@link ANeuralNetworksExecution_startComputeWithDependencies}), the
+ // reported time will be the same as ANEURALNETWORKS_DURATION_ON_HARDWARE.
+ // Available since API level 30.
+ ANEURALNETWORKS_FENCED_DURATION_ON_HARDWARE = 2,
+ // Execution time in driver, after all dependencies have been signaled. Excludes
+ // overhead such as that of the runtime itself and the IPC needed for the runtime
+ // to communicate with the driver.
+ // If no dependencies specified (for example, if the execution was scheduled other
+ // than with {@link ANeuralNetworksExecution_startComputeWithDependencies}), the
+ // reported time will be the same as ANEURALNETWORKS_DURATION_IN_DRIVER.
+ // Available since API level 30.
+ ANEURALNETWORKS_FENCED_DURATION_IN_DRIVER = 3,
+} DurationCode;
+
+/**
+ * Relative execution priority.
+ *
+ * Available since API level 30.
+ */
+typedef enum {
+ ANEURALNETWORKS_PRIORITY_LOW = 90,
+ ANEURALNETWORKS_PRIORITY_MEDIUM = 100,
+ ANEURALNETWORKS_PRIORITY_HIGH = 110,
+ ANEURALNETWORKS_PRIORITY_DEFAULT = ANEURALNETWORKS_PRIORITY_MEDIUM,
+} PriorityCode;
+
+/**
+ * ANeuralNetworksMemory is an opaque type that represents memory.
+ *
+ * This type is used to represent shared memory, memory mapped files,
+ * and similar memories.
+ *
+ * By using shared memory, a program can efficiently communicate to the
+ * runtime and drivers the tensors that define a model. See
+ * {@link ANeuralNetworksModel_setOperandValueFromMemory}. An application
+ * should typically create one shared memory object that contains every constant tensor
+ * needed to define a model. {@link ANeuralNetworksMemory_createFromFd} can be used to
+ * create shared memory from a file handle.
+ * {@link ANeuralNetworksMemory_createFromAHardwareBuffer} can be used to
+ * create shared memory from an AHardwareBuffer handle.
+ *
+ * Memory objects can also be used to specify the input and output arguments of
+ * an execution. See {@link ANeuralNetworksExecution_setInputFromMemory}
+ * and {@link ANeuralNetworksExecution_setOutputFromMemory}.
+ *
+ * When calling {@link ANeuralNetworksModel_setOperandValueFromMemory},
+ * {@link ANeuralNetworksExecution_setInputFromMemory} and
+ * {@link ANeuralNetworksExecution_setOutputFromMemory}, each operand in the shared
+ * memory object must be aligned on a boundary of a byte size that is a multiple
+ * of the element type byte size, e.g., a tensor with
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32} type must be aligned on 4-byte boundary.
+ *
+ * It is the application's responsibility to ensure that there are no uses of
+ * the memory after calling {@link ANeuralNetworksMemory_free}. This includes
+ * any model which references this memory because of a call to
+ * {@link ANeuralNetworksModel_setOperandValueFromMemory}, any compilation
+ * created using such a model, any execution object or burst object created
+ * using such a compilation, or any execution which references this memory
+ * because of a call to {@link ANeuralNetworksExecution_setInputFromMemory} or
+ * {@link ANeuralNetworksExecution_setOutputFromMemory}.
+ *
+ * Available since API level 27.
+ *
+ * Starting at API level 30, the application may request creation of device native memory from
+ * {@link ANeuralNetworksMemoryDesc} to avoid potential memory copying and transformation
+ * overhead between executions. See also {@link ANeuralNetworksMemoryDesc} and
+ * {@link ANeuralNetworksMemory_createFromDesc}.
+ */
+typedef struct ANeuralNetworksMemory ANeuralNetworksMemory;
+
+/**
+ * ANeuralNetworksModel is an opaque type that contains a description of the
+ * mathematical operations that constitute the model.
+ *
+ * <p>Build the model by calling<ul>
+ * <li>{@link ANeuralNetworksModel_create}</li>
+ * <li>{@link ANeuralNetworksModel_addOperation}</li>
+ * <li>{@link ANeuralNetworksModel_addOperand}</li>
+ * </ul>
+ *
+ * This forms a graph in which each operation and operand is a node, a
+ * directed edge from an operand to an operation indicates that the
+ * operand is an input to the operation, and a directed edge from an
+ * operation to an operand indicates that the operand is an output
+ * from the operation. This graph must be acyclic.
+ *
+ * A model is completed by calling {@link ANeuralNetworksModel_finish}.
+ * A model is destroyed by calling {@link ANeuralNetworksModel_free}.
+ *
+ * <p>A model cannot be modified once {@link ANeuralNetworksModel_finish}
+ * has been called on it.</p>
+ *
+ * <p>It is the application's responsibility to make sure that only one thread
+ * modifies a model at a given time. It is however safe for more than one
+ * thread to use the model once {@link ANeuralNetworksModel_finish} has returned.</p>
+ *
+ * <p>It is also the application's responsibility to ensure that there are no
+ * other uses of the model after calling {@link ANeuralNetworksModel_free}.
+ * This includes any compilation, execution object or burst object created using
+ * the model.</p>
+ *
+ * Available since API level 27.
+ */
+typedef struct ANeuralNetworksModel ANeuralNetworksModel;
+
+/**
+ * ANeuralNetworksCompilation is an opaque type that can be used to compile
+ * a machine learning model.
+ *
+ * <p>To use:<ul>
+ * <li>Create a new compilation instance by calling the
+ * {@link ANeuralNetworksCompilation_create} function or
+ * {@link ANeuralNetworksCompilation_createForDevices}.</li>
+ * <li>Set any desired properties on the compilation (for example,
+ * {@link ANeuralNetworksCompilation_setPreference}).</li>
+ * <li>Optionally, set the caching signature and the cache directory on the
+ * compilation by calling {@link ANeuralNetworksCompilation_setCaching}.</li>
+ * <li>Complete the compilation with {@link ANeuralNetworksCompilation_finish}.</li>
+ * <li>Use the compilation as many times as needed
+ * with {@link ANeuralNetworksExecution_create} and
+ * {@link ANeuralNetworksBurst_create}.</li>
+ * <li>Destroy the compilation with {@link ANeuralNetworksCompilation_free}
+ * once all executions using the compilation have completed.</li></ul></p>
+ *
+ * A compilation is completed by calling {@link ANeuralNetworksCompilation_finish}.
+ * A compilation is destroyed by calling {@link ANeuralNetworksCompilation_free}.
+ *
+ * <p>A compilation cannot be modified once {@link ANeuralNetworksCompilation_finish}
+ * has been called on it.</p>
+ *
+ * <p>It is the application's responsibility to make sure that only
+ * one thread modifies a compilation at a given time. It is however
+ * safe for more than one thread to use the compilation once
+ * {@link ANeuralNetworksCompilation_finish} has returned.</p>
+ *
+ * <p>It is also the application's responsibility to ensure that there are no other
+ * uses of the compilation after calling {@link ANeuralNetworksCompilation_free}.
+ * This includes any execution object or burst object created using the compilation,
+ * or any memory descriptor with the compilation as part of one of the roles specified by
+ * {@link ANeuralNetworksMemoryDesc_addInputRole} or
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}.</p>
+ *
+ * Available since API level 27.
+ */
+typedef struct ANeuralNetworksCompilation ANeuralNetworksCompilation;
+
+/**
+ * ANeuralNetworksExecution is an opaque type that can be used to apply a machine
+ * learning model to a set of inputs.
+ *
+ * <p>To use:<ul>
+ * <li>Create a new execution instance by calling the
+ * {@link ANeuralNetworksExecution_create} function.</li>
+ * <li>Associate input buffers or memory regions to the model inputs with
+ * {@link ANeuralNetworksExecution_setInput} or
+ * {@link ANeuralNetworksExecution_setInputFromMemory}.</li>
+ * <li>Associate output buffers or memory regions to the model outputs with
+ * {@link ANeuralNetworksExecution_setOutput} or
+ * {@link ANeuralNetworksExecution_setOutputFromMemory}.</li>
+ * <li>Apply the model with one of the following:</li><ul>
+ * <li>Asynchronously with {@link ANeuralNetworksExecution_startCompute}
+ * or with {@link ANeuralNetworksExecution_startComputeWithDependencies},
+ * waiting for the execution to complete with
+ * {@link ANeuralNetworksEvent_wait}.</li>
+ * <li>Synchronously with {@link ANeuralNetworksExecution_compute}.</li>
+ * <li>Synchronously as part of an execution burst with
+ * {@link ANeuralNetworksExecution_burstCompute}.</li></ul>
+ * <li>Destroy the execution with
+ * {@link ANeuralNetworksExecution_free}.</li></ul></p>
+ *
+ * <p>An output buffer or memory region must not overlap with any
+ * other output buffer or memory region, with an input buffer or
+ * memory region, or with an operand value in a memory object
+ * ({@link ANeuralNetworksModel_setOperandValueFromMemory}).</p>
+ *
+ * <p>An execution cannot be modified once
+ * {@link ANeuralNetworksExecution_burstCompute},
+ * {@link ANeuralNetworksExecution_compute},
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies} has been called on it.</p>
+ *
+ * <p>An execution can be applied to a model with
+ * {@link ANeuralNetworksExecution_burstCompute},
+ * {@link ANeuralNetworksExecution_compute},
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies} only once. Create new
+ * executions to do new evaluations of the model.</p>
+ *
+ * <p>It is the application's responsibility to make sure that only one thread
+ * modifies an execution at a given time. It is however safe for more than one
+ * thread to use {@link ANeuralNetworksEvent_wait} at the same time.</p>
+ *
+ * <p>It is also the application's responsibility to ensure that the execution
+ * either has never been scheduled or has completed (i.e., that
+ * {@link ANeuralNetworksExecution_burstCompute},
+ * {@link ANeuralNetworksExecution_compute}, or
+ * {@link ANeuralNetworksEvent_wait} has returned) before calling
+ * {@link ANeuralNetworksExecution_free}.</p>.
+ *
+ * <p>It is also the application's responsibility to ensure that there are no other
+ * uses of the execution after calling {@link ANeuralNetworksExecution_free}.</p>
+ *
+ * <p>Multiple executions can be scheduled and evaluated concurrently, either by
+ * means of {@link ANeuralNetworksExecution_compute} or
+ * {@link ANeuralNetworksExecution_burstCompute} (which are synchronous) in
+ * different threads, or by means of
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies} (which are asynchronous).
+ * (Concurrent uses of {@link ANeuralNetworksExecution_burstCompute} must be on
+ * different burst objects.) The runtime makes no guarantee on the ordering of
+ * completion of executions. If it's important to the application, the
+ * application should enforce the ordering by ensuring that one execution
+ * completes before the next is scheduled (for example, by scheduling all
+ * executions synchronously within a single thread, or by scheduling all
+ * executions asynchronously and using {@link ANeuralNetworksEvent_wait} between
+ * calls to {@link ANeuralNetworksExecution_startCompute}); or by using
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies} to make the execution wait for a
+ * list of events to be signaled before starting the actual evaluation.</p>
+ *
+ * Available since API level 27.
+ */
+typedef struct ANeuralNetworksExecution ANeuralNetworksExecution;
+
+#if __ANDROID_API__ >= 29
+/**
+ * Parameters for ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL operand.
+ */
+typedef struct ANeuralNetworksSymmPerChannelQuantParams {
+ /* The index of the channel dimension. */
+ uint32_t channelDim;
+ /** The size of the scale array. Should be equal to dimension[channelDim] of the Operand. */
+ uint32_t scaleCount;
+ /** The array of scaling values for each channel. Each value must be greater than zero. */
+ const float* scales;
+} ANeuralNetworksSymmPerChannelQuantParams;
+
+/**
+ * ANeuralNetworksBurst is an opaque type that can be used to reduce the latency
+ * of a rapid sequence of executions. It will likely cause overhead if only used
+ * for a single execution.
+ *
+ * ANeuralNetworksBurst serves as a context object for any number of inferences
+ * using {@link ANeuralNetworksExecution} objects. An ANeuralNetworksBurst
+ * object and the {@link ANeuralNetworksExecution} objects used with it must all
+ * have been created from the same {@link ANeuralNetworksCompilation} object.
+ *
+ * This object is also used as a hint to drivers, providing insight to the
+ * lifetime of a rapid sequence of executions. For example, a driver may choose
+ * to increase the clock frequency of its accelerator for the lifetime of a
+ * burst object.
+ *
+ * <p>To use:<ul>
+ * <li>Create a new burst object by calling the
+ * {@link ANeuralNetworksBurst_create} function.</li>
+ * <li>For each execution:</li><ul>
+ * <li>Create {@link ANeuralNetworksExecution} and configure its
+ * properties (see {@link ANeuralNetworksExecution} for details).</li>
+ * <li>Apply the model synchronously with
+ * {@link ANeuralNetworksExecution_burstCompute}, reusing the same
+ * {@link ANeuralNetworksBurst} with the new
+ * {@link ANeuralNetworksExecution}.</li>
+ * <li>Use and free the {@link ANeuralNetworksExecution}.</li></ul>
+ * <li>Destroy the burst with
+ * {@link ANeuralNetworksBurst_free}.</li></ul></p>
+ *
+ * Available since API level 29.
+ */
+typedef struct ANeuralNetworksBurst ANeuralNetworksBurst;
+#endif // __ANDROID_API__ >= 29
+
+/**
+ * ANeuralNetworksOperandType describes the type of an operand.
+ *
+ * This structure is used to describe both scalars and tensors.
+ *
+ * A tensor operand type with all dimensions specified is "fully
+ * specified". Whenever possible (i.e., whenever the dimensions are
+ * known at model construction time), a tensor operand type should be
+ * (but is not required to be) fully specified, in order to enable the
+ * best possible performance.
+ *
+ * If a tensor operand's type is not fully specified, the dimensions
+ * of the operand are deduced from the operand types and values of the
+ * operation for which that operand is an output or from the corresponding
+ * {@link ANEURALNETWORKS_IF} or {@link ANEURALNETWORKS_WHILE} operation input
+ * operand type in the case of referenced model input operands.
+ *
+ * <p>In the following situations, a tensor operand type must be fully
+ * specified:<ul>
+ * <li>The operand has a constant value, set by
+ * {@link ANeuralNetworksModel_setOperandValue} (with a
+ * non-nullptr buffer) or
+ * {@link ANeuralNetworksModel_setOperandValueFromMemory}.</li>
+ * <li>The operand is a model input (see
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}) of the main
+ * model within a compilation. A fully specified tensor operand type
+ * must either be provided to {@link ANeuralNetworksModel_addOperand};
+ * or it must be provided to the corresponding
+ * {@link ANeuralNetworksExecution_setInput}, or
+ * {@link ANeuralNetworksExecution_setInputFromMemory}.
+ * EXCEPTION: If the input is optional and omitted
+ * (by passing nullptr for buffer to
+ * {@link ANeuralNetworksExecution_setInput}) then it need
+ * not have a fully specified tensor operand type.</li>
+ * <li>The operand is a model output (see
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}) of the main
+ * model within a compilation and is to be used with {@link
+ * ANeuralNetworksExecution_startComputeWithDependencies}.
+ * A fully specified tensor operand type must either be provided
+ * to {@link ANeuralNetworksModel_addOperand}; or it must be
+ * provided to the corresponding
+ * {@link ANeuralNetworksExecution_setOutput}, or
+ * {@link ANeuralNetworksExecution_setOutputFromMemory}.</li></ul>
+ *
+ * A tensor operand type of specified rank but some number of
+ * unspecified dimensions is represented by setting dimensionCount to
+ * the rank and each unspecified dimension to 0.
+ *
+ * Available since API level 27.
+ *
+ * Starting at API level 29, a tensor operand type of unspecified rank is
+ * represented by setting dimensionCount to 0 and dimensions to NULL (just as if
+ * it were a scalar operand type).
+ */
+typedef struct ANeuralNetworksOperandType {
+ /**
+ * The data type, e.g ANEURALNETWORKS_FLOAT32.
+ */
+ int32_t type;
+
+ /**
+ * The number of dimensions (rank).
+ *
+ * Must be 0 for scalars.
+ */
+ uint32_t dimensionCount;
+
+ /**
+ * The dimensions of the tensor.
+ *
+ * Must be nullptr for scalars.
+ */
+ const uint32_t* dimensions;
+
+ /**
+ * The quantization scale.
+ *
+ * Must be 0 when not applicable to an operand type.
+ *
+ * See {@link OperandCode}.
+ */
+ float scale;
+
+ /**
+ * The quantization zero point.
+ *
+ * Must be 0 when not applicable to an operand type.
+ *
+ * See {@link OperandCode}.
+ */
+ int32_t zeroPoint;
+} ANeuralNetworksOperandType;
+
+typedef int32_t ANeuralNetworksOperationType;
+
+/**
+ * ANeuralNetworksEvent is an opaque type that represents an event
+ * that will be signaled once an execution completes.
+ *
+ * Available since API level 27.
+ */
+typedef struct ANeuralNetworksEvent ANeuralNetworksEvent;
+
+#if __ANDROID_API__ >= 29
+
+/**
+ * ANeuralNetworksDevice is an opaque type that represents a device.
+ *
+ * This type is used to query basic properties and supported operations of the corresponding
+ * device, and control which device(s) a model is to be run on.
+ *
+ * Available since API level 29.
+ */
+typedef struct ANeuralNetworksDevice ANeuralNetworksDevice;
+
+#endif // __ANDROID_API__ >= 29
+
+#if __ANDROID_API__ >= 30
+
+/**
+ * ANeuralNetworksMemoryDesc is an opaque type that represents a memory descriptor.
+ *
+ * A memory descriptor describes the properties of a memory object, and is used by
+ * {@link ANeuralNetworksMemory_createFromDesc}.
+ *
+ * To use:
+ * - Create a new memory descriptor by calling {@link ANeuralNetworksMemoryDesc_create}.
+ * - Specify all of the intended input and output roles by calling
+ * {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}.
+ * - Optionally, specify the memory dimensions by calling
+ * {@link ANeuralNetworksMemoryDesc_setDimensions}.
+ * - Complete the memory descriptor with {@link ANeuralNetworksMemoryDesc_finish}.
+ * - Use the memory descriptor as many times as needed with
+ * {@link ANeuralNetworksMemory_createFromDesc}.
+ * - Destroy the memory descriptor with {@link ANeuralNetworksMemoryDesc_free}.
+ *
+ * A memory descriptor is completed by calling {@link ANeuralNetworksMemoryDesc_finish}.
+ * A memory descriptor is destroyed by calling {@link ANeuralNetworksMemoryDesc_free}.
+ *
+ * A memory descriptor must not be modified once {@link ANeuralNetworksMemoryDesc_finish}
+ * has been called on it.
+ *
+ * It is the application's responsibility to make sure that only
+ * one thread modifies a memory descriptor at a given time. It is however
+ * safe for more than one thread to use the memory descriptor once
+ * {@link ANeuralNetworksMemoryDesc_finish} has returned.
+ *
+ * It is also the application's responsibility to ensure that there are no other
+ * uses of the memory descriptor after calling {@link ANeuralNetworksMemoryDesc_free}.
+ * It is however safe to continue using a {@link ANeuralNetworksMemory} object created
+ * from the memory descriptor.
+ *
+ * Available since API level 30.
+ */
+typedef struct ANeuralNetworksMemoryDesc ANeuralNetworksMemoryDesc;
+
+/**
+ * Create a {@link ANeuralNetworksMemoryDesc} with no properties.
+ *
+ * This only creates the memory descriptor. Its properties should be set with calls to
+ * {@link ANeuralNetworksMemoryDesc_addInputRole},
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}, and
+ * {@link ANeuralNetworksMemoryDesc_setDimensions}.
+ *
+ * {@link ANeuralNetworksMemoryDesc_finish} must be called once all properties have been set.
+ *
+ * {@link ANeuralNetworksMemoryDesc_free} must be called once the memory descriptor
+ * is no longer needed.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The {@link ANeuralNetworksMemoryDesc} to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksMemoryDesc_create(ANeuralNetworksMemoryDesc** desc) __INTRODUCED_IN(30);
+
+/**
+ * Destroy a memory descriptor.
+ *
+ * The memory descriptor need not have been finished by a call to
+ * {@link ANeuralNetworksMemoryDesc_finish}.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be destroyed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+void ANeuralNetworksMemoryDesc_free(ANeuralNetworksMemoryDesc* desc) __INTRODUCED_IN(30);
+
+/**
+ * Specify that a memory object will be playing the role of an input to an execution created from a
+ * particular compilation.
+ *
+ * The compilation and the input index fully specify an input operand. This function
+ * may be invoked multiple times on the same memory descriptor with different input operands,
+ * and the same input operand may be specified on multiple memory descriptors. However,
+ * specifying the same input operand on the same memory descriptor more than once will
+ * return an error.
+ *
+ * The dimensions of the corresponding model operands of all the roles specified by
+ * {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole} must be compatible with each other. Two
+ * dimensions are incompatible if both ranks are fully specified but have different values, or if
+ * there is at least one axis that is fully specified in both but has different values.
+ *
+ * At least one of {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole} must be called on a memory descriptor
+ * before invoking {@link ANeuralNetworksMemoryDesc_finish}.
+ *
+ * Attempting to modify a memory descriptor once {@link ANeuralNetworksMemoryDesc_finish} has been
+ * called will return an error.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be modified.
+ * @param compilation The compilation object. It must already have been finished by calling
+ * {@link ANeuralNetworksCompilation_finish}, and must outlive the memory
+ * descriptor.
+ * @param index The index of the input argument we are referencing from the compilation. It is
+ * an index into the inputs list passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link ANeuralNetworksModel_addOperand}.
+ * @param frequency A floating-point value within the range (0.0, 1.0]. Describes how likely the
+ * memory is to be used in the specified role. This is provided as a hint to
+ * optimize the case when different roles prefer different memory locations or data
+ * layouts.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksMemoryDesc_addInputRole(ANeuralNetworksMemoryDesc* desc,
+ const ANeuralNetworksCompilation* compilation,
+ uint32_t index, float frequency) __INTRODUCED_IN(30);
+
+/**
+ * Specify that a memory object will be playing the role of an output to an execution created from a
+ * particular compilation.
+ *
+ * The compilation and the output index fully specify an output operand. This function
+ * may be invoked multiple times on the same memory descriptor with different output operands,
+ * and the same output operand may be specified on multiple memory descriptors. However,
+ * specifying the same output operand on the same memory descriptor object more than once will
+ * return an error.
+ *
+ * The dimensions of the corresponding model operands of all the roles specified by
+ * {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole} must be compatible with each other. Two
+ * dimensions are incompatible if both ranks are fully specified but have different values, or if
+ * there is at least one axis that is fully specified in both but has different values.
+ *
+ * At least one of {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole} must be called on the memory descriptor
+ * before invoking {@link ANeuralNetworksMemoryDesc_finish}.
+ *
+ * Attempting to modify a memory descriptor once {@link ANeuralNetworksMemoryDesc_finish} has been
+ * called will return an error.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be modified.
+ * @param compilation The compilation object. It must already have been finished by calling
+ * {@link ANeuralNetworksCompilation_finish}, and must outlive the memory
+ * descriptor.
+ * @param index The index of the output argument we are referencing from the compilation. It is
+ * an index into the outputs list passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link ANeuralNetworksModel_addOperand}.
+ * @param frequency A floating-point value within the range (0.0, 1.0]. Describes how likely the
+ * memory is to be used in the specified role. This is provided as a hint to
+ * optimize the case when multiple roles prefer different memory locations or data
+ * layouts.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksMemoryDesc_addOutputRole(ANeuralNetworksMemoryDesc* desc,
+ const ANeuralNetworksCompilation* compilation,
+ uint32_t index, float frequency) __INTRODUCED_IN(30);
+
+/**
+ * Set the dimensional information of the memory descriptor.
+ *
+ * The specified dimensions must be compatible with the dimensions of the corresponding model
+ * operands of all the roles specified by {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}. Two dimensions are incompatible if both ranks
+ * are fully specified but have different values, or if there is at least one axis that is fully
+ * specified in both but has different values.
+ *
+ * Attempting to modify a memory descriptor once {@link ANeuralNetworksMemoryDesc_finish} has been
+ * called will return an error.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be modified.
+ * @param rank The number of dimensions. Must be 0 for scalars.
+ * @param dimensions An array of dimensions. An entry with the value 0 indicates that the
+ * corresponding axis has an unknown size.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksMemoryDesc_setDimensions(ANeuralNetworksMemoryDesc* desc, uint32_t rank,
+ const uint32_t* dimensions) __INTRODUCED_IN(30);
+
+/**
+ * Indicate that we have finished modifying a memory descriptor. Required before calling
+ * {@link ANeuralNetworksMemory_createFromDesc}.
+ *
+ * This function must only be called once for a given memory descriptor.
+ *
+ * See {@link ANeuralNetworksMemoryDesc} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor to be finished.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksMemoryDesc_finish(ANeuralNetworksMemoryDesc* desc) __INTRODUCED_IN(30);
+
+/**
+ * Creates a memory object from a memory descriptor.
+ *
+ * The memory object is created with an uninitialized buffer. A memory object with an uninitialized
+ * buffer may only be used according to the roles specified by {@link
+ * ANeuralNetworksMemoryDesc_addOutputRole}, or as the destination memory in {@link
+ * ANeuralNetworksMemory_copy}. The buffer of a memory object is initialized after the memory object
+ * is used as an output in a successful execution, or used as the destination memory in a successful
+ * {@link ANeuralNetworksMemory_copy}. A memory object with an initialized buffer may be used
+ * according to all roles specified in {@link ANeuralNetworksMemoryDesc}, or as the source or
+ * destination memory in {@link ANeuralNetworksMemory_copy}. The buffer of a memory object will
+ * return to the uninitialized state if the memory object is used as an output in a failed
+ * execution, or used as the destination memory in a failed {@link ANeuralNetworksMemory_copy}.
+ *
+ * The dimensions of the memory descriptor are deduced from the dimensions of the corresponding
+ * model operands of all the roles specified by {@link ANeuralNetworksMemoryDesc_addInputRole} and
+ * {@link ANeuralNetworksMemoryDesc_addOutputRole}, as well as the dimensions set by the call to
+ * {@link ANeuralNetworksMemoryDesc_setDimensions}, if any. The memory descriptor may have
+ * unspecified dimensions or rank. In such a case, the same memory object may be used with different
+ * shapes of outputs in different executions. When the memory is used as an input, the input shape
+ * must be the same as the output shape from the last execution using this memory object as an
+ * output, or the last {@link ANeuralNetworkMemory_copy} using this memory object as the destination
+ * memory. Creating a memory object with unspecified dimensions or rank may fail for certain sets of
+ * roles.
+ *
+ * Using the memory in roles or shapes that are not compatible with the rules specified above will
+ * return an error.
+ *
+ * When calling {@link ANeuralNetworksExecution_setInputFromMemory} or
+ * {@link ANeuralNetworksExecution_setOutputFromMemory} with the memory object,
+ * both offset and length must be set to zero and the entire memory region will be
+ * associated with the specified input or output operand.
+ *
+ * Calling {@link ANeuralNetworksModel_setOperandValueFromMemory} with the memory created from this
+ * function will return an error.
+ *
+ * {@link ANeuralNetworksMemory_free} must be called once the memory is no longer needed.
+ *
+ * Attempting to create memory from an unfinished memory descriptor will return an error.
+ *
+ * The provided {@link ANeuralNetworksMemoryDesc} need not outlive the {@link ANeuralNetworksMemory}
+ * object.
+ *
+ * Available since API level 30.
+ *
+ * @param desc The memory descriptor.
+ * @param memory The memory object to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful; ANEURALNETWORKS_OP_FAILED if the memory is
+ * created with unspecified dimensions or rank and it is not supported for this set of
+ * roles.
+ */
+int ANeuralNetworksMemory_createFromDesc(const ANeuralNetworksMemoryDesc* desc,
+ ANeuralNetworksMemory** memory) __INTRODUCED_IN(30);
+
+/**
+ * Copies data from one memory object to another.
+ *
+ * If at most one of the src and dst is created from {@link ANeuralNetworksMemory_createFromDesc},
+ * the src and dst must have the same logical size:
+ * - If the memory is created from {@link ANeuralNetworksMemory_createFromFd}, or if it is created
+ * from {@link ANeuralNetworksMemory_createFromAHardwareBuffer} with format of
+ * AHARDWAREBUFFER_FORMAT_BLOB, the logical size equals the size of the memory.
+ * - If the memory is created from {@link ANeuralNetworksMemory_createFromAHardwareBuffer} with a
+ * format other than AHARDWAREBUFFER_FORMAT_BLOB, the logical size equals the size when there is
+ * no padding and the data is tightly packed. This function may fail if the AHardwareBuffer
+ * cannot be accessed.
+ * - If the memory is created from {@link ANeuralNetworksMemory_createFromDesc}, the logical size
+ * equals the size indicated by the {@link OperandCode} multiplied by the number of elements. This
+ * function will fail if the number of elements is unknown.
+ *
+ * If both src and dst are created from {@link ANeuralNetworksMemory_createFromDesc}, they must have
+ * compatible dimensions. Two dimensions are incompatible if both ranks are fully specified but
+ * have different values, or if there is at least one axis that is fully specified in both but has
+ * different values. The dst may have unspecified dimensions or rank. In such a case, the dimensions
+ * of dst will get updated according to the dimensions of the src.
+ *
+ * In both cases, if the src is created from {@link ANeuralNetworksMemory_createFromDesc}, it must
+ * have been used as an output in a successful execution, or used as the destination memory in a
+ * successful {@link ANeuralNetworksMemory_copy}.
+ *
+ * The src and dst may have different data layout, in which case the data copying is performed
+ * logically with data layout transformation.
+ *
+ * Available since API level 30.
+ *
+ * @param src The source memory object.
+ * @param dst The destination memory object.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksMemory_copy(const ANeuralNetworksMemory* src, const ANeuralNetworksMemory* dst)
+ __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
+#if __ANDROID_API__ >= 29
+
+/**
+ * Get the number of available devices.
+ *
+ * @param numDevices Used to return the number of devices.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworks_getDeviceCount(uint32_t* numDevices) __INTRODUCED_IN(29);
+
+/**
+ * Get the representation of the specified device.
+ *
+ * @param devIndex The index of the specified device. Must be less than the
+ number of available devices.
+ * @param device The representation of the specified device.
+ * The same representation will always be returned for the specified
+ * device.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworks_getDevice(uint32_t devIndex, ANeuralNetworksDevice** device)
+ __INTRODUCED_IN(29);
+
+/**
+ * Get the name of the specified device.
+ *
+ * @param device The representation of the specified device.
+ * @param name The returned name of the specified device. The name will be in UTF-8
+ * and will be null-terminated. It will be recognizable as a known device name
+ * rather than a cryptic string. For devices with feature level reported by
+ * {@link ANeuralNetworksDevice_getFeatureLevel} that is 29 and above, the
+ * format of the name is {VENDOR}-{DEVICE}. For devices with feature level 28
+ * or lower, the format of the name is undefined.
+ * The name will remain valid for the duration of the application.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksDevice_getName(const ANeuralNetworksDevice* device, const char** name)
+ __INTRODUCED_IN(29);
+
+/**
+ * Get the type of a given device.
+ *
+ * The device type can be used to help application developers to distribute Machine Learning
+ * workloads and other workloads such as graphical rendering.
+ * E.g., for an app which renders AR scenes based on real time object detection results,
+ * the developer could choose an ACCELERATOR type device for ML workloads, and reserve GPU
+ * for graphical rendering.
+ *
+ * @param device The representation of the specified device.
+ * @param type The returned {@link DeviceTypeCode} of the specified device.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksDevice_getType(const ANeuralNetworksDevice* device, int32_t* type)
+ __INTRODUCED_IN(29);
+
+/**
+ * Get the version of the driver implementation of the specified device.
+ *
+ * It’s the responsibility of the driver implementor to insure that this version string
+ * uniquely distinguishes this implementation from all previous implementations.
+ *
+ * This version string must not be confused with the feature level which is solely defined
+ * by {@link ANeuralNetworksDevice_getFeatureLevel}. There is no implicit ordering of the versions.
+ * For example, it is not possible to filter all drivers older than a certain version.
+ *
+ * Application developers may use this version string to avoid or prefer specific driver
+ * implementations. For example, an application may want to do so because:
+ * - A specific version of the driver does not provide the required performance,
+ * perhaps because of a performance regression.
+ * - A specific version of the driver has a bug or returns results that don’t match
+ * the minimum precision requirement for the application.
+ *
+ * @param device The representation of the specified device.
+ * @param version The returned version string of the driver for the specified device. The
+ * string will be in UTF-8 and will be null-terminated. For devices with feature
+ * level 28 or lower, "UNKNOWN" will be returned. The version string will remain
+ * valid for the duration of the application.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksDevice_getVersion(const ANeuralNetworksDevice* device, const char** version)
+ __INTRODUCED_IN(29);
+
+/**
+ * Get the supported NNAPI version of the specified device.
+ *
+ * Each device has a supported feature level, which is the most advanced feature this driver
+ * implements. For example, if the driver implements the features introduced in Android P,
+ * but does not implement the features introduced after Android P, the value would be 28.
+ * Developers could decide whether or not the specified device should be used for a Model that
+ * has certain feature requirements.
+ *
+ * @param device The representation of the specified device.
+ * @param featureLevel The API level of the most advanced feature this driver implements.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksDevice_getFeatureLevel(const ANeuralNetworksDevice* device,
+ int64_t* featureLevel) __INTRODUCED_IN(29);
+
+#if __ANDROID_API__ >= 30
+
+/**
+ * Wait until the device is in a live state.
+ *
+ * A device may encounter internal errors and temporarily enter a dead state. A
+ * call that uses a device in such a state will return with the error
+ * {@link ANEURALNETWORKS_DEAD_OBJECT}. ANeuralNetworksDevice_wait will block until
+ * the device is in a live state.
+ *
+ * @param device The representation of the specified device.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 30.
+ */
+int ANeuralNetworksDevice_wait(const ANeuralNetworksDevice* device) __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
+/**
+ * Get the supported operations for a specified set of devices. If multiple devices
+ * are selected, the supported operation list is a union of supported operations of all
+ * selected devices.
+ *
+ * @param model The model to be queried.
+ * @param devices The set of devices. Must not contain duplicates.
+ * @param numDevices The number of devices in the set.
+ * @param supportedOps The boolean array to be filled. True means supported. The size of the
+ * boolean array must be at least as large as the number of operations
+ * in the model. The order of elements in the supportedOps array matches
+ * the order in which the corresponding operations were added to the model.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksModel_getSupportedOperationsForDevices(
+ const ANeuralNetworksModel* model, const ANeuralNetworksDevice* const* devices,
+ uint32_t numDevices, bool* supportedOps) __INTRODUCED_IN(29);
+
+/**
+ * Create a {@link ANeuralNetworksCompilation} to compile the given model for a specified set
+ * of devices. If more than one device is specified, the compilation will
+ * distribute the workload automatically across the devices. The model must be fully
+ * supported by the specified set of devices. This means that
+ * ANeuralNetworksModel_getSupportedOperationsForDevices() must have returned true for every
+ * operation for that model/devices pair.
+ *
+ * The user must handle all compilation and execution failures from the
+ * specified set of devices. This is in contrast to a use of {@link
+ * ANeuralNetworksCompilation_create}, where the runtime will attempt to recover
+ * from such failures.
+ *
+ * The model passed to this function is termed the "main model" of the
+ * compilation, to distinguish it from other models referred to by an Operand
+ * of type {@link ANEURALNETWORKS_MODEL} within this compilation.
+ *
+ * @param model The {@link ANeuralNetworksModel} to be compiled.
+ * @param devices The set of devices. Must not contain duplicates.
+ * @param numDevices The number of devices in the set.
+ * @param compilation The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA
+ * if the model is invalid.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksCompilation_createForDevices(ANeuralNetworksModel* model,
+ const ANeuralNetworksDevice* const* devices,
+ uint32_t numDevices,
+ ANeuralNetworksCompilation** compilation)
+ __INTRODUCED_IN(29);
+
+/**
+ * Sets the compilation caching signature and the cache directory.
+ *
+ * Provides optional caching information to the runtime for faster repeated
+ * compilation.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded usage.
+ *
+ * @param compilation The compilation to be modified.
+ * @param cacheDir The cache directory for the runtime to store and retrieve caching
+ * data. It is recommended to use the code cache directory provided
+ * by the Android runtime. If not using the code cache directory, the
+ * user should choose a directory local to the application, and is
+ * responsible for managing the cache entries.
+ * @param token The token provided by the user to specify a model must be of length
+ * ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN. The user should ensure that
+ * the token is unique to a model within the application. The NNAPI
+ * runtime cannot detect token collisions; a collision will result in a
+ * failed execution or in a successful execution that produces incorrect
+ * output values.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksCompilation_setCaching(ANeuralNetworksCompilation* compilation,
+ const char* cacheDir, const uint8_t* token)
+ __INTRODUCED_IN(29);
+
+/**
+ * Schedule synchronous evaluation of the execution.
+ *
+ * <p>Schedules synchronous evaluation of the execution. Returns once the
+ * execution has completed and the outputs are ready to be consumed.
+ * </p>
+ *
+ * If {@link ANeuralNetworksExecution_setTimeout} was called on this execution,
+ * and the execution is not able to complete before the timeout duration is
+ * exceeded, then execution may be aborted, in which case
+ * {@link ANEURALNETWORKS_MISSED_DEADLINE_*} will be returned. If the device has
+ * a feature level reported by {@link ANeuralNetworksDevice_getFeatureLevel}
+ * that is lower than 30, then the timeout duration hint will be ignored.
+ *
+ * If this execution contains a {@link ANEURALNETWORKS_WHILE} operation, and
+ * the condition model does not output false within the loop timeout duration,
+ * then execution will be aborted and {@link ANEURALNETWORKS_MISSED_DEADLINE_*}
+ * will be returned.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * See {@link ANeuralNetworksExecution_burstCompute} for burst synchronous execution.
+ * See {@link ANeuralNetworksExecution_startCompute} for regular asynchronous execution.
+ * See {@link ANeuralNetworksExecution_startComputeWithDependencies} for
+ * asynchronous execution with dependencies.
+ *
+ * Available since API level 29.
+ *
+ * @param execution The execution to be scheduled and executed.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the execution completed normally.
+ * ANEURALNETWORKS_UNMAPPABLE if the execution input or output memory cannot
+ * be properly mapped.
+ */
+int ANeuralNetworksExecution_compute(ANeuralNetworksExecution* execution) __INTRODUCED_IN(29);
+
+/**
+ * Get the dimensional information of the specified output operand of the model of the
+ * {@link ANeuralNetworksExecution}.
+ *
+ * The execution must have completed. On asynchronous execution initiated by
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies},
+ * {@link ANeuralNetworksEvent_wait} must be called prior to this function.
+ *
+ * @param execution The execution to be queried.
+ * @param index The index of the output argument we are querying. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link ANeuralNetworksModel_addOperand}.
+ * @param rank The rank of the output operand.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_OUTPUT_INSUFFICIENT_SIZE
+ * if the target output is provided an insufficient buffer at execution time,
+ * ANEURALNETWORKS_BAD_DATA if the index is invalid.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksExecution_getOutputOperandRank(ANeuralNetworksExecution* execution,
+ int32_t index, uint32_t* rank)
+ __INTRODUCED_IN(29);
+
+/**
+ * Get the dimensional information of the specified output operand of the model of the
+ * {@link ANeuralNetworksExecution}. The target output operand cannot be a scalar.
+ *
+ * The execution must have completed. On asynchronous execution initiated by
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies},
+ * {@link ANeuralNetworksEvent_wait} must be called prior to this function.
+ *
+ * @param execution The execution to be queried.
+ * @param index The index of the output argument we are querying. It is an index into the lists
+ * passed to {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link ANeuralNetworksModel_addOperand}.
+ * @param dimensions The dimension array to be filled. The size of the array must be exactly as
+ * large as the rank of the output operand to be queried in the model.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_OUTPUT_INSUFFICIENT_SIZE
+ * if the target output is provided an insufficient buffer at execution time,
+ * ANEURALNETWORKS_BAD_DATA if the index is invalid or if the target is a scalar.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksExecution_getOutputOperandDimensions(ANeuralNetworksExecution* execution,
+ int32_t index, uint32_t* dimensions)
+ __INTRODUCED_IN(29);
+
+/**
+ * Create a {@link ANeuralNetworksBurst} to apply the given compilation.
+ * This only creates the burst object. Computation is only performed once
+ * {@link ANeuralNetworksExecution_burstCompute} is invoked with a valid
+ * {@link ANeuralNetworksExecution} and {@link ANeuralNetworksBurst}.
+ *
+ * <p>The provided compilation must outlive the burst object.</p>
+ *
+ * Available since API level 29.
+ *
+ * @param compilation The {@link ANeuralNetworksCompilation} to be evaluated.
+ * @param burst The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA
+ * if the compilation is invalid.
+ */
+int ANeuralNetworksBurst_create(ANeuralNetworksCompilation* compilation,
+ ANeuralNetworksBurst** burst) __INTRODUCED_IN(29);
+
+/**
+ * Destroys the burst object.
+ *
+ * Available since API level 29.
+ *
+ * @param burst The burst object to be destroyed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+void ANeuralNetworksBurst_free(ANeuralNetworksBurst* burst) __INTRODUCED_IN(29);
+
+/**
+ * Schedule synchronous evaluation of the execution on a burst object.
+ *
+ * <p>Schedules synchronous evaluation of the execution. Returns once the
+ * execution has completed and the outputs are ready to be consumed.</p>
+ *
+ * If {@link ANeuralNetworksExecution_setTimeout} was called on the execution,
+ * and the execution is not able to complete before the timeout duration is
+ * exceeded, then execution may be aborted, in which case
+ * {@link ANEURALNETWORKS_MISSED_DEADLINE_*} will be returned.
+ *
+ * If the execution contains a {@link ANEURALNETWORKS_WHILE} operation, and
+ * the condition model does not output false within the loop timeout duration,
+ * then execution will be aborted and {@link ANEURALNETWORKS_MISSED_DEADLINE_*}
+ * will be returned. If the device has a feature level reported by
+ * {@link ANeuralNetworksDevice_getFeatureLevel} that is lower than 30, then the
+ * timeout duration hint will be ignored.
+ *
+ * <p>There must be at most one {@link ANeuralNetworksExecution} processing at
+ * any given time for any given burst object. Any
+ * {@link ANeuralNetworksExecution} launched before the previous has finished
+ * will result in ANEURALNETWORKS_BAD_STATE.</p>
+ *
+ * See {@link ANeuralNetworksExecution_compute} for synchronous execution.
+ * See {@link ANeuralNetworksExecution_startCompute} for regular asynchronous execution.
+ * See {@link ANeuralNetworksExecution_startComputeWithDependencies} for
+ * asynchronous execution with dependencies.
+ *
+ * Available since API level 29.
+ *
+ * @param burst The burst object to execute on.
+ * @param execution The execution to be scheduled and executed. The execution
+ * must be created from the same {@link
+ * ANeuralNetworksCompilation} as the burst object.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the execution completed normally.
+ */
+int ANeuralNetworksExecution_burstCompute(ANeuralNetworksExecution* execution,
+ ANeuralNetworksBurst* burst) __INTRODUCED_IN(29);
+
+/**
+ * Creates a shared memory object from an AHardwareBuffer handle.
+ *
+ * If the shared memory is backed by an AHardwareBuffer of AHARDWAREBUFFER_FORMAT_BLOB
+ * format, it can be used the same way as shared memory created from a file handle. See
+ * {@link ANeuralNetworksMemory} for a description on how to use this shared memory.
+ *
+ * If the shared memory is backed by an AHardwareBuffer of a format other than
+ * AHARDWAREBUFFER_FORMAT_BLOB, it can only be used for Model inputs and outputs.
+ * When calling {@link ANeuralNetworksExecution_setInputFromMemory} or
+ * {@link ANeuralNetworksExecution_setOutputFromMemory} with the shared memory, both
+ * offset and length must be set to zero and the entire memory region will be
+ * associated with the specified input or output operand. There is no guarantee
+ * that an arbitrary AHardwareBuffer_Format and AHardwareBuffer_UsageFlags combination
+ * can be used by arbitrary devices. The execution will fail if the selected set of
+ * devices cannot consume the buffer.
+ *
+ * Calling {@link ANeuralNetworksModel_setOperandValueFromMemory} with shared memory
+ * backed by an AHardwareBuffer of a format other than AHARDWAREBUFFER_FORMAT_BLOB is
+ * disallowed.
+ *
+ * The provided AHardwareBuffer must outlive the ANeuralNetworksMemory object.
+ *
+ * Available since API level 29.
+ *
+ * @param ahwb The AHardwareBuffer handle.
+ * @param memory The memory object to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the request completed normally.
+ *
+ * @see AHardwareBuffer
+ */
+int ANeuralNetworksMemory_createFromAHardwareBuffer(const AHardwareBuffer* ahwb,
+ ANeuralNetworksMemory** memory)
+ __INTRODUCED_IN(29);
+
+/**
+
+ * Specifies whether duration of the {@link ANeuralNetworksExecution} is to be
+ * measured. Evaluation of the execution must not have been scheduled.
+ *
+ * By default, duration is not measured.
+ *
+ * The {@link ANeuralNetworksExecution} must have been created from an
+ * {@link ANeuralNetworksCompilation} which in turn was created from
+ * {@link ANeuralNetworksCompilation_createForDevices} with numDevices = 1.
+ * If the device has a feature level reported by
+ * {@link ANeuralNetworksDevice_getFeatureLevel} that is lower than 29, then the
+ * duration will not be measured.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * Available since API level 29.
+ *
+ * @param execution The execution to be modified.
+ * @param measure 'true' if duration is to be measured, 'false' if not.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksExecution_setMeasureTiming(ANeuralNetworksExecution* execution, bool measure)
+ __INTRODUCED_IN(29);
+
+/**
+ * Get the time spent in the specified {@link ANeuralNetworksExecution}, in nanoseconds.
+ *
+ * The execution must have completed. On asynchronous execution initiated by
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies},
+ * {@link ANeuralNetworksEvent_wait} must be called prior to this function.
+ *
+ * @param execution The execution to be queried.
+ * @param durationCode The measurement to be queried, specified by {@link DurationCode}.
+ * @param duration The returned duration. If no measurement was requested by
+ * {@link ANeuralNetworksExecution_setMeasureTiming}, if the
+ * device is has a feature level reported by
+ * {@link ANeuralNetworksDevice_getFeatureLevel} that is lower
+ * than 29, or for some other reason the duration is not
+ * available, UINT64_MAX will be returned. A particular device
+ * need not support any given measurement.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksExecution_getDuration(const ANeuralNetworksExecution* execution,
+ int32_t durationCode, uint64_t* duration)
+ __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+#if __ANDROID_API__ >= 27
+
+/**
+ * Creates a shared memory object from a file descriptor.
+ *
+ * The shared memory is backed by a file descriptor via mmap.
+ * See {@link ANeuralNetworksMemory} for a description on how to use
+ * this shared memory.
+ *
+ * Available since API level 27.
+ *
+ * @param size The requested size in bytes.
+ * Must not be larger than the file size.
+ * @param prot The desired memory protection for the mapping.
+ * It is either PROT_NONE or the bitwise OR of one or
+ * more of the following flags: PROT_READ, PROT_WRITE.
+ * @param fd The requested file descriptor.
+ * The file descriptor has to be mmap-able. The file
+ * descriptor will be duplicated.
+ * @param offset The offset to the beginning of the file of the area to map.
+ * The offset has to be aligned to a page size.
+ * @param memory The memory object to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the request completed normally.
+ */
+int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset,
+ ANeuralNetworksMemory** memory) __INTRODUCED_IN(27);
+
+/**
+ * Delete a memory object.
+ *
+ * Destroys the object used by the run time to keep track of the memory.
+ * This will free the underlying actual memory if no other code has open
+ * handles to this memory.
+ *
+ * Available since API level 27.
+ *
+ * @param memory The memory object to be freed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+void ANeuralNetworksMemory_free(ANeuralNetworksMemory* memory) __INTRODUCED_IN(27);
+
+/**
+ * Create an empty {@link ANeuralNetworksModel}.
+ *
+ * <p>This only creates the object. Computation is performed once
+ * {@link ANeuralNetworksExecution_burstCompute},
+ * {@link ANeuralNetworksExecution_compute},
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies} is invoked.
+ *
+ * The model should be constructed with calls to
+ * {@link ANeuralNetworksModel_addOperation} and
+ * {@link ANeuralNetworksModel_addOperand}
+ *
+ * <p>{@link ANeuralNetworksModel_finish} should be called once the model
+ * has been fully constructed.</p>
+ *
+ * <p>{@link ANeuralNetworksModel_free} should be called once the model
+ * is no longer needed.</p>
+ *
+ * Available since API level 27.
+ *
+ * @param model The {@link ANeuralNetworksModel} to be created.
+ * Set to NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_create(ANeuralNetworksModel** model) __INTRODUCED_IN(27);
+
+/**
+ * Destroy a model.
+ *
+ * The model need not have been finished by a call to
+ * {@link ANeuralNetworksModel_finish}.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param model The model to be destroyed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+void ANeuralNetworksModel_free(ANeuralNetworksModel* model) __INTRODUCED_IN(27);
+
+/**
+ * Indicate that we have finished modifying a model. Required before
+ * calling {@link ANeuralNetworksCompilation_create} and
+ * {@link ANeuralNetworksCompilation_createForDevices}.
+ *
+ * An application must ensure that no other thread uses the model at the same
+ * time.
+ *
+ * This function must only be called once for a given model.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param model The model to be finished.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_finish(ANeuralNetworksModel* model) __INTRODUCED_IN(27);
+
+/**
+ * Add an operand to a model.
+ *
+ * The order in which the operands are added is important. The first one added
+ * to a model will have the index value 0, the second 1, etc. These indexes are
+ * used as operand identifiers in
+ * {@link ANeuralNetworksModel_addOperation},
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs},
+ * {@link ANeuralNetworksModel_setOperandValue},
+ * {@link ANeuralNetworksModel_setOperandValueFromMemory},
+ * {@link ANeuralNetworksExecution_setInput},
+ * {@link ANeuralNetworksExecution_setInputFromMemory},
+ * {@link ANeuralNetworksExecution_setOutput},
+ * {@link ANeuralNetworksExecution_setOutputFromMemory} and
+ * {@link ANeuralNetworksExecution_setOperandValue}.
+ *
+ * <p>Every operand must be referenced in exactly one of the following
+ * ways:<ul>
+ * <li>It is identified as a model input with
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}.</li>
+ * <li>It is identified as a constant with
+ * {@link ANeuralNetworksModel_setOperandValue} or
+ * {@link ANeuralNetworksModel_setOperandValueFromMemory}.</li>
+ * <li>It is identified as an output of exactly one operation with
+ * {@link ANeuralNetworksModel_addOperation}.</li></p>
+ * <p>An operand that is identified as a model input or as a constant
+ * must not also be identified as a model output with
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}.</p>
+ *
+ * To build a model that can accommodate inputs of various sizes, as
+ * you may want to do for a CNN, leave unspecified the dimensions that
+ * will vary at run time. If you do so, fully specify dimensions
+ * when calling {@link ANeuralNetworksExecution_setInput} or
+ * {@link ANeuralNetworksExecution_setInputFromMemory}.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has been
+ * called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param model The model to be modified.
+ * @param type The {@link ANeuralNetworksOperandType} that describes the shape
+ * of the operand. Neither the {@link ANeuralNetworksOperandType}
+ * nor the dimensions it points to need to outlive the call to
+ * {@link ANeuralNetworksModel_addOperand}.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_addOperand(ANeuralNetworksModel* model,
+ const ANeuralNetworksOperandType* type) __INTRODUCED_IN(27);
+
+/**
+ * Sets an operand to a constant value.
+ *
+ * Values of length smaller or equal to
+ * {@link ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES}
+ * are immediately copied into the model.
+ *
+ * For values of length greater than
+ * {@link ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES}, a pointer to
+ * the buffer is stored within the model. The application must not change the
+ * content of this region until all executions using this model have
+ * completed. As the data may be copied during processing, modifying the data
+ * after this call yields undefined results. The provided buffer must outlive
+ * this model.
+ *
+ * For large tensors, using {@link ANeuralNetworksModel_setOperandValueFromMemory}
+ * is likely to be more efficient.
+ *
+ * To indicate that an optional operand should be considered missing,
+ * pass nullptr for buffer and 0 for length.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has been
+ * called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param buffer A pointer to the data to use.
+ * @param length The size in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel* model, int32_t index,
+ const void* buffer, size_t length) __INTRODUCED_IN(27);
+
+#if __ANDROID_API__ >= 29
+
+/**
+ * Sets an operand's per channel quantization parameters.
+ *
+ * Sets parameters required by a tensor of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}.
+ * This function must be called for every tensor of type
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} before
+ * calling {@link ANeuralNetworksModel_finish}.
+ *
+ * Available since API level 29.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param channelQuant The per channel quantization parameters for the operand.
+ * No memory in this struct needs to outlive the call to
+ * this function.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(
+ ANeuralNetworksModel* model, int32_t index,
+ const ANeuralNetworksSymmPerChannelQuantParams* channelQuant) __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+/**
+ * Sets an operand to a value stored in a memory object.
+ *
+ * The content of the memory is not copied. A reference to that memory is stored
+ * inside the model. The application must not change the content of the memory
+ * region until all executions using this model have completed. As the data may
+ * be copied during processing, modifying the data after this call yields
+ * undefined results.
+ *
+ * <p>The provided memory must outlive this model.</p>
+ *
+ * To indicate that an optional operand should be considered missing,
+ * use {@link ANeuralNetworksModel_setOperandValue} instead, passing nullptr for buffer.
+ *
+ * It is disallowed to set an operand value with shared memory backed by an AHardwareBuffer
+ * of a format other than AHARDWAREBUFFER_FORMAT_BLOB.
+ *
+ * It is disallowed to set an operand value with memory created from
+ * {@link ANeuralNetworksMemory_createFromDesc}.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has been
+ * called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ * See {@link ANeuralNetworksMemory_createFromAHardwareBuffer} for information on
+ * AHardwareBuffer usage.
+ *
+ * Available since API level 27.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param buffer A pointer to the data to use.
+ * @param memory The memory containing the data.
+ * @param offset This specifies the location of the data within the memory.
+ * The offset is in bytes from the start of memory.
+ * @param length The size in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel* model, int32_t index,
+ const ANeuralNetworksMemory* memory,
+ size_t offset, size_t length)
+ __INTRODUCED_IN(27);
+
+#if __ANDROID_API__ >= 30
+
+/**
+ * Sets an operand to a value that is a reference to another NNAPI model.
+ *
+ * The referenced model must already have been finished by a call to
+ * {@link ANeuralNetworksModel_finish}.
+ *
+ * The {@link ANeuralNetworksModel_relaxComputationFloat32toFloat16} setting of
+ * referenced models is overridden by that setting of the main model of a
+ * compilation.
+ *
+ * The referenced model must outlive the model referring to it.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has
+ * been called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param value The model to be referenced.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_setOperandValueFromModel(ANeuralNetworksModel* model, int32_t index,
+ const ANeuralNetworksModel* value)
+ __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
+/**
+ * Add an operation to a model.
+ *
+ * @param model The model to be modified.
+ * @param type The {@link ANeuralNetworksOperationType} of the operation.
+ * @param inputCount The number of entries in the inputs array.
+ * @param inputs An array of indexes identifying each operand.
+ * @param outputCount The number of entries in the outputs array.
+ * @param outputs An array of indexes identifying each operand.
+ *
+ * The operands specified by inputs and outputs must have been
+ * previously added by calls to {@link ANeuralNetworksModel_addOperand}.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has been
+ * called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_addOperation(ANeuralNetworksModel* model,
+ ANeuralNetworksOperationType type, uint32_t inputCount,
+ const uint32_t* inputs, uint32_t outputCount,
+ const uint32_t* outputs) __INTRODUCED_IN(27);
+
+/**
+ * Specifies which operands will be the model's inputs and
+ * outputs. Every model must have at least one input and one output.
+ *
+ * An operand cannot be used for both input and output. Doing so will
+ * return an error.
+ *
+ * @param model The model to be modified.
+ * @param inputCount The number of entries in the inputs array.
+ * @param inputs An array of indexes identifying the input operands.
+ * @param outputCount The number of entries in the outputs array.
+ * @param outputs An array of indexes identifying the output operands.
+ *
+ * The operands specified by inputs and outputs must have been
+ * previously added by calls to {@link ANeuralNetworksModel_addOperand}.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has been
+ * called will return an error.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ */
+int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel* model, uint32_t inputCount,
+ const uint32_t* inputs, uint32_t outputCount,
+ const uint32_t* outputs) __INTRODUCED_IN(27);
+
+#if __ANDROID_API__ >= 28
+
+/**
+ * Specifies whether {@link ANEURALNETWORKS_TENSOR_FLOAT32} is allowed to be
+ * calculated with range and/or precision as low as that of the IEEE 754 16-bit
+ * floating-point format. By default, {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * must be calculated using at least the range and precision of the IEEE 754
+ * 32-bit floating-point format.
+ *
+ * The relaxComputationFloat32toFloat16 setting of the main model of
+ * a compilation overrides the values of the referenced models.
+ *
+ * @param model The model to be modified.
+ * @param allow 'true' indicates {@link ANEURALNETWORKS_TENSOR_FLOAT32} may be
+ * calculated with range and/or precision as low as that of the
+ * IEEE 754 16-bit floating point format. 'false' indicates
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32} must be calculated using
+ * at least the range and precision of the IEEE 754 32-bit floating
+ * point format.
+ *
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has been
+ * called will return an error.
+ *
+ * Available since API level 28.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ */
+int ANeuralNetworksModel_relaxComputationFloat32toFloat16(ANeuralNetworksModel* model, bool allow)
+ __INTRODUCED_IN(28);
+
+#endif // __ANDROID_API__ >= 28
+
+/**
+ * Create a {@link ANeuralNetworksCompilation} to compile the given model.
+ *
+ * The model passed to this function is termed the "main model" of the
+ * compilation, to distinguish it from other models referred to by an Operand
+ * of type {@link ANEURALNETWORKS_MODEL} within this compilation.
+ *
+ * <p>This function only creates the object. Compilation is only performed once
+ * {@link ANeuralNetworksCompilation_finish} is invoked.</p>
+ *
+ * <p>{@link ANeuralNetworksCompilation_finish} should be called once
+ * all desired properties have been set on the compilation.</p>
+ *
+ * <p>{@link ANeuralNetworksModel_free} should be called once the compilation
+ * is no longer needed.</p>
+ *
+ * <p>The provided model must outlive the compilation.</p>
+ *
+ * The model must already have been finished by a call to
+ * {@link ANeuralNetworksModel_finish}.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param model The {@link ANeuralNetworksModel} to be compiled.
+ * @param compilation The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA
+ * if the model is invalid.
+ */
+int ANeuralNetworksCompilation_create(ANeuralNetworksModel* model,
+ ANeuralNetworksCompilation** compilation) __INTRODUCED_IN(27);
+
+/**
+ * Destroy a compilation.
+ *
+ * The compilation need not have been finished by a call to
+ * {@link ANeuralNetworksCompilation_finish}.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param compilation The compilation to be destroyed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+void ANeuralNetworksCompilation_free(ANeuralNetworksCompilation* compilation) __INTRODUCED_IN(27);
+
+/**
+ * Sets the execution preference.
+ *
+ * <p>Provides guidance to the runtime when trade-offs are possible. By default the runtime
+ * uses PREFER_SINGLE_FAST_ANSWER</p>
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param compilation The compilation to be modified.
+ * @param preference Either {@link PREFER_LOW_POWER},
+ * {@link PREFER_SINGLE_FAST_ANSWER}, or
+ * {@link PREFER_SUSTAINED_SPEED}.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksCompilation_setPreference(ANeuralNetworksCompilation* compilation,
+ int32_t preference) __INTRODUCED_IN(27);
+
+/**
+ * Indicate that we have finished modifying a compilation. Required before
+ * calling {@link ANeuralNetworksBurst_create} or
+ * {@link ANeuralNetworksExecution_create}.
+ *
+ * An application must ensure that no other thread uses the compilation at the
+ * same time.
+ *
+ * This function must only be called once for a given compilation.
+ *
+ * If {@link ANeuralNetworksCompilation_setTimeout} was called on this
+ * compilation, and the compilation is not able to be finished before the
+ * timeout duration is exceeded, then compilation may be aborted, in which case
+ * {@link ANEURALNETWORKS_MISSED_DEADLINE_*} will be returned.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param compilation The compilation to be finished.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksCompilation_finish(ANeuralNetworksCompilation* compilation) __INTRODUCED_IN(27);
+
+#if __ANDROID_API__ >= 30
+
+/**
+ * Set the execution priority.
+ *
+ * Execution priorities are relative to other executions created by the same
+ * application (specifically same uid) for the same device. Specifically,
+ * priorities of executions from one application will not affect executions from
+ * another application. Similarly, priorities of executions on one device will
+ * not affect executions on another device.
+ *
+ * Higher priority executions may use more compute resources than lower priority
+ * executions, and may preempt or starve lower priority executions.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded usage.
+ *
+ * Available since API level 30.
+ *
+ * @param compilation The compilation to be modified.
+ * @param priority The relative priority of the execution compared to other
+ * executions created by the application. Must be one of
+ * ANEURALNETWORKS_PRIORITY_*.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksCompilation_setPriority(ANeuralNetworksCompilation* compilation, int priority)
+ __INTRODUCED_IN(30);
+
+/**
+ * Set the maximum expected duration for compiling the model.
+ *
+ * If the device is not able to complete the compilation within the specified
+ * duration, the compilation may be aborted. The timeout duration begins at the
+ * call to {@link ANeuralNetworksCompilation_finish}.
+ *
+ * This timeout duration acts as a hint to drivers, and can be used to both free
+ * up compute resources within the driver and return control back to the
+ * application quicker than is possible without the hint. It enables drivers
+ * that are able to estimate how long a compilation will take to abort the
+ * compilation before it has even started if the driver believes the compilation
+ * cannot be completed within the timeout duration. Similarly, it enables
+ * drivers to abort an ongoing compilation if it is taking too long. However,
+ * this call does not guarantee that the compilation will complete or abort
+ * within the timeout duration.
+ *
+ * By default (i.e., unless ANeuralNetworksCompilation_setTimeout is called),
+ * the timeout duration for compiling the model is considered infinite.
+ *
+ * The {@link ANeuralNetworksCompilation} must have been created with
+ * {@link ANeuralNetworksCompilation_createForDevices} with numDevices = 1,
+ * otherwise this function will fail with ANEURALNETWORKS_BAD_DATA. If the
+ * device has a feature level reported by
+ * {@link ANeuralNetworksDevice_getFeatureLevel} that is lower than 30, then the
+ * timeout duration hint will be ignored.
+ *
+ * See {@link ANeuralNetworksCompilation} for information on multithreaded usage.
+ *
+ * @param compilation The compilation to be modified.
+ * @param duration The maximum amount of time in nanoseconds that is expected to
+ * be spent finishing a compilation. If this duration is exceeded, the
+ * compilation may be aborted. If set to 0, the timeout duration is
+ * considered infinite.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 30.
+ */
+int ANeuralNetworksCompilation_setTimeout(ANeuralNetworksCompilation* compilation,
+ uint64_t duration) __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
+/**
+ * Create a {@link ANeuralNetworksExecution} to apply the given compilation.
+ * This only creates the object. Computation is only performed once
+ * {@link ANeuralNetworksExecution_burstCompute},
+ * {@link ANeuralNetworksExecution_compute},
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies} is invoked.
+ *
+ * <p>The provided compilation must outlive the execution.</p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param compilation The {@link ANeuralNetworksCompilation} to be evaluated.
+ * @param execution The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA
+ * if the compilation is invalid.
+ */
+int ANeuralNetworksExecution_create(ANeuralNetworksCompilation* compilation,
+ ANeuralNetworksExecution** execution) __INTRODUCED_IN(27);
+
+/**
+ * Destroy an execution.
+ *
+ * <p>The execution need not have been scheduled by a call to
+ * {@link ANeuralNetworksExecution_burstCompute},
+ * {@link ANeuralNetworksExecution_compute},
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies}; but if it has been scheduled,
+ * then the application must not call {@link ANeuralNetworksExecution_free}
+ * until the execution has completed (i.e.,
+ * {@link ANeuralNetworksExecution_burstCompute},
+ * {@link ANeuralNetworksExecution_compute}, or
+ * {@link ANeuralNetworksEvent_wait} has returned).
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param execution The execution to be destroyed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+void ANeuralNetworksExecution_free(ANeuralNetworksExecution* execution) __INTRODUCED_IN(27);
+
+/**
+ * Associate a user buffer with an input of the model of the
+ * {@link ANeuralNetworksExecution}. Evaluation of the execution must not have
+ * been scheduled. Once evaluation of the execution has been scheduled, the
+ * application must not change the content of the buffer until the execution has
+ * completed. Evaluation of the execution will not change the content of the
+ * buffer.
+ *
+ * <p>The provided buffer must outlive the execution.</p>
+ *
+ * If the input is optional, you can indicate that it is omitted by
+ * passing nullptr for buffer and 0 for length.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param execution The execution to be modified.
+ * @param index The index of the input argument we are setting. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with
+ * {@link ANeuralNetworksModel_addOperand}.
+ * @param type The {@link ANeuralNetworksOperandType} of the
+ * operand. Unless the input is omitted, this should be
+ * used to specify the dimensions that were left
+ * unspecified when the operand was added to the
+ * model. All other properties of the type must be the
+ * same as specified in the model. If the type is the same
+ * as specified when the model was built, NULL can be
+ * passed. Neither the {@link ANeuralNetworksOperandType}
+ * nor the dimensions it points to need to outlive the call
+ * to {@link ANeuralNetworksExecution_setInput}.
+ * @param buffer The buffer containing the data.
+ * @param length The length in bytes of the buffer.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA if the
+ * name is not recognized or the buffer is too small for the input.
+ */
+int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution* execution, int32_t index,
+ const ANeuralNetworksOperandType* type, const void* buffer,
+ size_t length) __INTRODUCED_IN(27);
+
+/**
+ * Associate a region of a memory object with an input of the model of the
+ * {@link ANeuralNetworksExecution}. Evaluation of the execution must not have
+ * been scheduled. Once evaluation of the execution has been scheduled, the
+ * application must not change the content of the region until the execution has
+ * completed. Evaluation of the execution will not change the content of the
+ * region.
+ *
+ * <p>The provided memory must outlive the execution.</p>
+ *
+ * If the input is optional, you can indicate that it is omitted by
+ * using {@link ANeuralNetworksExecution_setInput} instead, passing nullptr for
+ * buffer and 0 for length.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ * See {@link ANeuralNetworksMemory_createFromAHardwareBuffer} for information on
+ * AHardwareBuffer usage.
+ * See {@link ANeuralNetworksMemory_createFromDesc} for information on usage of memory objects
+ * created from memory descriptors.
+ *
+ * Available since API level 27.
+ *
+ * @param execution The execution to be modified.
+ * @param index The index of the input argument we are setting. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link ANeuralNetworksModel_addOperand}.
+ * @param type The {@link ANeuralNetworksOperandType} of the
+ * operand. This should be used to specify the dimensions
+ * that were left unspecified when the operand was added
+ * to the model. All other properties of the type must be
+ * the same as specified in the model. If the type is the
+ * same as specified when the model was built, NULL can be
+ * passed. Neither the {@link ANeuralNetworksOperandType}
+ * nor the dimensions it points to need to outlive the call
+ * to {@link ANeuralNetworksExecution_setInputFromMemory}.
+ * @param memory The memory containing the data.
+ * @param offset This specifies the location of the data within the memory.
+ * The offset is in bytes from the start of memory.
+ * @param length The size in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA if the
+ * name is not recognized or the buffer is too small for the input.
+ */
+int ANeuralNetworksExecution_setInputFromMemory(ANeuralNetworksExecution* execution, int32_t index,
+ const ANeuralNetworksOperandType* type,
+ const ANeuralNetworksMemory* memory, size_t offset,
+ size_t length) __INTRODUCED_IN(27);
+
+/**
+ * Associate a user buffer with an output of the model of the
+ * {@link ANeuralNetworksExecution}. Evaluation of the execution must not have
+ * been scheduled. Once evaluation of the execution has been scheduled, the
+ * application must not change the content of the buffer until the execution has
+ * completed.
+ *
+ * If the output is optional, you can indicate that it is omitted by
+ * passing nullptr for buffer and 0 for length.
+ *
+ * <p>The provided buffer must outlive the execution.</p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param execution The execution to be modified.
+ * @param index The index of the output argument we are setting. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link ANeuralNetworksModel_addOperand}.
+ * @param type The {@link ANeuralNetworksOperandType} of the
+ * operand. Unless the output is omitted, this should be
+ * used to specify the dimensions that were left
+ * unspecified when the operand was added to the
+ * model. All other properties of the type must be the
+ * same as specified in the model. If the type is the same
+ * as specified when the model was built, NULL can be
+ * passed. Neither the {@link ANeuralNetworksOperandType}
+ * nor the dimensions it points to need to outlive the call
+ * to {@link ANeuralNetworksExecution_setOutput}.
+ * Since API level 29, the output operand can have unspecified
+ * dimensions or rank to be deduced dynamically during the execution.
+ * However, the user must provide a large enough buffer. The user
+ * can retrieve the output dimensional information after the execution
+ * by {@link ANeuralNetworksExecution_getOutputOperandRank} and
+ * {@link ANeuralNetworksExecution_getOutputOperandDimensions}.
+ * @param buffer The buffer where the data is to be written.
+ * @param length The length in bytes of the buffer.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA if the
+ * name is not recognized or the buffer is too small for the output.
+ */
+int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution* execution, int32_t index,
+ const ANeuralNetworksOperandType* type, void* buffer,
+ size_t length) __INTRODUCED_IN(27);
+
+/**
+ * Associate a region of a memory object with an output of the model of the
+ * {@link ANeuralNetworksExecution}. Evaluation of the execution must not have
+ * been scheduled. Once evaluation of the execution has been scheduled, the
+ * application must not change the content of the region until the execution has
+ * completed.
+ *
+ * If the output is optional, you can indicate that it is omitted by
+ * using {@link ANeuralNetworksExecution_setOutput} instead, passing nullptr for
+ * buffer and 0 for length.
+ *
+ * <p>The provided memory must outlive the execution.</p>
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ * See {@link ANeuralNetworksMemory_createFromAHardwareBuffer} for information on
+ * AHardwareBuffer usage.
+ * See {@link ANeuralNetworksMemory_createFromDesc} for information on usage of memory objects
+ * created from memory descriptors.
+ *
+ * Available since API level 27.
+ *
+ * @param execution The execution to be modified.
+ * @param index The index of the output argument we are setting. It is
+ * an index into the lists passed to
+ * {@link ANeuralNetworksModel_identifyInputsAndOutputs}. It is not
+ * the index associated with {@link ANeuralNetworksModel_addOperand}.
+ * @param type The {@link ANeuralNetworksOperandType} of the operand. This should be
+ * used to specify the dimensions that were left
+ * unspecified when the operand was added to the
+ * model. All other properties of the type must be the
+ * same as specified in the model. If the type is the same
+ * as specified when the model was built, NULL can be
+ * passed. Neither the {@link ANeuralNetworksOperandType}
+ * nor the dimensions it points to need to outlive the call
+ * to {@link ANeuralNetworksExecution_setOutputFromMemory}.
+ * Since API level 29, the output operand can have unspecified
+ * dimensions or rank to be deduced dynamically during the execution.
+ * However, the user must provide a large enough memory. The user
+ * can retrieve the output dimensional information after the execution
+ * by {@link ANeuralNetworksExecution_getOutputOperandRank} and
+ * {@link ANeuralNetworksExecution_getOutputOperandDimensions}.
+ * @param memory The memory where the data is to be stored.
+ * @param offset This specifies the location of the data within the memory.
+ * The offset is in bytes from the start of memory.
+ * @param length The length in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful, ANEURALNETWORKS_BAD_DATA if the
+ * name is not recognized or the buffer is too small for the output.
+ */
+int ANeuralNetworksExecution_setOutputFromMemory(ANeuralNetworksExecution* execution, int32_t index,
+ const ANeuralNetworksOperandType* type,
+ const ANeuralNetworksMemory* memory, size_t offset,
+ size_t length) __INTRODUCED_IN(27);
+
+/**
+ * Schedule asynchronous evaluation of the execution.
+ *
+ * <p>Schedules asynchronous evaluation of the execution. Once the execution
+ * has completed and the outputs are ready to be consumed, the returned event
+ * will be signaled. Use {@link ANeuralNetworksEvent_wait} to wait for that
+ * event.
+ * </p>
+ *
+ * ANeuralNetworksEvent_wait must be called to recuperate the resources used
+ * by the execution.
+ *
+ * If {@link ANeuralNetworksExecution_setTimeout} was called on this execution,
+ * and the execution is not able to complete before the timeout duration is
+ * exceeded, then execution may be aborted, in which case
+ * {@link ANEURALNETWORKS_MISSED_DEADLINE_*} will be returned through
+ * {@link ANeuralNetworksExecution_startCompute} or
+ * {@link ANeuralNetworksEvent_wait} on the event object. If the device has a
+ * feature level reported by {@link ANeuralNetworksDevice_getFeatureLevel} that
+ * is lower than 30, then the timeout duration hint will be ignored.
+ *
+ * If this execution contains a {@link ANEURALNETWORKS_WHILE} operation, and
+ * the condition model does not output false within the loop timeout duration,
+ * then execution will be aborted and {@link ANEURALNETWORKS_MISSED_DEADLINE_*}
+ * will be returned through {@link ANeuralNetworksEvent_wait} on the event
+ * object.
+ *
+ * If the device can detect before the execution has started that the execution
+ * will not complete within the timeout duration, the device may choose to skip
+ * the execution and instead return {@link ANEURALNETWORKS_MISSED_DEADLINE_*}.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * See {@link ANeuralNetworksExecution_compute} for synchronous execution.
+ * See {@link ANeuralNetworksExecution_burstCompute} for burst synchronous execution.
+ * See {@link ANeuralNetworksExecution_startComputeWithDependencies} for
+ * asynchronous execution with dependencies.
+ *
+ * Available since API level 27.
+ *
+ * @param execution The execution to be scheduled and executed.
+ * @param event The event that will be signaled on completion. event is set to
+ * NULL if there's an error.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the evaluation is successfully scheduled.
+ */
+int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution* execution,
+ ANeuralNetworksEvent** event) __INTRODUCED_IN(27);
+
+#if __ANDROID_API__ >= 30
+
+/**
+ * Set the maximum expected duration of the specified execution.
+ *
+ * If the device is not able to complete the execution within the specified
+ * duration, the execution may be aborted. The timeout duration begins at a
+ * call to one of:
+ * - {@link ANeuralNetworksExecution_burstCompute}
+ * - {@link ANeuralNetworksExecution_compute}
+ * - {@link ANeuralNetworksExecution_startCompute}
+ * - {@link ANeuralNetworksExecution_startComputeWithDependencies}
+ *
+ * This timeout duration acts as a hint to drivers, and can be used to both free
+ * up compute resources within the driver and return control back to the
+ * application quicker than is possible without the hint. It enables drivers
+ * that are able to estimate how long an execution will take to abort the
+ * execution before it has even started if the driver believes the execution
+ * cannot be completed within the timeout duration. Similarly, it enables
+ * drivers to abort an ongoing execution if it is taking too long. However, this
+ * call does not guarantee that the execution will complete or abort within the
+ * timeout duration.
+ *
+ * By default (i.e., unless ANeuralNetworksExecution_setTimeout is called),
+ * the timeout duration for execution is considered infinite.
+ *
+ * The {@link ANeuralNetworksExecution} must have been created from an
+ * {@link ANeuralNetworksCompilation} which in turn was created from
+ * {@link ANeuralNetworksCompilation_createForDevices} with numDevices = 1,
+ * otherwise this function will fail with ANEURALNETWORKS_BAD_DATA. If the
+ * device has a feature level reported by
+ * {@link ANeuralNetworksDevice_getFeatureLevel} that is lower than 30, then the
+ * timeout duration hint will be ignored.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param execution The execution to be modified.
+ * @param duration The maximum amount of time in nanoseconds that is expected to
+ * be spent executing a model. If this duration is exceeded, the execution
+ * may be aborted. If set to 0, the timeout duration is considered infinite.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 30.
+ */
+int ANeuralNetworksExecution_setTimeout(ANeuralNetworksExecution* execution, uint64_t duration)
+ __INTRODUCED_IN(30);
+
+/**
+ * Set the maximum duration of WHILE loops in the specified execution.
+ *
+ * This is a fuzzy per-loop timeout intended to prevent infinite loops.
+ *
+ * If a WHILE loop condition model does not output false within the specified
+ * duration, the execution will be aborted.
+ *
+ * See {@link ANeuralNetworks_getDefaultLoopTimeout} and
+ * {@link ANeuralNetworks_getMaximumLoopTimeout} for the default
+ * and maximum timeout values.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * @param execution The execution to be modified.
+ * @param duration The maximum amount of time in nanoseconds that can be spent
+ * executing a WHILE loop. If the specified duration value exceeds the value
+ * produced by {@link ANeuralNetworks_getMaximumLoopTimeout}, it will be
+ * overridden by that value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ * ANEURALNETWORKS_BAD_STATE if execution has started.
+ * ANEURALNETWORKS_UNEXPECTED_NULL if execution is NULL.
+ *
+ * Available since API level 30.
+ */
+int ANeuralNetworksExecution_setLoopTimeout(ANeuralNetworksExecution* execution, uint64_t duration)
+ __INTRODUCED_IN(30);
+
+/**
+ * Get the default timeout value for WHILE loops.
+ *
+ * @return The default timeout value in nanoseconds.
+ *
+ * Available since API level 30.
+ */
+uint64_t ANeuralNetworks_getDefaultLoopTimeout() __INTRODUCED_IN(30);
+
+/**
+ * Get the maximum timeout value for WHILE loops.
+ *
+ * @return The maximum timeout value in nanoseconds.
+ *
+ * Available since API level 30.
+ */
+uint64_t ANeuralNetworks_getMaximumLoopTimeout() __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
+/**
+ * Waits until the execution completes.
+ *
+ * More than one thread can wait on an event. When the execution completes,
+ * all threads will be released.
+ *
+ * If {@link ANeuralNetworksExecution_setTimeout} was called on the execution
+ * corresponding to this event, and the execution is not able to complete
+ * before the duration is exceeded, the execution may be aborted, in which case
+ * {@link ANEURALNETWORKS_MISSED_DEADLINE_*} will be returned here.
+ *
+ * If the execution contains a {@link ANEURALNETWORKS_WHILE} operation, and
+ * the condition model does not output false within the loop timeout duration,
+ * the execution will be aborted, and {@link ANEURALNETWORKS_MISSED_DEADLINE_*}
+ * will be returned here.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param event The event that will be signaled on completion.
+ * @return ANEURALNETWORKS_NO_ERROR if the execution completed normally.
+ * ANEURALNETWORKS_UNMAPPABLE if the execution input or output memory cannot
+ * be properly mapped.
+ */
+int ANeuralNetworksEvent_wait(ANeuralNetworksEvent* event) __INTRODUCED_IN(27);
+
+/**
+ * Destroys the event.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * Available since API level 27.
+ *
+ * @param event The event object to be destroyed. Passing NULL is acceptable and
+ * results in no operation.
+ */
+void ANeuralNetworksEvent_free(ANeuralNetworksEvent* event) __INTRODUCED_IN(27);
+
+#endif // __ANDROID_API__ >= 27
+
+#if __ANDROID_API__ >= 30
+/**
+ * Create a {@link ANeuralNetworksEvent} from a sync_fence file descriptor.
+ *
+ * The newly created ANeuralNetworksEvent does not take ownership of the provided sync_fence_fd,
+ * it will instead dup the provided sync_fence_fd and own the duplicate.
+ *
+ * @param sync_fence_fd The sync_fence file descriptor.
+ * @param event The newly created object or NULL if unsuccessful.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 30.
+ */
+int ANeuralNetworksEvent_createFromSyncFenceFd(int sync_fence_fd, ANeuralNetworksEvent** event)
+ __INTRODUCED_IN(30);
+
+/**
+ * Get sync_fence file descriptor from the event.
+ *
+ * If the ANeuralNetworksEvent is not backed by a sync fence, the sync_fence_fd
+ * will be set to -1, and ANEURALNETWORKS_BAD_DATA will be returned.
+ *
+ * See {@link ANeuralNetworksEvent_createFromSyncFenceFd} and
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies} to see how to create
+ * an event backed by a sync fence.
+ *
+ * The user takes ownership of the returned fd, and must close the returned file descriptor when
+ * it is no longer needed.
+ *
+ * @param event An event that is backed by a sync fence.
+ * @param sync_fence_fd The sync_fence file descriptor. The file descriptor will
+ * be set to -1 if there is an error.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 30.
+ */
+int ANeuralNetworksEvent_getSyncFenceFd(const ANeuralNetworksEvent* event, int* sync_fence_fd)
+ __INTRODUCED_IN(30);
+
+/**
+ * Schedule asynchronous evaluation of the execution with dependencies.
+ *
+ * The execution will wait for all the depending events to be signaled before
+ * starting the evaluation. Once the execution has completed and the outputs
+ * are ready to be consumed, the returned event will be signaled. Depending on which
+ * devices are handling the execution, the event could be backed by a sync fence.
+ * Use {@link ANeuralNetworksEvent_wait} to wait for that event.
+ *
+ * ANeuralNetworksEvent_wait must be called to recurperate the resources used
+ * by the execution.
+ *
+ * If parts of the execution are scheduled on devices that do not support fenced execution,
+ * the function call may wait for such parts to finish before returning.
+ *
+ * The function will return an error if any of the events in dependencies is already in a bad
+ * state. After the execution is scheduled, if any of the events in dependencies does not complete
+ * normally, the execution will fail, and {@link ANeuralNetworksEvent_wait} on the returned
+ * event will return an error.
+ *
+ * The function will return an error if any of the execution outputs has a tensor operand type
+ * that is not fully specified.
+ *
+ * The function can be passed a timeout duration in nanoseconds. This timeout
+ * duration acts as a hint to drivers in the same way that the timeout durations
+ * in {@link ANeuralNetworksCompilation_setTimeout} and {@link
+ * ANeuralNetworksExecution_setTimeout} act as hints to drivers. The duration
+ * begins when all waitFor sync fences have been signaled, and can be used
+ * together with {@link ANeuralNetworksExecution_setTimeout} which specifies the
+ * maximum timeout duration beginning at the call to
+ * {@link ANeuralNetworksExecution_startComputeWithDependencies}.
+ * If the duration is non-zero, the {@link ANeuralNetworksExecution} must have been created
+ * from an {@link ANeuralNetworksCompilation} which in turn was created from
+ * {@link ANeuralNetworksCompilation_createForDevices} with numDevices = 1,
+ * otherwise this function will fail with ANEURALNETWORKS_BAD_DATA. If either
+ * the timeout duration from {@link ANeuralNetworksExecution_setTimeout} or the
+ * timeout duration passed to this call is exceeded, the execution may be
+ * aborted, in which case {@link ANEURALNETWORKS_MISSED_DEADLINE_*} will be
+ * returned through {@link ANeuralNetworksExecution_startComputeWithDependencies}
+ * or {@link ANeuralNetworksEvent_wait} on the event object. If the device has a
+ * feature level reported by {@link ANeuralNetworksDevice_getFeatureLevel} that
+ * is lower than 30, then the timeout duration hints will be ignored.
+ *
+ * If this execution contains a {@link ANEURALNETWORKS_WHILE} operation, and
+ * the condition model does not output false within the loop timeout duration,
+ * then execution will be aborted and {@link ANEURALNETWORKS_MISSED_DEADLINE_*}
+ * will be returned through {@link ANeuralNetworksEvent_wait} on the event
+ * object.
+ *
+ * See {@link ANeuralNetworksExecution} for information on multithreaded usage.
+ *
+ * See {@link ANeuralNetworksExecution_compute} for synchronous execution.
+ * See {@link ANeuralNetworksExecution_burstCompute} for burst synchronous execution.
+ * See {@link ANeuralNetworksExecution_startCompute} for regular asynchronous execution.
+ *
+ * @param execution The execution to be scheduled and executed.
+ * @param dependencies A set of depending events. The actual evaluation will not start
+ * until all the events are signaled.
+ * @param num_dependencies The number of events in the dependencies set.
+ * @param duration The maximum amount of time in nanoseconds that is expected to
+ * be spent executing the model after all dependencies are
+ * signaled. If set to 0, the timeout duration is considered
+ * infinite.
+ * @param event The event that will be signaled on completion. event is set to
+ * NULL if there's an error.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if the evaluation is successfully scheduled.
+ *
+ * Available since API level 30.
+ */
+int ANeuralNetworksExecution_startComputeWithDependencies(
+ ANeuralNetworksExecution* execution, const ANeuralNetworksEvent* const* dependencies,
+ uint32_t num_dependencies, uint64_t duration, ANeuralNetworksEvent** event)
+ __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
+__END_DECLS
+
+#endif // ANDROID_FRAMEWORKS_ML_NN_RUNTIME_NEURAL_NETWORKS_H
+
+// For compatibility with android, check __ANDROID__ is defined
+#ifndef __ANDROID__
+#undef __ANDROID_API__
+#undef __INTRODUCED_IN
+#endif // __ANDROID__
+
+/** @} */
diff --git a/runtime/nnapi-header/include/NeuralNetworksEx.h b/runtime/nnapi-header/include/NeuralNetworksEx.h
new file mode 100644
index 000000000..d15262e17
--- /dev/null
+++ b/runtime/nnapi-header/include/NeuralNetworksEx.h
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file NeuralNetworksEx.h
+ * @brief This file contains ANeuralNetworksModel_addOperationEx function definition
+ * @note This header describes experimental feature,
+ * so specification here can be changed or/and removed
+ */
+#ifndef NN_RUNTIME_NEURAL_NETWORKS_EX_H
+#define NN_RUNTIME_NEURAL_NETWORKS_EX_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * @brief Extended operation types
+ */
+typedef enum {
+ /** extends operation. */
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_CAST_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_CAST instead
+ *
+ */
+ ANEURALNETWORKS_CAST_EX = 50000,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_GATHER_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_GATHER instead
+ *
+ */
+ ANEURALNETWORKS_GATHER_EX = 50001, /**< Gather slices according to indexes and axis */
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_TOPK_V2_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_TOPK_V2 instead
+ *
+ */
+ ANEURALNETWORKS_TOPK_V2_EX = 50002,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_REDUCE_MAX_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_REDUCE_MAX instead
+ *
+ */
+ ANEURALNETWORKS_REDUCE_MAX_EX = 50003,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_SPLIT_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_SPLIT instead
+ *
+ */
+ ANEURALNETWORKS_SPLIT_EX = 50004, /**< Splits a tensor into sub tensors */
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_RSQRT_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_RSQRT instead
+ *
+ */
+ ANEURALNETWORKS_RSQRT_EX = 50005,
+
+ /**
+ * Computes element-wise squared difference on the input tensors.
+ *
+ * Takes two input tensors of identical {@link OperandCode} and compatible dimensions.
+ * The output is the result of squaring of difference given by subtracting the second input tensor
+ * from the first one.
+ *
+ * Two dimensions are compatible when:
+ * 1. they are equal, or
+ * 2. one of them is 1
+ *
+ * The size of the output is the maximum size along each dimension of the
+ * input operands. It starts with the trailing dimensions, and works its way
+ * forward.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: An n-D tensor, specifying the first input.
+ * * 1: A tensor of the same {@link OperandCode}, and compatible dimensions
+ * as input0.
+ *
+ * Outputs:
+ * * 0: The output tensor, of the same {@link OperandCode} as input0.
+ */
+ ANEURALNETWORKS_SQUARED_DIFFERENCE_EX = 50006,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_NEG_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_NEG instead
+ *
+ */
+ ANEURALNETWORKS_NEG_EX = 50007,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_EXP_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_EXP instead
+ *
+ */
+ ANEURALNETWORKS_EXP_EX = 50008,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_REDUCE_SUM_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_REDUCE_SUM instead
+ *
+ */
+ ANEURALNETWORKS_REDUCE_SUM_EX = 50009,
+
+ /**
+ * A transposed convolutional layer carries out a regular convolution
+ * but reverts its spatial transformation.
+ * Transpose convolution basically performs convolution with transposed weights.
+ *
+ * Supported tensor {@link OperandCode}:
+ * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ *
+ * Supported tensor rank: only 4
+ *
+ * Inputs:
+ * 0: An {@link ANEURALNETWORKS_INT32} 1-D four element tensor, specifying the output shape.
+ * 1: A 4-D tensor, of shape [depth_out, filter_height, filter_width, depth_in],
+ * specifying the filter.
+ * 2: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input.
+ * 3: An {@link ANEURALNETWORKS_INT32} scalar, specifying the padding type.
+ * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * 5: An {@link ANEURALNETWORKS_INT32} scalar, specifying the stride when
+ * walking through input in the height dimension.
+ *
+ * Outputs:
+ * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth_out].
+ */
+ ANEURALNETWORKS_TRANSPOSE_CONV_EX = 50010,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_EQUAL_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_EQUAL instead
+ *
+ */
+ ANEURALNETWORKS_EQUAL_EX = 50011,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_ABS_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_ABS instead
+ *
+ */
+ ANEURALNETWORKS_ABS_EX = 50012,
+ /**
+ * Packs a list of rank-R tensors into one rank- (R+1) tensor along the axis dimension.
+ *
+ * The input tensors must have identical {@link OperandCode} and the same
+ * dimensions.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ *
+ * Supported tensor rank: up to 3
+ *
+ * Inputs:
+ * * 0 ~ n-1: The list of n input tensors, of shape
+ * [D0, D1, ..., Daxis(i), ..., Dm]. For inputs of
+ * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, all input tensors
+ * must have the same scale and zeroPoint.
+ * * n: An {@link ANEURALNETWORKS_INT32} scalar, specifying the
+ * number of input tensors.
+ * * n+1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the
+ * pack axis.
+ *
+ * Outputs:
+ * * 0: The output, a tensor of the same {@link OperandCode} as the input
+ * tensors. The output shape is [D0, D1, ..., N at Daxis(i), ..., Dm+1]
+ * where N is the number of tensors to be packed.
+ */
+ ANEURALNETWORKS_PACK_EX = 50013,
+ /**
+ * Unpacks a given rank-R tensors into num_splits rank- (R-1) tensors along the axis dimension.
+ * num_splits has to respect integral divisibility of dimension value along axis dimension
+ * of the input.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: The input shape is [D0, D1, ..., N at Daxis(i), ..., Dm+1].
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the
+ * number of splits along unpack axis.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar, specifying the
+ * unpack axis.
+ *
+ * Outputs:
+ * * 0 ~ n-1: The list of n output tensors, of shape
+ * [D0, D1, ..., Daxis(i), ..., Dm]. The output tensors are of the same
+ * {@link OperandCode} as the input tensor 0.
+ */
+ ANEURALNETWORKS_UNPACK_EX = 50014,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_ARGMAX_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_ARGMAX instead
+ *
+ */
+ ANEURALNETWORKS_ARGMAX_EX = 50015,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_SQRT_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_SQRT instead
+ *
+ */
+ ANEURALNETWORKS_SQRT_EX = 50016,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_NOT_EQUAL_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_NOT_EQUAL instead
+ *
+ */
+ ANEURALNETWORKS_NOT_EQUAL_EX = 50017,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_LOGICAL_NOT_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_LOGICAL_NOT instead
+ *
+ */
+ ANEURALNETWORKS_LOGICAL_NOT_EX = 50018,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_LOGICAL_AND_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_LOGICAL_AND instead
+ *
+ */
+ ANEURALNETWORKS_LOGICAL_AND_EX = 50019,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_LOGICAL_OR_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_LOGICAL_OR instead
+ *
+ */
+ ANEURALNETWORKS_LOGICAL_OR_EX = 50020,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_REDUCE_MIN_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_REDUCE_MIN instead
+ *
+ */
+ ANEURALNETWORKS_REDUCE_MIN_EX = 50021,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_PRELU_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_PRELU instead
+ *
+ */
+ ANEURALNETWORKS_PRELU_EX = 50022,
+
+ /**
+ * Returns a one-hot tensor.
+ *
+ * The locations represented by indices in indices take value on_value, while all other locations
+ * take value off_value.
+ * The on_value and off_value must have matching data types. They must be the same data type as
+ * specified by the data type of output.
+ *
+ * If the input indices is rank N, the output will have rank N+1. The new axis is created at
+ * dimension axis.
+ * If indices is a scalar the output shape will be a vector of length depth.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Supported tensor type {@link OperandCode} for on_value and off_value:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Inputs:
+ * * 0: An {@link ANEURALNETWORKS_INT32} tensor, specifying the indices.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar, specifying the depth.
+ * * 2: A tensor, specifying the on_value.
+ * * 3: A tensor, specifying the off_value.
+ * * 4: An {@link ANEURALNETWORKS_INT32} scalar, specifying the axis to fill. Optional.
+ * (default: -1, a new inner-most axis).
+ *
+ * Outputs:
+ * * 0: The one-hot tensor.
+ */
+ ANEURALNETWORKS_ONE_HOT_EX = 50023,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_GREATER_EQUAL_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_GREATER_EQUAL instead
+ *
+ */
+ ANEURALNETWORKS_GREATER_EQUAL_EX = 50024,
+
+ /**
+ *
+ * IMPORTANT NOTICE:
+ * ANEURALNETWORKS_LESS_EX operation is DEPRECATED
+ * Use ANEURALNETWORKS_LESS instead
+ *
+ */
+ ANEURALNETWORKS_LESS_EX = 50025,
+
+ /**
+ * Returns the input tensor's shape as a rank 1 output tensor
+ * If the input shape is [D0, D1, ..., D(N-1) ] and rank is N,
+ * the output tensor is [D0, D1, ... D(N-1)], shape is [N] and rank is 1.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_INT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ *
+ * Supported tensor rank: virtually unlimited
+ *
+ * Inputs:
+ * * 0: The input tensor.
+ *
+ * Outputs:
+ * * 0: The rank-1 shape tensor.
+ */
+ ANEURALNETWORKS_SHAPE_EX = 50026,
+
+ /**
+ * Computes element-wise round() on the input tensor.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor, of the same {@link OperandCode} and dimensions as
+ * the input tensor.
+ */
+ ANEURALNETWORKS_ROUND_EX = 50027,
+
+ /**
+ * Reverses specific dimensions of a tensor.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor to reverse.
+ * * 1: A 1-D tensor of {@link ANEURALNETWORKS_TENSOR_INT32}. The dimensions to reverse
+ *
+ * Outputs:
+ * * 0: The output tensor, of the same {@link OperandCode} and dimensions as
+ * the input tensor.
+ */
+ ANEURALNETWORKS_REVERSE_EX = 50028,
+
+ ANEURALNETWORKS_FILL_EX = 50029,
+
+ ANEURALNETWORKS_SELECT_V2_EX = 50030,
+
+ /**
+ * Make the output tensor same shape to the input tensor and fill zero for all elements.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32, ANEURALNETWORKS_TENSOR_INT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor, of the same {@link OperandCode} and dimensions as
+ * the input tensor.
+ */
+ ANEURALNETWORKS_ZEROS_LIKE_EX = 50031,
+
+ /**
+ * Computes cosine of x element-wise
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ *
+ * Outputs:
+ * * 0: The output tensor, of the same {@link OperandCode} and dimensions as
+ * the input tensor.
+ */
+ ANEURALNETWORKS_COS_EX = 50032,
+
+ /**
+ * Creates a sequence of numbers
+ * that begins at 'start' and extends by increments of 'delta' up to but not including 'limit'.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32, ANEURALNETWORKS_TENSOR_INT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A 0-D Tensor (scalar). 'start' acts as first entry in the range
+ * * 1: A 0-D Tensor (scalar). 'limit' acts as upper limit of sequence
+ * * 2: A 0-D Tensor (scalar). 'delta' acts as number that increments 'start'
+ *
+ * Outputs:
+ * * 0: An 1-D output tensor
+ */
+ ANEURALNETWORKS_RANGE_EX = 50033,
+
+ ANEURALNETWORKS_FUSED_BATCH_NORM_V3_EX = 50034,
+
+ ANEURALNETWORKS_BATCH_MATMUL_EX = 50035,
+
+ /**
+ * Copy a tensor setting everything outside a central band in each innermost matrix.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: An {@link ANEURALNETWORKS_INT32} scalar. Number of subdiagonals to keep. If negative, keep
+ * entire lower triangle.
+ * * 2: An {@link ANEURALNETWORKS_INT32} scalar. Number of superdiagonals to keep. If negative,
+ * keep entire upper triangle.
+ *
+ * Outputs:
+ * * 0: An output tensor. The extracted banded tensor with the same shape as input.
+ */
+ ANEURALNETWORKS_MATRIX_BAND_PART_EX = 50036,
+
+ /**
+ * Tensor contraction over specified indices and outer product
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0 ~ n-1: The list of n input tensors.
+ * * 1: An 1-D tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}. Each element represent
+ * equation character.
+ * Always scalar is 1.0 and zeroPoint is 0
+ *
+ * Outputs:
+ * * 0: An output tensor.
+ */
+ ANEURALNETWORKS_EINSUM_EX = 50037,
+
+ ANEURALNETWORKS_BROADCAST_TO_EX = 50038,
+
+ /** Adds two tensors, element-wise.
+ *
+ * Takes two input tensors of identical type and compatible dimensions. The output
+ * is the sum of both input tensors, optionally modified by an activation function.
+ *
+ * Two dimensions are compatible when:
+ * 1. they are equal, or
+ * 2. one of them is 1
+ *
+ * The size of the output is the maximum size along each dimension of the input operands.
+ * It starts with the trailing dimensions, and works its way forward.
+ *
+ * Example:
+ *
+ * input1.dimension = {4, 1, 2}
+ * input2.dimension = {5, 4, 3, 1}
+ * output.dimension = {5, 4, 3, 2}
+ *
+ * Supported tensor types:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32}
+ * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor.
+ * * 1: A tensor of the same type, and compatible dimensions as input0.
+ * * 2: An INT32 value, and has to be one of the {@link FuseCode} values.
+ * Specifies the activation to invoke on the result of each addition.
+ *
+ * Outputs:
+ * * 0: The sum, a tensor of the same type as input0.
+ */
+ ANEURALNETWORKS_ADDV2_EX = 50039,
+
+ ANEURALNETWORKS_STATELESS_RANDOM_UNIFORM_EX = 50040,
+
+ /** Splits a tensor value into a list of sub tensors.
+ *
+ * Supported tensor {@link OperandCode}:
+ * * {@link ANEURALNETWORKS_TENSOR_FLOAT32, ANEURALNETWORKS_TENSOR_INT32}
+ *
+ * Supported tensor rank: up to 4
+ *
+ * Inputs:
+ * * 0: A tensor to split.
+ * * 1: A tensor containing the sizes of each output tensor along split_dim
+ * * 2: The dimension along which to split
+ *
+ * Outputs:
+ * * 0: Tensor objects resulting from splitting value.
+ */
+ ANEURALNETWORKS_SPLIT_V_EX = 50041
+
+} OperationCodeEx; // extends OperationCode
+
+typedef OperationCodeEx ANeuralNetworksOperationTypeEx;
+
+/**
+ * @brief Add an extended operation to a model.
+ *
+ * @param[in] model The model to be modified.
+ * @param[in] type The type of extended operation.
+ * @param[in] inputCount The number of entries in the inputs array.
+ * @param[in] inputs An array of indexes identifying each operand.
+ * @param[in] outputCount The number of entries in the outputs array.
+ * @param[in] outputs An array of indexes identifying each operand.
+ *
+ * @note The operands specified by inputs and outputs must have been
+ * previously added by calls to {@link ANeuralNetworksModel_addOperand}.\n
+ * Attempting to modify a model once {@link ANeuralNetworksModel_finish} has been
+ * called will return an error.\n
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationTypeEx type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs);
+
+__END_DECLS
+
+#endif // NN_RUNTIME_NEURAL_NETWORKS_EX_H
diff --git a/runtime/nnapi-header/include/NeuralNetworksExtensions.h b/runtime/nnapi-header/include/NeuralNetworksExtensions.h
new file mode 100644
index 000000000..dd51b0301
--- /dev/null
+++ b/runtime/nnapi-header/include/NeuralNetworksExtensions.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_ML_NN_RUNTIME_NEURAL_NETWORKS_EXTENSIONS_H
+#define ANDROID_FRAMEWORKS_ML_NN_RUNTIME_NEURAL_NETWORKS_EXTENSIONS_H
+
+#include "NeuralNetworks.h"
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is not intended for use by general developers -- only
+ * by OEM applications.
+ *
+ * Extensions source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+/**
+ * Queries whether an extension is supported by the driver implementation of the specified device.
+ *
+ * @param device The representation of the specified device.
+ * @param extension The extension name.
+ * @param isExtensionSupported The boolean value indicating whether the extension is supported.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ *
+ * Available since API level 29.
+ */
+int ANeuralNetworksDevice_getExtensionSupport(const ANeuralNetworksDevice* device,
+ const char* extensionName, bool* isExtensionSupported)
+ __INTRODUCED_IN(29);
+
+/**
+ * Creates an operand type from an extension name and an extension operand code.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 29.
+ *
+ * @param model The model to contain the operand.
+ * @param extensionName The extension name.
+ * @param operandCodeWithinExtension The extension operand code.
+ * @param type The operand type.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_getExtensionOperandType(ANeuralNetworksModel* model,
+ const char* extensionName,
+ uint16_t operandCodeWithinExtension, int32_t* type)
+ __INTRODUCED_IN(29);
+
+/**
+ * Creates an operation type from an extension name and an extension operation code.
+ *
+ * See {@link ANeuralNetworksModel} for information on multithreaded usage.
+ *
+ * Available since API level 29.
+ *
+ * @param model The model to contain the operation.
+ * @param extensionName The extension name.
+ * @param operationCodeWithinExtension The extension operation code.
+ * @param type The operation type.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_getExtensionOperationType(ANeuralNetworksModel* model,
+ const char* extensionName,
+ uint16_t operationCodeWithinExtension,
+ ANeuralNetworksOperationType* type)
+ __INTRODUCED_IN(29);
+
+/**
+ * Sets extension operand parameters.
+ *
+ * Available since API level 29.
+ *
+ * @param model The model to be modified.
+ * @param index The index of the model operand we're setting.
+ * @param data A pointer to the extension operand data.
+ * The data does not have to outlive the call to this function.
+ * @param length The size in bytes of the data value.
+ *
+ * @return ANEURALNETWORKS_NO_ERROR if successful.
+ */
+int ANeuralNetworksModel_setOperandExtensionData(ANeuralNetworksModel* model, int32_t index,
+ const void* data, size_t length)
+ __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_FRAMEWORKS_ML_NN_RUNTIME_NEURAL_NETWORKS_EXTENSIONS_H
diff --git a/runtime/onert/CMakeLists.txt b/runtime/onert/CMakeLists.txt
new file mode 100644
index 000000000..88d52a5bd
--- /dev/null
+++ b/runtime/onert/CMakeLists.txt
@@ -0,0 +1,15 @@
+if(NOT BUILD_ONERT)
+ return()
+endif(NOT BUILD_ONERT)
+
+add_subdirectory(backend)
+add_subdirectory(frontend)
+add_subdirectory(core)
+add_subdirectory(api)
+add_subdirectory(sample)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+add_subdirectory(test)
diff --git a/runtime/onert/api/CMakeLists.txt b/runtime/onert/api/CMakeLists.txt
new file mode 100644
index 000000000..b238b1f89
--- /dev/null
+++ b/runtime/onert/api/CMakeLists.txt
@@ -0,0 +1,32 @@
+file(GLOB_RECURSE API_SRC "*.cc")
+
+set(ONERT_DEV nnfw-dev)
+add_library(${ONERT_DEV} SHARED ${API_SRC})
+
+# Public headers to publish
+# nnfw_internal.h is header for runtime developer, so it will not be installed
+# But runtime developer can use nnfw_internal.h by linking nnfw-dev
+set(NNFW_API_HEADERS include/nnfw.h include/nnfw_experimental.h)
+
+target_link_libraries(${ONERT_DEV} PUBLIC nnfw-nnapi-header)
+target_link_libraries(${ONERT_DEV} PRIVATE onert_core)
+target_link_libraries(${ONERT_DEV} PRIVATE jsoncpp tflite_loader circle_loader ${LIB_PTHREAD})
+target_link_libraries(${ONERT_DEV} PRIVATE nnfw_common)
+target_link_libraries(${ONERT_DEV} PRIVATE nnfw_coverage)
+# NOTE Below line is added to remove warning for android build
+# It will be removed after android build uses gold linker
+if (ANDROID)
+ target_link_libraries(${ONERT_DEV} INTERFACE log)
+endif (ANDROID)
+
+target_include_directories(${ONERT_DEV} PUBLIC include)
+set_target_properties(${ONERT_DEV} PROPERTIES PUBLIC_HEADER "${NNFW_API_HEADERS}")
+
+if(CMAKE_BUILD_TYPE_LC STREQUAL "release")
+ add_custom_command(TARGET ${ONERT_DEV} POST_BUILD
+ COMMAND ${CMAKE_STRIP} "--strip-unneeded" $<TARGET_FILE_NAME:${ONERT_DEV}>)
+endif()
+
+install(TARGETS ${ONERT_DEV}
+ LIBRARY DESTINATION lib
+ PUBLIC_HEADER DESTINATION include/nnfw)
diff --git a/runtime/onert/api/include/nnfw.h b/runtime/onert/api/include/nnfw.h
new file mode 100644
index 000000000..76380b4b8
--- /dev/null
+++ b/runtime/onert/api/include/nnfw.h
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file nnfw.h
+ * @brief This file describes runtime API
+ */
+#ifndef __NNFW_H__
+#define __NNFW_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Session to query with runtime
+ *
+ * <p>nnfw_session is started and passed by calling {@link nnfw_create_session}.
+ * Each session has its own inference environment, such as model to inference, backend usage, etc.
+ *
+ * <p>Load model by calling {@link nnfw_load_model_from_file}
+ *
+ * <p>After loading, prepare inference by calling {@link nnfw_prepare}.
+ * Application can set runtime environment before prepare by calling
+ * {@link nnfw_set_available_backends} and {@link nnfw_set_op_backend}, and it is optional.
+ *
+ * <p>Application can inference by calling {@link nnfw_run}.
+ * Before inference, application has responsibility to set input tensor to set input data by calling
+ * {@link nnfw_set_output}, and output tensor to get output by calling {@link nnfw_set_input}
+ *
+ * <p>To support input and output setting, application can get
+ * input and output tensor information by calling<ul>
+ * <li>{@link nnfw_input_size}</li>
+ * <li>{@link nnfw_output_size}</li>
+ * <li>{@link nnfw_input_tensorinfo}</li>
+ * <li>{@link nnfw_output_tensorinfo}</li>
+ * </ul>
+ *
+ * <p>Application can inference many times using one session,
+ * but next inference can do after prior inference end
+ *
+ * <p>Application cannot use muitiple model using one session
+ */
+typedef struct nnfw_session nnfw_session;
+
+/**
+ * @brief Tensor types
+ *
+ * The type of tensor represented in {@link nnfw_tensorinfo}
+ */
+typedef enum {
+ /** A tensor of 32 bit floating point */
+ NNFW_TYPE_TENSOR_FLOAT32 = 0,
+ /** A tensor of 32 bit signed integer */
+ NNFW_TYPE_TENSOR_INT32 = 1,
+ /**
+ * A tensor of 8 bit unsigned integers that represent real numbers.
+ *
+ * real_value = (integer_value - zeroPoint) * scale.
+ */
+ NNFW_TYPE_TENSOR_QUANT8_ASYMM = 2,
+ /** A tensor of boolean */
+ NNFW_TYPE_TENSOR_BOOL = 3,
+
+ /** A tensor of 8 bit unsigned integer */
+ NNFW_TYPE_TENSOR_UINT8 = 4,
+
+ /** A tensor of 64 bit signed integer */
+ NNFW_TYPE_TENSOR_INT64 = 5,
+
+ /**
+ * A tensor of 8 bit signed integers that represent real numbers.
+ *
+ * real_value = (integer_value - zeroPoint) * scale.
+ */
+ NNFW_TYPE_TENSOR_QUANT8_ASYMM_SIGNED = 6,
+
+} NNFW_TYPE;
+
+/**
+ * @brief Result values returned from a call to an API function
+ */
+typedef enum {
+ /** Successful */
+ NNFW_STATUS_NO_ERROR = 0,
+ /**
+ * An error code for general use.
+ * Mostly used when there is no specific value for that certain situation.
+ */
+ NNFW_STATUS_ERROR = 1,
+ /** Unexpected null argument is given. */
+ NNFW_STATUS_UNEXPECTED_NULL = 2,
+ /** When a function was called but it is not valid for the current session state. */
+ NNFW_STATUS_INVALID_STATE = 3,
+ /** When it is out of memory */
+ NNFW_STATUS_OUT_OF_MEMORY = 4,
+ /** When it was given an insufficient output buffer */
+ NNFW_STATUS_INSUFFICIENT_OUTPUT_SIZE = 5,
+} NNFW_STATUS;
+
+/**
+ * @brief Data format of a tensor
+ */
+typedef enum {
+ /** Don't care layout */
+ NNFW_LAYOUT_NONE = 0,
+ /**
+ * Channel last layout
+ * If rank is 4, layout is NHWC
+ */
+ NNFW_LAYOUT_CHANNELS_LAST = 1,
+ /**
+ * Channel first layout
+ * If rank is 4, layout is NCHW
+ */
+ NNFW_LAYOUT_CHANNELS_FIRST = 2,
+} NNFW_LAYOUT;
+
+/**
+ * @brief Information ID for retrieving information on nnfw (e.g. version)
+ */
+typedef enum {
+ /** nnfw runtime version
+ * Its value is uint32 in 0xMMmmmmPP, where MM = major, mmmm = minor, PP = patch.
+ */
+ NNFW_INFO_ID_VERSION = 0,
+} NNFW_INFO_ID;
+
+/**
+ * @brief Maximum rank expressible with nnfw
+ */
+#define NNFW_MAX_RANK (6)
+
+/**
+ * @brief tensor info describes the type and shape of tensors
+ *
+ * <p>This structure is used to describe input and output tensors.
+ * Application can get input and output tensor type and shape described in model by using
+ * {@link nnfw_input_tensorinfo} and {@link nnfw_output_tensorinfo}
+ *
+ * <p>Maximum rank is 6 (NNFW_MAX_RANK). And tensor's dimension value is filled in 'dims' field from
+ * index 0.
+ * For example, if tensor's rank is 4,
+ * application can get dimension value from dims[0], dims[1], dims[2], and dims[3]
+ */
+typedef struct nnfw_tensorinfo
+{
+ /** The data type */
+ NNFW_TYPE dtype;
+ /** The number of dimensions (rank) */
+ int32_t rank;
+ /**
+ * The dimension of tensor.
+ * Maximum rank is 6 (NNFW_MAX_RANK).
+ */
+ int32_t dims[NNFW_MAX_RANK];
+} nnfw_tensorinfo;
+
+/**
+ * @brief Create a new session instance.
+ *
+ * <p>This only creates a session.
+ * Model is loaded after {@link nnfw_load_model_from_file} is invoked.
+ * And inference is performed after {@link nnfw_run} is invoked.
+ *
+ * <p>{@link nnfw_close_session} should be called once
+ * if session is no longer need
+ *
+ * @param[out] session The session to be created
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_create_session(nnfw_session **session);
+
+/**
+ * @brief Close a session instance
+ *
+ * After called, access to closed session by application will be invalid
+ *
+ * @param[in] session The session to be closed
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_close_session(nnfw_session *session);
+
+/**
+ * @brief Load model from nnpackage file or directory
+ *
+ * The length of \p package_file_path must not execeed 1024 bytes including zero at the end.
+ *
+ * @param[in] session nnfw_session loading the given nnpackage file/dir
+ * @param[in] package_file_path Path to the nnpackage file or unzipped directory to be loaded
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_load_model_from_file(nnfw_session *session, const char *package_file_path);
+
+/**
+ * @brief Apply i-th input's tensor info to resize input tensor
+ *
+ * This function should be called before {@link nnfw_prepare} is invoked, and
+ * should be called after {@link nnfw_load_model_from_file} is invoked
+ * See {@link nnfw_prepare} for information applying updated tensor info
+ * If this function is called many times for same index, tensor info is overwritten
+ *
+ * @deprecated Deprecated since 1.7.0. Use {@link nnfw_set_input_tensorinfo} instead.
+ *
+ * @param[in] session Session to the input tensor info is to be set
+ * @param[in] index Index of input to be applied (0-indexed)
+ * @param[in] tensor_info Tensor info to be applied
+ * @return @c NNFW_STATUS_NO_ERROR if successful, otherwise return @c NNFW_STATUS_ERROR
+ */
+NNFW_STATUS nnfw_apply_tensorinfo(nnfw_session *session, uint32_t index,
+ nnfw_tensorinfo tensor_info);
+
+/**
+ * @brief Set input model's tensor info for resizing
+ *
+ * This function can be called at any time after calling {@link nnfw_model_load_from_file}. Changing
+ * input tensor's shape will cause shape inference for the model. There are two different types of
+ * shape inference - static and dynamic. Which one to use is depend on the current state of the
+ * session.
+ * When it is called after calling {@link nnfw_model_load_from_file} and before calling {@link
+ * nnfw_prepare}, this info will be used when {@link nnfw_prepare}. And it will perform static shape
+ * inference for all tensors.
+ * When it is called after calling {@link nnfw_prepare} or even after {@link nnfw_run}, this info
+ * will be used when {@link nnfw_run}. And the shapes of the tensors are determined on the fly.
+ * If this function is called many times for the same index, it is overwritten.
+ *
+ * @param[in] session Session to the input tensor info is to be set
+ * @param[in] index Index of input to be set (0-indexed)
+ * @param[in] tensor_info Tensor info to be set
+ * @return @c NNFW_STATUS_NO_ERROR if successful, otherwise return @c NNFW_STATUS_ERROR
+ */
+NNFW_STATUS nnfw_set_input_tensorinfo(nnfw_session *session, uint32_t index,
+ const nnfw_tensorinfo *tensor_info);
+
+/**
+ * @brief Prepare session to be ready for inference
+ *
+ * This phase may finalize model compilation, scheduling, and additional settings.
+ * If {@link nnfw_apply_tensor} is called to apply input tensor info different with model
+ * before this function, tries to resize all tensors.
+ *
+ * @param[in] session the session to be prepared
+ * @return @c NNFW_STATUS_NO_ERROR if successful, otherwise return @c NNFW_STATUS_ERROR
+ */
+NNFW_STATUS nnfw_prepare(nnfw_session *session);
+
+/**
+ * @brief Run inference
+ *
+ * <p>This function should be called after model is loaded by {@link nnfw_load_model_from_file},
+ * session is prepared for inference by {@link nnfw_prepare}, set input and output buffers
+ * by {@link nnfw_set_input} and {@link nnfw_set_output}.</p>
+ *
+ * <p>This function return after inference is finished.</p>
+ *
+ * @param[in] session The session to run inference
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_run(nnfw_session *session);
+
+/**
+ * @brief Run inference asynchronously
+ *
+ * <p>This function must be called after model is loaded by {@link nnfw_load_model_from_file},
+ * session is prepared for inference by {@link nnfw_prepare}, set input and output buffers
+ * by {@link nnfw_set_input} and {@link nnfw_set_output}.</p>
+ *
+ * <p>This function returns immediately after starting a thread to run the inference.
+ * To get the result of it or to do the next inference with {@link nnfw_run} or
+ * {@link nnfw_run_async}, {@link nnfw_await} must be called to ensure the current asynchronous
+ * inference has finished. Only one asynchronous inference is allowed at a time for a session.
+ * If this function is called while the previous one is still running, it returns an error.</p>
+ *
+ * @param[in] session The session to run inference
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_run_async(nnfw_session *session);
+
+/**
+ * @brief Wait for asynchronous run to finish
+ *
+ * <p>This function must be called after calling {@link nnfw_run_asnyc}, and can be called only once
+ * for a {@link nnfw_run_async} call.
+ *
+ * <p>When this function returns, it means that this session has finished the asynchronous run. Then
+ * the user can safely use the output data.</p>
+ *
+ * <p>This function returns after the asynchronous inference is finished.</p>
+ *
+ * @param[in] session The session to run inference
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_await(nnfw_session *session);
+
+/**
+ * @brief Set input buffer
+ *
+ * This function must be called after {@link nnfw_prepare}, \p buffer given to this function can be
+ * reused for many inferences. \p length must be greater or equal than the operand requires. To
+ * specify an optional input, you can either not call this for that input or call this with \p
+ * buffer of NULL and \p length of 0.
+ *
+ * @param[in] session Session to the input is to be set
+ * @param[in] index Index of input to be set (0-indexed)
+ * @param[in] type Type of the input
+ * @param[in] buffer Raw buffer for input
+ * @param[in] length Size of bytes of input buffer
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_input(nnfw_session *session, uint32_t index, NNFW_TYPE type,
+ const void *buffer, size_t length);
+
+/**
+ * @brief Set output buffer
+ *
+ * This function must be called after {@link nnfw_prepare}, \p buffer given to this function can be
+ * reused for many inferences. \p length must be greater or equal than the operand requires. An
+ * output operand can have unspecified shape and deduced dynamically during the execution. You must
+ * provide \p buffer large enough.
+ *
+ * @param[in] session Session from inference output is to be extracted
+ * @param[in] index Index of output to be set (0-indexed)
+ * @param[in] type Type of the output
+ * @param[out] buffer Raw buffer for output
+ * @param[in] length Size of bytes of output buffer
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_output(nnfw_session *session, uint32_t index, NNFW_TYPE type, void *buffer,
+ size_t length);
+
+/**
+ * @brief Get the number of inputs
+ *
+ * Application can call this function to get number of inputs defined in loaded model.
+ * This function should be called after {@link nnfw_load_model_from_file} is invoked to load model
+ *
+ * @param[in] session Session from input information is to be extracted
+ * @param[out] number Variable which the number of inputs is put into
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_input_size(nnfw_session *session, uint32_t *number);
+
+/**
+ * @brief Get the number of outputs
+ *
+ * Application can call this function to get number of outputs defined in loaded model.
+ * This function should be called after {@link nnfw_load_model_from_file} is invoked to load model
+ *
+ * @param[in] session Session from output information is to be extracted
+ * @param[out] number Variable which the number of outputs is put into
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_output_size(nnfw_session *session, uint32_t *number);
+
+/**
+ * @brief Set the layout of an input
+ *
+ * The input that does not call this has NNFW_LAYOUT_NHWC layout
+ *
+ * @param[in] session session from inference input is to be extracted
+ * @param[in] index index of input to be set (0-indexed)
+ * @param[in] layout layout to set to target input
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_input_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout);
+
+/**
+ * @brief Set the layout of an output
+ *
+ * The output that does not call this has NNFW_LAYOUT_NHWC layout
+ *
+ * @param[in] session session from inference output is to be extracted
+ * @param[in] index index of output to be set (0-indexed)
+ * @param[in] layout layout to set to target output
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_output_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout);
+
+/**
+ * @brief Get i-th input tensor info
+ *
+ * <p>Before {@link nnfw_prepare} is invoked, this function return tensor info in model,
+ * so updated tensor info by {@link nnfw_apply_tensorinfo} is not returned.</p>
+ *
+ * <p>After {@link nnfw_prepare} is invoked, this function return updated tensor info
+ * if tensor info is updated by {@link nnfw_apply_tensorinfo}.</p>
+ *
+ * @param[in] session Session from input information is to be extracted
+ * @param[in] index Index of input
+ * @param[out] tensor_info Tensor info (shape, type, etc)
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_input_tensorinfo(nnfw_session *session, uint32_t index,
+ nnfw_tensorinfo *tensor_info);
+
+/**
+ * @brief Get i-th output tensor info
+ *
+ * <p>After {@link nnfw_load_model_from_file} and before {@link nnfw_prepare} is invoked, it returns
+ * tensor info in the model.</p>
+ *
+ * <p>After {@link nnfw_prepare} and before {@link nnfw_run} is invoked, this function returns
+ * updated tensor info if tensor info is updated by {@link nnfw_set_input_tensorinfo}.</p>
+ *
+ * <p>After {@link nnfw_run} is invoked(at least once), it returns the updated tensor info during
+ * the latest execution.</p>
+ *
+ * @param[in] session Session from output information is to be extracted
+ * @param[in] index Index of output
+ * @param[out] tensor_info Tensor info (shape, type, etc)
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_output_tensorinfo(nnfw_session *session, uint32_t index,
+ nnfw_tensorinfo *tensor_info);
+
+/**
+ * @brief Set available backends
+ *
+ * This function should be called before {@link nnfw_prepare} is invoked.
+ *
+ * <p>Supported backends differs on each platforms.
+ * For example, `x86_64` supports "cpu" only.
+ * Multiple backends can be set and they must be separated by a semicolon (ex: "acl_cl;cpu").
+ * For each backend string, `libbackend_{backend}.so` will be dynamically loaded during
+ * {@link nnfw_prepare}.
+ * Among the multiple backends, the 1st element is used as the default backend.</p>
+ *
+ * @param[in] session session to which avilable backends are set
+ * @param[in] backends available backends on which nnfw uses
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_available_backends(nnfw_session *session, const char *backends);
+
+/**
+ * @brief Set the operation's backend
+ *
+ * This function should be called before {@link nnfw_prepare} is invoked.
+ *
+ * <p>The backend for op has higher priority than available backends specified by
+ * {@link nnfw_set_available_backends}.</p>
+ *
+ * @deprecated Deprecated since 1.8.0.
+ *
+ * @param[in] session session to be modified
+ * @param[in] op operation to be set
+ * @param[in] backend bakcend on which operation run
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_op_backend(nnfw_session *session, const char *op, const char *backend);
+
+/**
+ * @brief Retrieve uint32 type of nnfw information for given information ID.
+ *
+ * <p>Retrieves the information of property given by information id </p>
+ *
+ * @note: The input session could be null for global information (e.g. runtime version).*
+ *
+ * @param[in] session session to be queried on.
+ * @param[in] information ID to be queried
+ * @param[out] val uint32 value to be returned.
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_query_info_u32(nnfw_session *session, NNFW_INFO_ID id, uint32_t *val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/onert/api/include/nnfw_experimental.h b/runtime/onert/api/include/nnfw_experimental.h
new file mode 100644
index 000000000..94f781988
--- /dev/null
+++ b/runtime/onert/api/include/nnfw_experimental.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_EXPERIMENTAL_H__
+#define __NNFW_EXPERIMENTAL_H__
+
+#include "nnfw.h"
+
+// Used for custom kernel development
+
+/*
+ * operand type, used only for custom operations
+ */
+typedef struct
+{
+ nnfw_tensorinfo type;
+ void *allocation;
+} nnfw_operand;
+
+/*
+ * Used as input to custom operation eval function
+ */
+typedef struct
+{
+ size_t ninputs;
+ nnfw_operand *inputs;
+
+ size_t noutputs;
+ nnfw_operand *outputs;
+} nnfw_custom_kernel_params;
+
+/*
+ * Custom kernel evaluation function
+ *
+ * param[in] params custom operation parameters
+ * param[in] userdata pointer to user-specified buffer( kernel instance specific )
+ */
+typedef void (*nnfw_custom_eval)(nnfw_custom_kernel_params *params, char *userdata,
+ size_t userdata_size);
+
+/*
+ * custom operation registration info
+ */
+typedef struct
+{
+ nnfw_custom_eval eval_function;
+} custom_kernel_registration_info;
+
+NNFW_STATUS nnfw_register_custom_op_info(nnfw_session *session, const char *id,
+ custom_kernel_registration_info *info);
+
+/**
+ * @brief Get the input tensor index by name
+ *
+ * This function finds an input tensor of the given name.
+ * If found, the index value is set to the address that @c index points to, and returns
+ * @c NNFW_STATUS_NO_ERROR. Otherwise, @c index is unchanged and returns @c NNFW_STATUS_ERROR .
+ *
+ * @note If two or more input tensors are of the same name, the one with the lowest index is always
+ * returned.
+ *
+ * @param[in] session the session object
+ * @param[in] tensorname the name of the tensor to find, a null terminated char pointer string
+ * @param[out] index the index to be ret
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_input_tensorindex(nnfw_session *session, const char *tensorname, uint32_t *index);
+
+/**
+ * @brief Get the input tensor index by name
+ *
+ * This function finds an input tensor of the given name.
+ * If found, the index value is set to the address that @c index points to, and returns
+ * @c NNFW_STATUS_NO_ERROR. Otherwise, @c index is unchanged and returns @c NNFW_STATUS_ERROR .
+ *
+ * @note If two or more input tensors are of the same name, the one with the lowest index is always
+ * returned.
+ *
+ * @param[in] session the session object
+ * @param[in] tensorname the name of the tensor to find, a null terminated char pointer string
+ * @param[out] index the index to be ret
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_output_tensorindex(nnfw_session *session, const char *tensorname, uint32_t *index);
+
+#endif // __NNFW_EXPERIMENTAL_H__
diff --git a/runtime/onert/api/include/nnfw_internal.h b/runtime/onert/api/include/nnfw_internal.h
new file mode 100644
index 000000000..eb4b6d629
--- /dev/null
+++ b/runtime/onert/api/include/nnfw_internal.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_INTERNAL_H__
+#define __NNFW_INTERNAL_H__
+
+#include "nnfw.h"
+
+NNFW_STATUS nnfw_set_config(nnfw_session *session, const char *key, const char *value);
+
+NNFW_STATUS nnfw_get_config(nnfw_session *session, const char *key, char *value, size_t value_size);
+
+/**
+ * @brief Load a circle model from buffer.
+ *
+ * The buffer must outlive the session.
+ *
+ * @param[in] session session
+ * @param[in] buffer Pointer to the buffer
+ * @param[in] size Buffer size
+ * @return NNFW_STATUS
+ */
+NNFW_STATUS nnfw_load_circle_from_buffer(nnfw_session *session, uint8_t *buffer, size_t size);
+
+#endif // __NNFW_INTERNAL_H__
diff --git a/runtime/onert/api/include/nnfw_version.h b/runtime/onert/api/include/nnfw_version.h
new file mode 100644
index 000000000..4044cb657
--- /dev/null
+++ b/runtime/onert/api/include/nnfw_version.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_VERSION_H__
+#define __NNFW_VERSION_H__
+
+/**
+ * NNFW_VERSION is a uint32 value representing nnfw runtime version
+ * in 0xMMmmmmPP, where MM = major, mmmm = minor, PP = patch
+ */
+#define NNFW_VERSION 0x01000b00
+
+#endif // __NNFW_VERSION_H__
diff --git a/runtime/onert/api/src/CustomKernel.cc b/runtime/onert/api/src/CustomKernel.cc
new file mode 100644
index 000000000..3f3a5d81e
--- /dev/null
+++ b/runtime/onert/api/src/CustomKernel.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CustomKernel.h"
+
+namespace onert
+{
+namespace frontend
+{
+namespace custom
+{
+
+using namespace backend::custom;
+
+class APIConverter
+{
+public:
+ static nnfw_operand convertOperand(void *alloc, const TypeInfo &type)
+ {
+ nnfw_operand api_operand;
+ api_operand.allocation = alloc;
+ api_operand.type = convertType(type);
+ return api_operand;
+ }
+
+ static nnfw_tensorinfo convertType(const TypeInfo &type)
+ {
+ nnfw_tensorinfo api_type;
+ api_type.rank = type.shape.rank();
+ assert(type.shape.rank() <= 6);
+ std::copy(type.shape.dims().begin(), type.shape.dims().end(), std::begin(api_type.dims));
+
+ switch (type.dtype)
+ {
+ case ir::DataType::FLOAT32:
+ api_type.dtype = NNFW_TYPE_TENSOR_FLOAT32;
+ break;
+ case ir::DataType::INT32:
+ api_type.dtype = NNFW_TYPE_TENSOR_INT32;
+ break;
+ case ir::DataType::QUANT_UINT8_ASYMM:
+ api_type.dtype = NNFW_TYPE_TENSOR_QUANT8_ASYMM;
+ break;
+ case ir::DataType::BOOL8:
+ api_type.dtype = NNFW_TYPE_TENSOR_BOOL;
+ break;
+ default:
+ throw std::runtime_error("Unsupported tensor datatype");
+ }
+ return api_type;
+ }
+};
+
+Kernel::Kernel(const nnfw_custom_eval evalFunction)
+ : _in_params(), _userdata(nullptr), _userdata_size(0), _evalFunction(evalFunction)
+{
+}
+
+void Kernel::configure(CustomKernelConfigParams &&inParams)
+{
+ _userdata = inParams.userdata;
+ _userdata_size = inParams.userdata_size;
+
+ _in_params = std::move(inParams);
+}
+
+void Kernel::run()
+{
+ nnfw_custom_kernel_params params;
+
+ // set input tensor buffer and types
+ params.ninputs = _in_params.input_tensors.size();
+ params.inputs = new nnfw_operand[params.ninputs];
+
+ for (size_t i = 0; i < params.ninputs; ++i)
+ {
+ auto *buf = _in_params.input_tensors[i]->buffer();
+ assert(buf);
+ params.inputs[i] = APIConverter::convertOperand(buf, _in_params.input_types[i]);
+ }
+
+ // set output tensor buffer and types
+ params.noutputs = _in_params.output_tensors.size();
+ params.outputs = new nnfw_operand[params.noutputs];
+
+ for (size_t i = 0; i < params.noutputs; ++i)
+ {
+ auto *buf = _in_params.output_tensors[i]->buffer();
+ assert(buf);
+ params.outputs[i] = APIConverter::convertOperand(buf, _in_params.output_types[i]);
+ }
+
+ _evalFunction(&params, _userdata, _userdata_size);
+
+ delete[] params.inputs;
+ delete[] params.outputs;
+}
+
+} // namespace custom
+} // namespace frontend
+} // namespace onert
diff --git a/runtime/onert/api/src/CustomKernel.h b/runtime/onert/api/src/CustomKernel.h
new file mode 100644
index 000000000..a42f7a639
--- /dev/null
+++ b/runtime/onert/api/src/CustomKernel.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CUSTOM_KERNEL_H__
+#define __ONERT_BACKEND_CUSTOM_KERNEL_H__
+
+#include "nnfw_experimental.h"
+
+#include "backend/CustomKernelBuilder.h"
+#include "exec/IFunction.h"
+
+#include <vector>
+
+namespace onert
+{
+namespace frontend
+{
+namespace custom
+{
+
+class Kernel : public ::onert::exec::IFunction
+{
+public:
+ explicit Kernel(nnfw_custom_eval evalFunction);
+
+ backend::custom::CustomKernelConfigParams _in_params;
+
+ char *_userdata;
+ size_t _userdata_size;
+
+ nnfw_custom_eval _evalFunction;
+ // nnfw_custom_type_infer _type_infer_function; //Unused for now
+
+ /**
+ * Fills _params field used later by user specified eval function
+ * @param inParams custom kernel parameters
+ */
+ virtual void configure(backend::custom::CustomKernelConfigParams &&inParams);
+
+ void run() override;
+};
+
+} // namespace custom
+} // namespace frontend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CUSTOM_KERNEL_H__
diff --git a/runtime/onert/api/src/CustomKernelRegistry.cc b/runtime/onert/api/src/CustomKernelRegistry.cc
new file mode 100644
index 000000000..7812609d1
--- /dev/null
+++ b/runtime/onert/api/src/CustomKernelRegistry.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CustomKernelRegistry.h"
+
+#include <memory>
+
+namespace onert
+{
+namespace frontend
+{
+namespace custom
+{
+
+void KernelRegistry::registerKernel(const std::string &id, nnfw_custom_eval evalFunction)
+{
+ _storage.emplace(id, evalFunction);
+}
+
+std::shared_ptr<backend::custom::IKernelBuilder> KernelRegistry::getBuilder()
+{
+ return std::make_unique<KernelBuilder>(this);
+}
+
+std::unique_ptr<Kernel> KernelRegistry::buildKernelForOp(const std::string &id)
+{
+ auto it = _storage.find(id);
+ if (it == _storage.end())
+ {
+ throw std::runtime_error("Unable to find associated kernel for op");
+ }
+
+ return std::make_unique<Kernel>(it->second);
+}
+
+// Kernel builder
+std::unique_ptr<exec::IFunction>
+KernelBuilder::buildKernel(const std::string &id,
+ backend::custom::CustomKernelConfigParams &&params) const
+{
+ auto kernel = _registry->buildKernelForOp(id);
+ kernel->configure(std::move(params));
+
+ return kernel;
+}
+
+KernelBuilder::KernelBuilder(KernelRegistry *registry) : _registry(registry) {}
+
+} // namespace custom
+} // namespace frontend
+} // namespace onert
diff --git a/runtime/onert/api/src/CustomKernelRegistry.h b/runtime/onert/api/src/CustomKernelRegistry.h
new file mode 100644
index 000000000..fe60d5bcc
--- /dev/null
+++ b/runtime/onert/api/src/CustomKernelRegistry.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CUSTOM_KERNEL_REGISTRY_H__
+#define __ONERT_BACKEND_CUSTOM_KERNEL_REGISTRY_H__
+
+#include "CustomKernel.h"
+
+#include <unordered_map>
+#include <functional>
+#include <memory>
+
+#include <iostream>
+
+namespace onert
+{
+namespace frontend
+{
+namespace custom
+{
+
+class KernelRegistry
+{
+public:
+ void registerKernel(const std::string &id, nnfw_custom_eval evalFunction);
+
+ std::shared_ptr<backend::custom::IKernelBuilder> getBuilder();
+ std::unique_ptr<Kernel> buildKernelForOp(const std::string &id);
+
+private:
+ std::unordered_map<std::string, nnfw_custom_eval> _storage;
+};
+
+class KernelBuilder : public backend::custom::IKernelBuilder
+{
+public:
+ KernelBuilder(KernelRegistry *registry);
+
+ std::unique_ptr<exec::IFunction>
+ buildKernel(const std::string &id,
+ backend::custom::CustomKernelConfigParams &&params) const override;
+
+private:
+ KernelRegistry *_registry;
+};
+
+} // namespace custom
+} // namespace frontend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CUSTOM_KERNEL_REGISTRY_H__
diff --git a/runtime/onert/api/src/OpMap.lst b/runtime/onert/api/src/OpMap.lst
new file mode 100644
index 000000000..fa8afae5e
--- /dev/null
+++ b/runtime/onert/api/src/OpMap.lst
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MAP_MACRO
+#error Define MAP_MACRO before including this file
+#endif
+
+// Table: circle operation ID order
+// circle operation | onert internal operation
+MAP_MACRO(ADD , Add)
+MAP_MACRO(AVERAGE_POOL_2D , AvgPool2D)
+MAP_MACRO(CONCATENATION , Concat)
+MAP_MACRO(CONV_2D , Conv2D)
+MAP_MACRO(DEPTHWISE_CONV_2D , DepthwiseConv2D)
+// DEPTH_TO_SPACE
+MAP_MACRO(DEQUANTIZE , Dequantize)
+MAP_MACRO(EMBEDDING_LOOKUP , EmbeddingLookup)
+MAP_MACRO(FLOOR , Floor)
+MAP_MACRO(FULLY_CONNECTED , FullyConnected)
+MAP_MACRO(HASHTABLE_LOOKUP , HashtableLookup)
+MAP_MACRO(L2_NORMALIZATION , L2Normalization)
+MAP_MACRO(L2_POOL_2D , L2Pool2D)
+MAP_MACRO(LOCAL_RESPONSE_NORMALIZATION , LocalResponseNormalization)
+MAP_MACRO(LOGISTIC , Logistic)
+// LSH_PROJECTION
+MAP_MACRO(LSTM , LSTM)
+MAP_MACRO(MAX_POOL_2D , MaxPool2D)
+MAP_MACRO(MUL , Mul)
+MAP_MACRO(RELU , ReLU)
+MAP_MACRO(RELU_N1_TO_1 , ReLU1)
+MAP_MACRO(RELU6 , ReLU6)
+MAP_MACRO(RESHAPE , Reshape)
+MAP_MACRO(RESIZE_BILINEAR , ResizeBilinear)
+MAP_MACRO(RNN , RNN)
+MAP_MACRO(SOFTMAX , Softmax)
+MAP_MACRO(SPACE_TO_DEPTH , SpaceToDepth)
+// SVDF
+MAP_MACRO(TANH , Tanh)
+// CONCAT_EMBEDDINGS
+// SKIP_GRAM
+// CALL
+MAP_MACRO(CUSTOM , Custom)
+// EMBEDDING_LOOKUP_SPARSE
+MAP_MACRO(PAD , Pad)
+// UNIDIRECTIONAL_SEQUENCE_RNN
+MAP_MACRO(GATHER , Gather)
+MAP_MACRO(BATCH_TO_SPACE_ND , BatchToSpaceND)
+MAP_MACRO(SPACE_TO_BATCH_ND , SpaceToBatchND)
+MAP_MACRO(TRANSPOSE , Transpose)
+MAP_MACRO(MEAN , Mean)
+MAP_MACRO(SUB , Sub)
+MAP_MACRO(DIV , Div)
+MAP_MACRO(SQUEEZE , Squeeze)
+// UNIDIRECTIONAL_SEQUENCE_LSTM
+MAP_MACRO(STRIDED_SLICE , StridedSlice)
+// BIDIRECTIONAL_SEQUENCE_RNN
+MAP_MACRO(EXP , Exp)
+MAP_MACRO(TOPK_V2 , TopKV2)
+MAP_MACRO(SPLIT , Split)
+// LOG_SOFTMAX
+// DELEGATE
+// BIDIRECTIONAL_SEQUENCE_LSTM
+MAP_MACRO(CAST , Cast)
+MAP_MACRO(PRELU , PReLU)
+MAP_MACRO(MAXIMUM , Max)
+MAP_MACRO(ARG_MAX , ArgMax)
+MAP_MACRO(MINIMUM , Min)
+// LESS (Comparison) ?
+MAP_MACRO(NEG , Neg)
+// PADV2
+// GREATER (Comparison) ?
+// GREATER_EQUAL (Comparison) ?
+// LESS_EQUAL (Comparison) ?
+MAP_MACRO(SELECT , Select)
+MAP_MACRO(SLICE , Slice)
+MAP_MACRO(SIN , Sin)
+MAP_MACRO(TRANSPOSE_CONV , TransposeConv)
+// SPARSE_TO_DENSE
+MAP_MACRO(TILE , Tile)
+MAP_MACRO(EXPAND_DIMS , ExpandDims)
+// EQUAL (Comparison) ?
+// NOT_EQUAL (Comparison) ?
+MAP_MACRO(LOG , Log)
+MAP_MACRO(SUM , ReduceSum)
+MAP_MACRO(SQRT , SQRT)
+MAP_MACRO(RSQRT , RSQRT)
+MAP_MACRO(SHAPE , Shape)
+MAP_MACRO(POW , Pow)
+// ARG_MIN
+// FAKE_QUANT
+MAP_MACRO(REDUCE_PROD , ReduceProd)
+MAP_MACRO(REDUCE_MAX , ReduceMax)
+MAP_MACRO(PACK , Pack)
+MAP_MACRO(LOGICAL_OR , LogicalOr)
+MAP_MACRO(ONE_HOT , OneHot)
+MAP_MACRO(LOGICAL_AND , LogicalAnd)
+MAP_MACRO(LOGICAL_NOT , LogicalNot)
+MAP_MACRO(UNPACK , Unpack)
+MAP_MACRO(REDUCE_MIN , ReduceMin)
+// FLOOR_DIV
+MAP_MACRO(REDUCE_ANY , ReduceAny)
+// SQUARE
+MAP_MACRO(ZEROS_LIKE , ZerosLike)
+MAP_MACRO(FILL , Fill)
+// FLOOR_MOD
+MAP_MACRO(RANGE , Range)
+// RESIZE_NEAREST_NEIGHBOR
+// LEAKY_RELU
+MAP_MACRO(SQUARED_DIFFERENCE , SquaredDifference)
+// MIRROR_PAD
+MAP_MACRO(ABS , Abs)
+// SPLIT_V
+// UNIQUE
+// CEIL
+MAP_MACRO(REVERSE_V2 , Reverse)
+// ADD_N
+// GATHER_ND
+MAP_MACRO(COS , Cos)
+// WHERE
+// RANK
+// ELU
+// REVERSE_SEQUENCE
+// MATRIX_DIAG
+// QUANTIZE
+// MATRIX_SET_DIAG
+MAP_MACRO(ROUND , Round)
+// HARD_SWISH
+MAP_MACRO(IF , If)
+MAP_MACRO(WHILE , While)
+// NON_MAX_SUPPRESSION_V4
+// NON_MAX_SUPPRESSION_V5
+// SCATTER_ND
+// SELECT_V2 (Select) ?
+// DENSIFY
+// SEGMENT_SUM
+MAP_MACRO(BATCH_MATMUL , BatchMatMul)
+MAP_MACRO(BCQ_GATHER , BCQGather)
+MAP_MACRO(BCQ_FULLY_CONNECTED , BCQFullyConnected)
+MAP_MACRO(INSTANCE_NORM , InstanceNorm)
diff --git a/runtime/onert/api/src/nnfw_api.cc b/runtime/onert/api/src/nnfw_api.cc
new file mode 100644
index 000000000..835b2078a
--- /dev/null
+++ b/runtime/onert/api/src/nnfw_api.cc
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nnfw_api_internal.h"
+#include "nnfw_version.h"
+
+// Double-check enum value changes
+
+#define STATIC_ASSERT_ENUM_CHECK(ENUM, VAL) static_assert((ENUM) == (VAL), #ENUM " has changed")
+
+STATIC_ASSERT_ENUM_CHECK(NNFW_TYPE_TENSOR_FLOAT32, 0);
+STATIC_ASSERT_ENUM_CHECK(NNFW_TYPE_TENSOR_INT32, 1);
+STATIC_ASSERT_ENUM_CHECK(NNFW_TYPE_TENSOR_QUANT8_ASYMM, 2);
+STATIC_ASSERT_ENUM_CHECK(NNFW_TYPE_TENSOR_BOOL, 3);
+STATIC_ASSERT_ENUM_CHECK(NNFW_TYPE_TENSOR_UINT8, 4);
+STATIC_ASSERT_ENUM_CHECK(NNFW_TYPE_TENSOR_INT64, 5);
+STATIC_ASSERT_ENUM_CHECK(NNFW_TYPE_TENSOR_QUANT8_ASYMM_SIGNED, 6);
+
+STATIC_ASSERT_ENUM_CHECK(NNFW_STATUS_NO_ERROR, 0);
+STATIC_ASSERT_ENUM_CHECK(NNFW_STATUS_ERROR, 1);
+STATIC_ASSERT_ENUM_CHECK(NNFW_STATUS_UNEXPECTED_NULL, 2);
+STATIC_ASSERT_ENUM_CHECK(NNFW_STATUS_INVALID_STATE, 3);
+STATIC_ASSERT_ENUM_CHECK(NNFW_STATUS_OUT_OF_MEMORY, 4);
+STATIC_ASSERT_ENUM_CHECK(NNFW_STATUS_INSUFFICIENT_OUTPUT_SIZE, 5);
+
+STATIC_ASSERT_ENUM_CHECK(NNFW_LAYOUT_NONE, 0);
+STATIC_ASSERT_ENUM_CHECK(NNFW_LAYOUT_CHANNELS_LAST, 1);
+STATIC_ASSERT_ENUM_CHECK(NNFW_LAYOUT_CHANNELS_FIRST, 2);
+
+STATIC_ASSERT_ENUM_CHECK(NNFW_INFO_ID_VERSION, 0);
+
+#undef STATIC_ASSERT_ENUM_CHECK
+
+#define NNFW_RETURN_ERROR_IF_NULL(p) \
+ do \
+ { \
+ if ((p) == NULL) \
+ return NNFW_STATUS_UNEXPECTED_NULL; \
+ } while (0)
+
+/*
+ * Create a new session instance
+ *
+ * @param session the session to be created
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_create_session(nnfw_session **session)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+
+ *session = new (std::nothrow) nnfw_session();
+ if (*session == nullptr)
+ return NNFW_STATUS_OUT_OF_MEMORY;
+ return NNFW_STATUS_NO_ERROR;
+}
+
+/*
+ * Close a session instance
+ *
+ * @param session the session to be closed
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_close_session(nnfw_session *session)
+{
+ delete session;
+ return NNFW_STATUS_NO_ERROR;
+}
+
+/*
+ * Load model from nnpackage file or directory
+ *
+ * @param session nnfw_session loading the given nnpackage file/dir
+ * @param package_file_path path to the nnpackage file or unzipped directory to be loaded
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_load_model_from_file(nnfw_session *session, const char *pacakge_file_path)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->load_model_from_file(pacakge_file_path);
+}
+
+/*
+ * Prepare session to be ready for inference
+ * This phase may finalize model compilation, scheduling, and additional settings.
+ *
+ * @param session the session to be prepared
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_prepare(nnfw_session *session)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->prepare();
+}
+
+/*
+ * Run inference
+ *
+ * @param session the session to run inference
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_run(nnfw_session *session)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->run();
+}
+
+NNFW_STATUS nnfw_run_async(nnfw_session *session)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->run_async();
+}
+
+NNFW_STATUS nnfw_await(nnfw_session *session)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->await();
+}
+
+/*
+ * Set input
+ *
+ * @param session session to the input is to be set
+ * @param index index of input to be set (0-indexed)
+ * @param type type of the input
+ * @param buffer raw buffer for input
+ * @param length size of bytes of input
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+
+NNFW_STATUS nnfw_set_input(nnfw_session *session, uint32_t index, NNFW_TYPE type,
+ const void *buffer, size_t length)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->set_input(index, type, buffer, length);
+}
+
+/*
+ * Set output
+ *
+ * @param session session from inference output is to be extracted
+ * @param index index of output to be set (0-indexed)
+ * @param type type of the output
+ * @param buffer raw buffer for output
+ * @param length size of bytes of output
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+
+NNFW_STATUS nnfw_set_output(nnfw_session *session, uint32_t index, NNFW_TYPE type, void *buffer,
+ size_t length)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->set_output(index, type, buffer, length);
+}
+
+/*
+ * Get the number of inputs
+ *
+ * @param[in] session session from input information is to be extracted
+ * @param[out] number variable which the number of inputs is put into
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+
+NNFW_STATUS nnfw_input_size(nnfw_session *session, uint32_t *number)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->input_size(number);
+}
+
+/*
+ * Get the number of outputs
+ *
+ * @param[in] session session from output information is to be extracted
+ * @param[out] number variable which the number of outputs is put into
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_output_size(nnfw_session *session, uint32_t *number)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->output_size(number);
+}
+
+/*
+ * Set the layout of an input
+ * @note The input that does not call this has NNFW_LAYOUT_CHANNELS_LAST layout
+ *
+ * @param[in] session session from inference input is to be extracted
+ * @param[in] index index of input to be set (0-indexed)
+ * @param[in] layout layout to set to target input
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_input_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->set_input_layout(index, layout);
+}
+
+/*
+ * Set the layout of an output
+ * @note The output that does not call this has NNFW_LAYOUT_CHANNELS_LAST layout
+ *
+ * @param[in] session session from inference output is to be extracted
+ * @param[in] index index of output to be set (0-indexed)
+ * @param[in] layout layout to set to target output
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_output_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->set_output_layout(index, layout);
+}
+
+/*
+ * Get i-th input tensor info
+ *
+ * @param[in] session session from input information is to be extracted
+ * @param[in] index index of input
+ * @param[out] tensor_info nnfw_tensor_info
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_input_tensorinfo(nnfw_session *session, uint32_t index,
+ nnfw_tensorinfo *tensor_info)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->input_tensorinfo(index, tensor_info);
+}
+
+/*
+ * Get i-th output tensor info
+ *
+ * @param[in] session session from output information is to be extracted
+ * @param[in] index index of output
+ * @param[out] tensor_info nnfw_tensor_info
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_output_tensorinfo(nnfw_session *session, uint32_t index,
+ nnfw_tensorinfo *tensor_info)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->output_tensorinfo(index, tensor_info);
+}
+
+/*
+ * Register custom operation
+ * @param session session to register this operation
+ * @param id operation id
+ * @param info registration info ( eval function, etc. )
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_register_custom_op_info(nnfw_session *session, const char *id,
+ custom_kernel_registration_info *info)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->register_custom_operation(id, info->eval_function);
+}
+
+NNFW_STATUS nnfw_apply_tensorinfo(nnfw_session *session, uint32_t index,
+ nnfw_tensorinfo tensor_info)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->apply_tensorinfo(index, tensor_info);
+}
+
+NNFW_STATUS nnfw_set_input_tensorinfo(nnfw_session *session, uint32_t index,
+ const nnfw_tensorinfo *tensor_info)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->set_input_tensorinfo(index, tensor_info);
+}
+
+/*
+ * Set available backends
+ *
+ * @param[in] session session to which a avilable backends are set
+ * @param[in] backends available backends on which nnfw uses
+ */
+NNFW_STATUS nnfw_set_available_backends(nnfw_session *session, const char *backends)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->set_available_backends(backends);
+}
+
+/*
+ * Set the operation's backend
+ *
+ * @param[in] session session to be modified
+ * @param[in] op operation to be set
+ * @param[in] backend bakcend on which operation run
+ *
+ * @return NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_set_op_backend(nnfw_session *session, const char *op, const char *backend)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->set_op_backend(op, backend);
+}
+
+/*
+ * Retrieve uint32 type of nnfw information for given information ID.
+ *
+ * @param[in] session session to be queried on
+ * @param[in] information ID to be queried
+ * @param[out] val uint32 value to be returned
+ *
+ * @return @c NNFW_STATUS_NO_ERROR if successful
+ */
+NNFW_STATUS nnfw_query_info_u32(nnfw_session *session, NNFW_INFO_ID id, uint32_t *val)
+{
+ (void)session;
+ switch (id)
+ {
+ case NNFW_INFO_ID_VERSION:
+ if (val)
+ {
+ *val = NNFW_VERSION;
+ return NNFW_STATUS_NO_ERROR;
+ }
+ break;
+ default:
+ return NNFW_STATUS_ERROR;
+ }
+ // It should not be reached.
+ return NNFW_STATUS_ERROR;
+}
+
+NNFW_STATUS nnfw_load_circle_from_buffer(nnfw_session *session, uint8_t *buffer, size_t size)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->load_circle_from_buffer(buffer, size);
+}
+
+NNFW_STATUS nnfw_input_tensorindex(nnfw_session *session, const char *tensorname, uint32_t *index)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->input_tensorindex(tensorname, index);
+}
+
+NNFW_STATUS nnfw_output_tensorindex(nnfw_session *session, const char *tensorname, uint32_t *index)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->output_tensorindex(tensorname, index);
+}
diff --git a/runtime/onert/api/src/nnfw_api_internal.cc b/runtime/onert/api/src/nnfw_api_internal.cc
new file mode 100644
index 000000000..a4c69eb4f
--- /dev/null
+++ b/runtime/onert/api/src/nnfw_api_internal.cc
@@ -0,0 +1,895 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nnfw_api_internal.h"
+#include "CustomKernelRegistry.h"
+#include "compiler/Compiler.h"
+#include "util/ConfigSource.h"
+#include "util/Exceptions.h"
+#include "exec/Execution.h"
+#include "circle_loader.h"
+#include "tflite_loader.h"
+#include "json/json.h"
+#include "ir/OpCode.h"
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <dirent.h>
+#include <util/ConfigSource.h>
+#include <misc/string_helpers.h>
+
+/*
+ * API does not accept string argument longer than max length below
+ */
+#define MAX_BACKEND_NAME_LENGTH 32
+#define MAX_OP_NAME_LENGTH 64
+#define MAX_PATH_LENGTH 1024
+#define MAX_TENSOR_NAME_LENGTH 64
+
+// Is null-terminating in length ?
+static bool null_terminating(const char *str, uint32_t length)
+{
+ for (uint32_t i = 0; i < length; i++)
+ {
+ if (*(str + i) == '\0')
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static onert::ir::Layout convertLayout(NNFW_LAYOUT layout)
+{
+ if (layout == NNFW_LAYOUT_CHANNELS_LAST)
+ {
+ return onert::ir::Layout::NHWC;
+ }
+ else if (layout == NNFW_LAYOUT_CHANNELS_FIRST)
+ {
+ return onert::ir::Layout::NCHW;
+ }
+ return onert::ir::Layout::UNKNOWN;
+}
+
+NNFW_STATUS getTensorIndexImpl(const onert::ir::Graph &graph, const char *tensorname,
+ uint32_t *index, bool is_input)
+{
+ if (!tensorname || !index)
+ return NNFW_STATUS_UNEXPECTED_NULL;
+
+ if (!null_terminating(tensorname, MAX_TENSOR_NAME_LENGTH))
+ {
+ std::cerr << "nnpackage path is too long" << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ auto ind_found = is_input ? graph.getInputIndex(tensorname) : graph.getOutputIndex(tensorname);
+
+ if (ind_found.undefined())
+ {
+ // Not found
+ return NNFW_STATUS_ERROR;
+ }
+ else
+ {
+ *index = ind_found.value();
+ return NNFW_STATUS_NO_ERROR;
+ }
+}
+
+nnfw_session::nnfw_session()
+ : _subgraphs{nullptr}, _execution{nullptr},
+ _kernel_registry{std::make_shared<onert::frontend::custom::KernelRegistry>()}
+{
+ // DO NOTHING
+}
+
+nnfw_session::~nnfw_session() = default;
+
+NNFW_STATUS nnfw_session::load_circle_from_buffer(uint8_t *buffer, size_t size)
+{
+ if (!isStateInitialized())
+ return NNFW_STATUS_INVALID_STATE;
+
+ if (!buffer)
+ return NNFW_STATUS_UNEXPECTED_NULL;
+
+ if (size == 0)
+ return NNFW_STATUS_ERROR;
+
+ try
+ {
+ _subgraphs = onert::circle_loader::loadModel(buffer, size);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during model loading : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ _compiler = std::make_unique<onert::compiler::Compiler>(_subgraphs);
+
+ _state = State::MODEL_LOADED;
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::load_model_from_file(const char *package_dir)
+{
+ if (!isStateInitialized())
+ return NNFW_STATUS_INVALID_STATE;
+
+ if (!package_dir)
+ {
+ std::cerr << "package_dir is null." << std::endl;
+ return NNFW_STATUS_UNEXPECTED_NULL;
+ }
+
+ if (!null_terminating(package_dir, MAX_PATH_LENGTH))
+ {
+ std::cerr << "nnpackage path is too long" << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ // TODO : add support for zipped package file load
+ DIR *dir;
+ if (!(dir = opendir(package_dir)))
+ {
+ std::cerr << "invalid nnpackge directory: " << package_dir << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ closedir(dir);
+
+ try
+ {
+ std::string manifest_file_name(package_dir);
+ manifest_file_name += "/metadata/MANIFEST";
+ std::ifstream mfs(manifest_file_name);
+
+ // extract the filename of the first(index 0) model
+ // e.g. In MANIFEST file, { "models" : [ "firstmodel.tflite", "2nd.tflite" ] }
+ Json::Value root;
+ mfs >> root;
+ const Json::Value &models = root["models"];
+ const Json::Value &model_types = root["model-types"];
+
+ auto model_file_path = package_dir + std::string("/") + models[0].asString(); // first model
+ auto model_type = model_types[0].asString(); // first model's type
+ if (model_type == "tflite")
+ {
+ _subgraphs = onert::tflite_loader::loadModel(model_file_path.c_str());
+ }
+ else if (model_type == "circle")
+ {
+ _subgraphs = onert::circle_loader::loadModel(model_file_path.c_str());
+ }
+ else
+ {
+ std::cerr << "Unsupported model type in MANIFEST" << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ _subgraphs->primary()->bindKernelBuilder(_kernel_registry->getBuilder());
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during model loading : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ _compiler = std::make_unique<onert::compiler::Compiler>(_subgraphs);
+
+ _state = State::MODEL_LOADED;
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::prepare()
+{
+ // NOTE. If users want to run prepare() more than one time, this could be removed.
+ if (!isStateModelLoaded())
+ {
+ std::cerr << "Error during model prepare : ";
+ if (isStateInitialized())
+ {
+ std::cerr << "prepare should be run once";
+ }
+ else
+ {
+ std::cerr << "invalid state";
+ }
+ std::cerr << std::endl;
+ return NNFW_STATUS_INVALID_STATE;
+ }
+
+ if (!_subgraphs || !primary_subgraph() || primary_subgraph()->isBuildingPhase())
+ {
+ std::cerr << "Error during model prepare : "
+ << "prepare should be run after load_model" << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ try
+ {
+ _subgraphs.reset();
+ std::shared_ptr<onert::exec::ExecutorMap> executors = _compiler->compile();
+ _execution = std::make_shared<onert::exec::Execution>(executors);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during model prepare : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ _state = State::PREPARED;
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::run()
+{
+ if (!isStatePreparedOrFinishedRun())
+ {
+ std::cerr << "Error during nnfw_session::run : "
+ << "run should be run after prepare" << std::endl;
+ return NNFW_STATUS_INVALID_STATE;
+ }
+
+ try
+ {
+ _execution->execute();
+ }
+ catch (const onert::InsufficientBufferSizeException &e)
+ {
+ // Currently insufficient buffer always means output buffer.
+ std::cerr << "Error during nnfw_session::run : " << e.what() << std::endl;
+ return NNFW_STATUS_INSUFFICIENT_OUTPUT_SIZE;
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::run : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ _state = State::FINISHED_RUN;
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::run_async()
+{
+ if (!isStatePreparedOrFinishedRun())
+ {
+ std::cerr << "Error during nnfw_session::run_async : "
+ << "run_async should be run after prepare" << std::endl;
+ return NNFW_STATUS_INVALID_STATE;
+ }
+
+ _execution->startExecute();
+
+ _state = State::RUNNING;
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::await()
+{
+ if (!isStateRunning())
+ {
+ std::cerr << "Error during nnfw_session::run_await : "
+ << "run_await should be run after run_async" << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ _execution->waitFinish();
+
+ _state = State::FINISHED_RUN;
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::set_input(uint32_t index, NNFW_TYPE /*type*/, const void *buffer,
+ size_t length)
+{
+ if (!isStatePreparedOrFinishedRun())
+ {
+ std::cerr << "Error during nnfw_session::set_input : invalid state" << std::endl;
+ return NNFW_STATUS_INVALID_STATE;
+ }
+
+ if (!buffer && length != 0)
+ {
+ std::cerr
+ << "Error during nnfw_session::set_input : given buffer is NULL but the length is not 0"
+ << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ try
+ {
+ _execution->setInput(onert::ir::IOIndex(index), buffer, length);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::set_input : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::set_output(uint32_t index, NNFW_TYPE /*type*/, void *buffer,
+ size_t length)
+{
+ if (!isStatePreparedOrFinishedRun())
+ {
+ std::cerr << "Error during nnfw_session::set_output : invalid state" << std::endl;
+ return NNFW_STATUS_INVALID_STATE;
+ }
+
+ if (!buffer && length != 0)
+ {
+ std::cerr
+ << "Error during nnfw_session::set_output : given buffer is NULL but the length is not 0"
+ << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ try
+ {
+ _execution->setOutput(onert::ir::IOIndex(index), buffer, length);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::set_output : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::input_size(uint32_t *number)
+{
+ if (isStateInitialized()) // Model is not loaded
+ return NNFW_STATUS_INVALID_STATE;
+
+ try
+ {
+ if (number == nullptr)
+ {
+ std::cerr << "Error during nnfw_session::input_size, number is null pointer." << std::endl;
+ return NNFW_STATUS_UNEXPECTED_NULL;
+ }
+ *number = primary_subgraph()->getInputs().size();
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::input_size : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::output_size(uint32_t *number)
+{
+ if (isStateInitialized()) // Model is not loaded
+ return NNFW_STATUS_INVALID_STATE;
+
+ try
+ {
+ if (number == nullptr)
+ {
+ std::cerr << "Error during nnfw_session::output_size, number is null pointer." << std::endl;
+ return NNFW_STATUS_UNEXPECTED_NULL;
+ }
+ *number = primary_subgraph()->getOutputs().size();
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::output_size" << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::set_input_layout(uint32_t index, NNFW_LAYOUT layout)
+{
+ try
+ {
+ if (layout != NNFW_LAYOUT_NONE && layout != NNFW_LAYOUT_CHANNELS_FIRST &&
+ layout != NNFW_LAYOUT_CHANNELS_LAST)
+ {
+ std::cerr << "Error during nnfw_session::set_input_layout, not supported layout" << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ _execution->setInputLayout(onert::ir::IOIndex(index), convertLayout(layout));
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::set_input_layout : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::set_output_layout(uint32_t index, NNFW_LAYOUT layout)
+{
+ try
+ {
+ if (layout != NNFW_LAYOUT_NONE && layout != NNFW_LAYOUT_CHANNELS_FIRST &&
+ layout != NNFW_LAYOUT_CHANNELS_LAST)
+ {
+ std::cerr << "Error during nnfw_session::set_output_layout, not supported layout"
+ << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ _execution->setOutputLayout(onert::ir::IOIndex(index), convertLayout(layout));
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::set_output_layout : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+static NNFW_TYPE datatype_to_nnfw_dtype(onert::ir::DataType dt)
+{
+ using onert::ir::DataType;
+ switch (dt)
+ {
+ case DataType::FLOAT32:
+ return NNFW_TYPE_TENSOR_FLOAT32;
+ case DataType::INT32:
+ return NNFW_TYPE_TENSOR_INT32;
+ case DataType::QUANT_UINT8_ASYMM:
+ return NNFW_TYPE_TENSOR_QUANT8_ASYMM;
+ case DataType::BOOL8:
+ return NNFW_TYPE_TENSOR_BOOL;
+ case DataType::UINT8:
+ return NNFW_TYPE_TENSOR_UINT8;
+ case DataType::INT64:
+ return NNFW_TYPE_TENSOR_INT64;
+ case DataType::QUANT_INT8_ASYMM:
+ return NNFW_TYPE_TENSOR_QUANT8_ASYMM_SIGNED;
+ case DataType::UINT32:
+ case DataType::QUANT_INT8_SYMM:
+ default:
+ throw std::runtime_error("Error: Model has type that runtime API does not support.");
+ }
+}
+
+NNFW_STATUS nnfw_session::apply_tensorinfo(uint32_t index, nnfw_tensorinfo ti)
+{
+ // sanity check
+ {
+ if (isStateInitialized())
+ {
+ std::cerr << "Error during set_input_tensorinfo : should be run after load_model"
+ << std::endl;
+ return NNFW_STATUS_INVALID_STATE;
+ }
+
+ if (ti.rank <= 0 || ti.rank > NNFW_MAX_RANK)
+ {
+ std::cerr << "unsupported rank: " << ti.rank << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ for (int32_t i = 0; i < ti.rank; ++i)
+ {
+ if (ti.dims[i] <= 0)
+ {
+ std::cerr << "dim must be positive integer but was " << ti.dims[i] << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ }
+ }
+
+ onert::ir::Shape new_shape(ti.rank);
+ for (int32_t i = 0; i < ti.rank; i++)
+ new_shape.dim(i) = ti.dims[i];
+
+ if (!isStatePreparedOrFinishedRun())
+ {
+ // In this case, if we apply input shape in primary_subgraph, it will propagate after
+ // compilation and excution
+ auto ind = primary_subgraph()->getInputs().at(index);
+ auto &input = primary_subgraph()->operands().at(ind);
+
+ // overwrite input shape with the shape from ti
+ input.info().shape(new_shape);
+ }
+ else // when called after nnfw_session::prepare()
+ {
+ _execution->changeInputShape(onert::ir::IOIndex(index), new_shape);
+ }
+
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::set_input_tensorinfo(uint32_t index, const nnfw_tensorinfo *ti)
+{
+ nnfw_tensorinfo ti_copy = *ti;
+ return apply_tensorinfo(index, ti_copy);
+}
+
+NNFW_STATUS nnfw_session::input_tensorinfo(uint32_t index, nnfw_tensorinfo *ti)
+{
+ if (isStateInitialized())
+ return NNFW_STATUS_INVALID_STATE;
+
+ try
+ {
+ if (ti == nullptr)
+ {
+ std::cerr << "Error during nnfw_session::input_tensorinfo, tensorinfo is null pointer."
+ << std::endl;
+ return NNFW_STATUS_UNEXPECTED_NULL;
+ }
+ if (index >= primary_subgraph()->getInputs().size())
+ {
+ std::cerr << "Error during nnfw_session::input_tensorinfo, index is out of range."
+ << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ auto opidx = primary_subgraph()->getInputs().at(index);
+ auto shape = primary_subgraph()->operands().at(opidx).shape();
+ if (isStatePreparedOrFinishedRun())
+ shape = _execution->getInputShape(onert::ir::IOIndex{index});
+ ti->rank = shape.rank();
+ for (int j = 0; j < ti->rank; ++j)
+ {
+ ti->dims[j] = shape.dim(j);
+ }
+ ti->dtype = datatype_to_nnfw_dtype(primary_subgraph()->operands().at(opidx).typeInfo().type());
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::input_tensorinfo : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::output_tensorinfo(uint32_t index, nnfw_tensorinfo *ti)
+{
+ if (isStateInitialized())
+ return NNFW_STATUS_INVALID_STATE;
+
+ if (ti == nullptr)
+ {
+ std::cerr << "Error during nnfw_session::output_tensorinfo, tensorinfo is null pointer."
+ << std::endl;
+ return NNFW_STATUS_UNEXPECTED_NULL;
+ }
+
+ if (index >= primary_subgraph()->getOutputs().size())
+ {
+ std::cerr << "Error during nnfw_session::output_tensorinfo, index is out of range."
+ << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ try
+ {
+ auto opidx = primary_subgraph()->getOutputs().at(index);
+ auto shape = primary_subgraph()->operands().at(opidx).shape();
+ // If it is called after `nnfw_run` then get the shape from Execution, not from the graph
+ if (isStateFinishedRun())
+ shape = _execution->getOutputShape(onert::ir::IOIndex{index});
+ ti->rank = shape.rank();
+ for (int j = 0; j < ti->rank; ++j)
+ {
+ ti->dims[j] = shape.dim(j);
+ }
+ ti->dtype = datatype_to_nnfw_dtype(primary_subgraph()->operands().at(opidx).typeInfo().type());
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::output_tensorinfo : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+
+ return NNFW_STATUS_NO_ERROR;
+}
+NNFW_STATUS nnfw_session::register_custom_operation(const std::string &id,
+ nnfw_custom_eval eval_func)
+{
+ _kernel_registry->registerKernel(id, eval_func);
+ return NNFW_STATUS_NO_ERROR;
+}
+
+static std::string get_op_backend_string(std::string op)
+{
+#define MAP_MACRO(CircleName, OneRTName) {#CircleName, #OneRTName},
+
+ static std::unordered_map<std::string, std::string> operation_map = {
+#include "OpMap.lst"
+ };
+
+#undef MAP_MACRO
+
+ auto n = operation_map.find(op);
+
+ if (n == operation_map.end())
+ {
+ // this return value is handled by a caller to return error code
+ return std::string("");
+ }
+ else
+ {
+ return n->second;
+ }
+}
+
+NNFW_STATUS nnfw_session::set_available_backends(const char *backends)
+{
+ if (!isStateModelLoaded())
+ return NNFW_STATUS_INVALID_STATE;
+
+ try
+ {
+ if (!backends)
+ return NNFW_STATUS_UNEXPECTED_NULL;
+ if (null_terminating(backends, MAX_BACKEND_NAME_LENGTH) == false)
+ return NNFW_STATUS_ERROR;
+
+ auto &options = _compiler->options();
+
+ using namespace onert::util;
+
+ options.backend_list = nnfw::misc::split(std::string{backends}, ';');
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::set_available_backends : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::set_op_backend(const char *op, const char *backend)
+{
+ if (!isStateModelLoaded())
+ return NNFW_STATUS_INVALID_STATE;
+
+ try
+ {
+ if (!op || !backend)
+ return NNFW_STATUS_UNEXPECTED_NULL;
+ if (!null_terminating(op, MAX_OP_NAME_LENGTH) ||
+ !null_terminating(backend, MAX_BACKEND_NAME_LENGTH))
+ return NNFW_STATUS_ERROR;
+
+ auto key = get_op_backend_string(op);
+
+ if (key.empty())
+ {
+ return NNFW_STATUS_ERROR;
+ }
+
+ auto &opcode_to_backend = _compiler->options().manual_scheduler_options.opcode_to_backend;
+ opcode_to_backend.emplace(onert::ir::toOpCode(key), backend);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Error during nnfw_session::set_op_backend : " << e.what() << std::endl;
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+NNFW_STATUS nnfw_session::set_config(const char *key, const char *value)
+{
+ if (!isStateModelLoaded())
+ return NNFW_STATUS_INVALID_STATE;
+
+ if (!key || !value)
+ return NNFW_STATUS_UNEXPECTED_NULL;
+
+ auto &options = _compiler->options();
+
+ using namespace onert::util;
+
+ const std::string skey = key;
+
+ if (skey == config::TRACE_FILEPATH)
+ {
+ options.trace_filepath = value;
+ }
+ else if (skey == config::GRAPH_DOT_DUMP)
+ {
+ options.graph_dump_level = toInt(value);
+ }
+ else if (skey == config::OP_SEQ_MAX_NODE)
+ {
+ options.op_seq_max_node = toInt(value);
+ }
+ else if (skey == config::EXECUTOR)
+ {
+ options.executor = value;
+ }
+ else if (skey == config::OP_BACKEND_ALLOPS)
+ {
+ options.manual_scheduler_options.backend_for_all = value;
+ }
+ else if (skey == config::USE_SCHEDULER)
+ {
+ options.he_scheduler = toBool(value);
+ }
+ else if (skey == config::PROFILING_MODE)
+ {
+ options.he_profiling_mode = toBool(value);
+ }
+ else if (skey == config::DISABLE_COMPILE)
+ {
+ options.disable_compile = toBool(value);
+ }
+ else
+ {
+ return NNFW_STATUS_ERROR;
+ }
+ return NNFW_STATUS_NO_ERROR;
+}
+
+onert::ir::Graph *nnfw_session::primary_subgraph()
+{
+ if (_subgraphs)
+ {
+ assert(!_execution);
+ return _subgraphs->primary().get();
+ }
+ else
+ {
+ assert(_execution);
+ // TODO Remove const_cast
+ // We assumed the graph will not change after compilation, but shape could change
+ return const_cast<onert::ir::Graph *>(&_execution->primary_subgraph());
+ }
+}
+
+NNFW_STATUS nnfw_session::get_config(const char *key, char *value, size_t value_size)
+{
+ if (!isStateModelLoaded())
+ return NNFW_STATUS_INVALID_STATE;
+
+ if (!key || !value)
+ return NNFW_STATUS_UNEXPECTED_NULL;
+
+ auto &options = _compiler->options();
+
+ auto check_boundary = [](size_t dest_size, std::string &src) {
+ if (dest_size < src.length() + 1 /* for '\0' */)
+ {
+ std::cerr << "buffer is small to copy config value." << std::endl;
+ return false;
+ }
+ return true;
+ };
+
+ const std::string skey = key;
+
+ if (skey == onert::util::config::BACKENDS)
+ {
+ if (options.backend_list.size() == 0)
+ return NNFW_STATUS_NO_ERROR; // no setting backend is not an error of get_config_str()
+
+ auto str = nnfw::misc::join(options.backend_list.begin(), options.backend_list.end(), ";");
+
+ if (!check_boundary(value_size, str))
+ return NNFW_STATUS_ERROR;
+
+ strncpy(value, str.c_str(), value_size);
+ }
+ else if (skey == onert::util::config::EXECUTOR)
+ {
+ if (!check_boundary(value_size, options.executor))
+ return NNFW_STATUS_ERROR;
+
+ strncpy(value, options.executor.c_str(), options.executor.length());
+ }
+ else
+ {
+ return NNFW_STATUS_ERROR;
+ }
+
+ return NNFW_STATUS_NO_ERROR;
+}
+
+bool nnfw_session::isStateInitialized()
+{
+ if (_state == State::INITIALIZED)
+ {
+ assert(!_subgraphs);
+ assert(!_compiler);
+ assert(!_execution);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool nnfw_session::isStateModelLoaded()
+{
+ if (_state == State::MODEL_LOADED)
+ {
+ assert(_subgraphs);
+ assert(_compiler);
+ assert(!_execution);
+ assert(!primary_subgraph()->isBuildingPhase());
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool nnfw_session::isStatePrepared()
+{
+ if (_state == State::PREPARED)
+ {
+ assert(!_subgraphs);
+ assert(_compiler);
+ assert(_execution);
+ assert(!primary_subgraph()->isBuildingPhase());
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool nnfw_session::isStateRunning()
+{
+ if (_state == State::RUNNING)
+ {
+ assert(!_subgraphs);
+ assert(_compiler);
+ assert(_execution);
+ assert(!primary_subgraph()->isBuildingPhase());
+ return true;
+ }
+ return false;
+}
+
+bool nnfw_session::isStateFinishedRun()
+{
+ if (_state == State::FINISHED_RUN)
+ {
+ assert(!_subgraphs);
+ assert(_compiler);
+ assert(_execution);
+ assert(!primary_subgraph()->isBuildingPhase());
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool nnfw_session::isStatePreparedOrFinishedRun()
+{
+ return isStatePrepared() || isStateFinishedRun();
+}
+
+NNFW_STATUS nnfw_session::input_tensorindex(const char *tensorname, uint32_t *index)
+{
+ return getTensorIndexImpl(*primary_subgraph(), tensorname, index, true);
+}
+
+NNFW_STATUS nnfw_session::output_tensorindex(const char *tensorname, uint32_t *index)
+{
+ return getTensorIndexImpl(*primary_subgraph(), tensorname, index, false);
+}
diff --git a/runtime/onert/api/src/nnfw_api_internal.h b/runtime/onert/api/src/nnfw_api_internal.h
new file mode 100644
index 000000000..604ba38b4
--- /dev/null
+++ b/runtime/onert/api/src/nnfw_api_internal.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __API_NNFW_API_INTERNAL_H__
+#define __API_NNFW_API_INTERNAL_H__
+
+#include "nnfw.h"
+#include "nnfw_experimental.h"
+
+#include <util/GeneralConfigSource.h>
+
+#include <string>
+#include <memory>
+
+namespace onert
+{
+namespace frontend
+{
+namespace custom
+{
+class KernelRegistry;
+}
+} // namespace frontend
+namespace exec
+{
+class Execution;
+} // namespace exec
+namespace ir
+{
+class Graph;
+class Subgraphs;
+} // namespace ir
+namespace compiler
+{
+class Compiler;
+} // namespace compiler
+} // namespace onert
+
+struct nnfw_session
+{
+private:
+ /**
+ * @brief Enum class to express the session's state
+ *
+ * State transition diagram:
+ *
+ * +--------------+
+ * | INITIALIZED |
+ * +--------------+
+ * |
+ * | load_model
+ * v
+ * +--------------+
+ * | MODEL_LOADED |
+ * +--------------+
+ * |
+ * | prepare
+ * v
+ * +--------------+
+ * | PREPARED | --------+
+ * +--------------+ |
+ * | |
+ * | run |
+ * v |
+ * +--------------+ run |
+ * | | -----+ |
+ * +-----> | FINISHED_RUN | | | run_async
+ * | | | <----+ |
+ * | +--------------+ |
+ * | | |
+ * | await | run_async |
+ * | v |
+ * | +--------------+ |
+ * +------ | RUNNING | <-------+
+ * +--------------+
+ */
+ enum class State
+ {
+ INITIALIZED, //< Session is initialized and nothing has done to it
+ MODEL_LOADED, //< Model is loaded
+ PREPARED, //< Prepared(compiled) for execution
+ RUNNING, //< Execution is in progress (only for asynchronous execution)
+ FINISHED_RUN //< Executed at least once
+ };
+
+public:
+ nnfw_session();
+ ~nnfw_session();
+
+ NNFW_STATUS load_model_from_file(const char *package_file_path);
+ NNFW_STATUS prepare();
+ NNFW_STATUS run();
+
+ NNFW_STATUS run_async();
+ NNFW_STATUS await();
+
+ NNFW_STATUS set_input(uint32_t index, NNFW_TYPE type, const void *buffer, size_t length);
+ NNFW_STATUS set_output(uint32_t index, NNFW_TYPE type, void *buffer, size_t length);
+
+ NNFW_STATUS input_size(uint32_t *number);
+ NNFW_STATUS output_size(uint32_t *number);
+
+ NNFW_STATUS set_input_layout(uint32_t index, NNFW_LAYOUT layout);
+ NNFW_STATUS set_output_layout(uint32_t index, NNFW_LAYOUT layout);
+
+ NNFW_STATUS apply_tensorinfo(uint32_t index, nnfw_tensorinfo ti); // Will be deprecated
+ NNFW_STATUS set_input_tensorinfo(uint32_t index, const nnfw_tensorinfo *ti);
+
+ NNFW_STATUS input_tensorinfo(uint32_t index, nnfw_tensorinfo *ti);
+ NNFW_STATUS output_tensorinfo(uint32_t index, nnfw_tensorinfo *ti);
+
+ NNFW_STATUS set_available_backends(const char *backends);
+ NNFW_STATUS set_op_backend(const char *op, const char *backend);
+
+ //
+ // Internal-only API
+ //
+
+ NNFW_STATUS set_config(const char *key, const char *value);
+ NNFW_STATUS get_config(const char *key, char *value, size_t value_size);
+ NNFW_STATUS load_circle_from_buffer(uint8_t *buffer, size_t size);
+
+ //
+ // Experimental API
+ //
+
+ NNFW_STATUS register_custom_operation(const std::string &id, nnfw_custom_eval eval_func);
+ NNFW_STATUS input_tensorindex(const char *tensorname, uint32_t *index);
+ NNFW_STATUS output_tensorindex(const char *tensorname, uint32_t *index);
+
+private:
+ onert::ir::Graph *primary_subgraph();
+ bool isStateInitialized();
+ bool isStateModelLoaded();
+ bool isStatePrepared();
+ bool isStateRunning();
+ bool isStateFinishedRun();
+ bool isStatePreparedOrFinishedRun();
+
+private:
+ State _state{State::INITIALIZED};
+ std::shared_ptr<onert::ir::Subgraphs> _subgraphs;
+ std::unique_ptr<onert::compiler::Compiler> _compiler;
+ std::shared_ptr<onert::exec::Execution> _execution;
+ std::shared_ptr<onert::frontend::custom::KernelRegistry> _kernel_registry;
+};
+
+#endif // __API_NNFW_API_INTERNAL_H__
diff --git a/runtime/onert/api/src/nnfw_debug.cc b/runtime/onert/api/src/nnfw_debug.cc
new file mode 100644
index 000000000..01e5bf8f2
--- /dev/null
+++ b/runtime/onert/api/src/nnfw_debug.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nnfw_api_internal.h"
+
+#include <util/ConfigSource.h>
+
+#define NNFW_RETURN_ERROR_IF_NULL(p) \
+ do \
+ { \
+ if ((p) == NULL) \
+ return NNFW_STATUS_UNEXPECTED_NULL; \
+ } while (0)
+
+NNFW_STATUS nnfw_set_config(nnfw_session *session, const char *key, const char *value)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->set_config(key, value);
+}
+
+NNFW_STATUS nnfw_get_config(nnfw_session *session, const char *key, char *value, size_t value_size)
+{
+ NNFW_RETURN_ERROR_IF_NULL(session);
+ return session->get_config(key, value, value_size);
+}
diff --git a/runtime/onert/backend/CMakeLists.txt b/runtime/onert/backend/CMakeLists.txt
new file mode 100644
index 000000000..42d622aa8
--- /dev/null
+++ b/runtime/onert/backend/CMakeLists.txt
@@ -0,0 +1,6 @@
+set(LIB_ONERT_BACKEND_ACL_COMMON onert_backend_acl_common)
+
+add_subdirectory(cpu)
+add_subdirectory(acl_cl)
+add_subdirectory(acl_neon)
+add_subdirectory(acl_common)
diff --git a/runtime/onert/backend/acl_cl/Backend.h b/runtime/onert/backend/acl_cl/Backend.h
new file mode 100644
index 000000000..5c5041378
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/Backend.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_BACKEND_H__
+#define __ONERT_BACKEND_ACL_CL_BACKEND_H__
+
+#include <memory>
+#include <backend/Backend.h>
+
+#include "Config.h"
+#include "ConstantInitializer.h"
+#include "KernelGenerator.h"
+#include "TensorManager.h"
+#include "Optimizer.h"
+#include "AclTensorRegistry.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+class Backend : public ::onert::backend::Backend
+{
+public:
+ Backend() : _config{std::make_shared<Config>()} {}
+
+ std::shared_ptr<IConfig> config() const override { return _config; }
+
+ std::unique_ptr<BackendContext> newContext(const ir::Graph &graph,
+ const std::shared_ptr<custom::IKernelBuilder> &,
+ bool is_linear_executor) const override
+ {
+ const auto &operands = graph.operands();
+ const auto &operations = graph.operations();
+ auto context = std::make_unique<BackendContext>(this, &graph);
+ auto tm = createTensorManager(is_linear_executor);
+ auto tr = std::make_shared<acl_common::AclTensorRegistry<TensorManager>>(tm);
+ auto tb = std::make_shared<TensorBuilder>(operands, tm, tr);
+ context->tensor_registry = tr;
+ context->tensor_builder = tb;
+ context->constant_initializer = std::make_shared<ConstantInitializer>(operands, tr);
+ context->kernel_gen = std::make_shared<KernelGenerator>(operands, operations, tb, tr);
+ context->tensor_register = nullptr;
+ context->optimizer = std::make_shared<Optimizer>(context.get());
+ return context;
+ }
+
+private:
+ std::shared_ptr<IConfig> _config;
+};
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_BACKEND_H__
diff --git a/runtime/onert/backend/acl_cl/CLTimer.h b/runtime/onert/backend/acl_cl/CLTimer.h
new file mode 100644
index 000000000..722dc68ef
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/CLTimer.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_CLTIMER_H__
+#define __ONERT_BACKEND_ACL_CL_CLTIMER_H__
+
+#include <util/ITimer.h>
+#include <arm_compute/core/CL/OpenCL.h>
+#include <arm_compute/runtime/CL/CLScheduler.h>
+#include <chrono>
+#include <list>
+#include <sstream>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+/**
+ * @brief Class to measure CL kernels execution time
+ */
+class CLTimer : public util::ITimer
+{
+public:
+ /**
+ * @brief This function replaces CL function, which enqueues a command to execute a kernel
+ * with a wrapper which remembers enqueued kernels
+ */
+ void handleBegin() override
+ {
+ _measured_events.clear();
+
+ _origin_enqueue_function = arm_compute::CLSymbols::get().clEnqueueNDRangeKernel_ptr;
+
+ auto _timer_enqueue_function = [this](cl_command_queue command_queue, cl_kernel kernel,
+ cl_uint work_dim, const size_t *gwo, const size_t *gws,
+ const size_t *lws, cl_uint num_events_in_wait_list,
+ const cl_event *event_wait_list, cl_event *usr_event) {
+ cl_event event;
+ cl_int enqueue_res =
+ this->_origin_enqueue_function(command_queue, kernel, work_dim, gwo, gws, lws,
+ num_events_in_wait_list, event_wait_list, &event);
+ this->_measured_events.emplace_back(event);
+
+ // According to spec, if NULL was provided in usr_event - event shouldn't be returned
+ if (usr_event != nullptr)
+ {
+ clRetainEvent(event);
+ *usr_event = event;
+ }
+ return enqueue_res;
+ };
+ arm_compute::CLSymbols::get().clEnqueueNDRangeKernel_ptr = _timer_enqueue_function;
+
+ // Set CL_QUEUE_PROFILING_ENABLE flag for the CL command-queue, if it isn't already set
+ auto &cl_scheduler = arm_compute::CLScheduler::get();
+ auto props = cl_scheduler.queue().getInfo<CL_QUEUE_PROPERTIES>();
+ if ((props & CL_QUEUE_PROFILING_ENABLE) == 0)
+ {
+ cl_scheduler.set_queue(
+ cl::CommandQueue(cl_scheduler.context(), props | CL_QUEUE_PROFILING_ENABLE));
+ }
+ };
+
+ /**
+ * @brief Get timer result by addition executed CL kernels durations
+ */
+ void handleEnd() override
+ {
+ _timer_res = 0;
+ for (auto const &event : _measured_events)
+ {
+ cl_ulong start;
+ cl_ulong end;
+ event.getProfilingInfo(CL_PROFILING_COMMAND_START, &start);
+ event.getProfilingInfo(CL_PROFILING_COMMAND_END, &end);
+ _timer_res += (end - start) / 1000.f; // nanoseconds -> microseconds
+ }
+
+ // Restore origin CL enqueue function
+ arm_compute::CLSymbols::get().clEnqueueNDRangeKernel_ptr = _origin_enqueue_function;
+ };
+
+private:
+ std::function<decltype(clEnqueueNDRangeKernel)> _origin_enqueue_function;
+ std::list<::cl::Event> _measured_events;
+};
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_CLTIMER_H__
diff --git a/runtime/onert/backend/acl_cl/CMakeLists.txt b/runtime/onert/backend/acl_cl/CMakeLists.txt
new file mode 100644
index 000000000..2c94ea69c
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Unsupported architecture
+nnfw_find_package(ARMCompute QUIET)
+if(NOT ARMCompute_FOUND)
+ return()
+endif(NOT ARMCompute_FOUND)
+
+set(LIB_ONERT_BACKEND_ACL_CL onert_backend_acl_cl)
+
+file(GLOB_RECURSE SOURCES "*.cc")
+
+add_library(${LIB_ONERT_BACKEND_ACL_CL} SHARED ${SOURCES})
+
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_CL} PRIVATE ${LIB_ONERT_BACKEND_ACL_COMMON})
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_CL} PRIVATE nnfw_common)
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_CL} PRIVATE nnfw_coverage)
+
+set_target_properties(${LIB_ONERT_BACKEND_ACL_CL} PROPERTIES OUTPUT_NAME backend_acl_cl)
+
+if(CMAKE_BUILD_TYPE_LC STREQUAL "release")
+ add_custom_command(TARGET onert_backend_acl_cl POST_BUILD
+ COMMAND ${CMAKE_STRIP} "--strip-unneeded" $<TARGET_FILE_NAME:onert_backend_acl_cl>)
+endif()
+
+install(TARGETS ${LIB_ONERT_BACKEND_ACL_CL} DESTINATION lib)
diff --git a/runtime/onert/backend/acl_cl/Config.cc b/runtime/onert/backend/acl_cl/Config.cc
new file mode 100644
index 000000000..8017bdb0b
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/Config.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// For CLKernelLibraryEx initialization
+#include "arm_compute/core/CL/CLHelpers.h"
+#include "arm_compute/core/CL/CLKernelLibrary.h"
+#include "arm_compute/core/CL/CLKernelLibraryEx.h"
+
+#include <util/ConfigSource.h>
+
+#include <arm_compute/runtime/CL/CLScheduler.h>
+
+#include "Config.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+bool Config::initialize()
+{
+ if (!arm_compute::opencl_is_available())
+ {
+ return false;
+ }
+ arm_compute::CLScheduler::get().default_init();
+ // NOTE CLKernelLibraryEx must use the same context as CLScheduler
+ // It did not check whether another device is available.
+ arm_compute::CLKernelLibraryEx::get().init(
+ "./cl_kernels/", arm_compute::CLScheduler::get().context(), cl::Device::getDefault());
+
+ return true;
+}
+
+ir::Layout Config::supportLayout(const ir::Operation &, ir::Layout frontend_layout)
+{
+ const std::string acl_layout_str = util::getConfigString(util::config::ACL_LAYOUT);
+ if (acl_layout_str == "NHWC")
+ {
+ return ir::Layout::NHWC;
+ }
+ else if (acl_layout_str == "NCHW")
+ {
+ return ir::Layout::NCHW;
+ }
+
+ return frontend_layout;
+}
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_cl/Config.h b/runtime/onert/backend/acl_cl/Config.h
new file mode 100644
index 000000000..f71e81b6a
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/Config.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_CONFIG_H__
+#define __ONERT_BACKEND_ACL_CL_CONFIG_H__
+
+#include "CLTimer.h"
+#include <memory>
+#include <backend/IConfig.h>
+#include <arm_compute/runtime/CL/CLScheduler.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+class Config : public IConfig
+{
+public:
+ std::string id() override { return "acl_cl"; }
+ bool initialize() override;
+ bool supportPermutation() override { return true; }
+ ir::Layout supportLayout(const ir::Operation &node, ir::Layout frontend_layout) override;
+ bool supportDynamicTensor() override { return false; }
+ bool supportFP16() override { return true; }
+ void sync() const override { arm_compute::CLScheduler::get().sync(); }
+
+ std::unique_ptr<util::ITimer> timer() override { return std::make_unique<CLTimer>(); }
+};
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_CONFIG_H__
diff --git a/runtime/onert/backend/acl_cl/ConstantInitializer.cc b/runtime/onert/backend/acl_cl/ConstantInitializer.cc
new file mode 100644
index 000000000..b45b91058
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/ConstantInitializer.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <AclActivationBuilder.h>
+#include <AclFunction.h>
+#include <Convert.h>
+#include <Swizzle.h>
+
+#include "ConstantInitializer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+ConstantInitializer::ConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg)
+ : acl_common::AclConstantInitializer{operands, tensor_reg}
+{
+ // DO NOTHING
+}
+
+void ConstantInitializer::visit(const ir::operation::EmbeddingLookup &node)
+{
+ copyInputInitialize(node, ir::operation::EmbeddingLookup::LOOKUPS);
+}
+
+void ConstantInitializer::visit(const ir::operation::Gather &node)
+{
+ copyInputInitialize(node, ir::operation::Gather::INDICES);
+}
+
+void ConstantInitializer::visit(const ir::operation::HashtableLookup &node)
+{
+ copyInputInitialize(node, ir::operation::HashtableLookup::LOOKUPS);
+ copyInputInitialize(node, ir::operation::HashtableLookup::KEYS);
+}
+
+void ConstantInitializer::visit(const ir::operation::SpaceToBatchND &node)
+{
+ const auto &block_size_index = node.getInputs().at(ir::operation::SpaceToBatchND::BLOCK_SIZE);
+ const auto &block_size_obj = _operands.at(block_size_index);
+
+ if (block_size_obj.isConstant())
+ {
+ _init_map[block_size_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) {
+ assert(model_obj.data());
+ const auto &shape = model_obj.shape();
+ const auto base = reinterpret_cast<const int32_t *>(model_obj.data()->base());
+ assert(model_obj.shape().rank() == 1);
+ obj.access([&](ITensor &tensor) {
+ for (size_t i = 0; i < shape.num_elements(); ++i)
+ {
+ const int32_t value = base[shape.num_elements() - i - 1];
+ int32_t *into = reinterpret_cast<int32_t *>(tensor.buffer() +
+ tensor.calcOffset({static_cast<int32_t>(i)}));
+ *into = value;
+ }
+ });
+ };
+ }
+
+ const auto &paddings_index = node.getInputs().at(ir::operation::SpaceToBatchND::PADDINGS);
+ const auto &paddings_obj = _operands.at(paddings_index);
+ if (paddings_obj.isConstant())
+ {
+ _init_map[paddings_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) {
+ assert(model_obj.data());
+ const auto &shape = model_obj.shape();
+ const auto base = reinterpret_cast<const int32_t *>(model_obj.data()->base());
+ assert(model_obj.shape().rank() == 2);
+ assert(obj.dimension(0) == 2);
+ obj.access([&](ITensor &tensor) {
+ for (auto i = 0; i < shape.dim(0); ++i)
+ {
+ for (auto j = 0; j < shape.dim(1); ++j)
+ {
+ const int32_t value = base[i * 2 + j];
+ int32_t *into = reinterpret_cast<int32_t *>(
+ tensor.buffer() + tensor.calcOffset({shape.dim(0) - i - 1, j}));
+ *into = value;
+ }
+ }
+ });
+ };
+ }
+}
+
+void ConstantInitializer::visit(const ir::operation::Reverse &node)
+{
+ const auto &output_index = node.getOutputs().at(0);
+
+ const auto &input_index = node.getInputs().at(ir::operation::Reverse::Input::INPUT);
+ const auto &input_obj = _operands.at(input_index);
+
+ const auto &axis_index = node.getInputs().at(ir::operation::Reverse::Input::AXIS);
+ const auto &axis_obj = _operands.at(axis_index);
+
+ const auto ifm_rank = input_obj.shape().rank();
+ const auto frontend_layout = this->_current_op_seq_layout;
+
+ auto output_tensor = this->_tensor_reg->getITensor(output_index);
+ const auto backend_layout = output_tensor->layout();
+
+ if (axis_obj.isConstant())
+ {
+ _init_map[axis_index] = [ifm_rank, frontend_layout, backend_layout](const ir::Operand &operand,
+ backend::ITensor &obj) {
+ assert(operand.data());
+
+ const auto axis_value = *(reinterpret_cast<const int32_t *>(operand.data()->base()));
+ int32_t axis_tmp = axis_value;
+ if (axis_tmp < 0)
+ {
+ axis_tmp = axis_tmp + ifm_rank;
+ }
+
+ auto axis =
+ acl_common::ToARMComputeAxis(ifm_rank, axis_tmp, frontend_layout, backend_layout).value();
+
+ obj.access([&](ITensor &tensor) {
+ int32_t *into = reinterpret_cast<int32_t *>(tensor.buffer());
+ *into = (int32_t)axis;
+ });
+ };
+ }
+}
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_cl/ConstantInitializer.h b/runtime/onert/backend/acl_cl/ConstantInitializer.h
new file mode 100644
index 000000000..9f3acb461
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/ConstantInitializer.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_ACL_CL_CONSTANT_INITIALIZER_H__
+#define __ONERT_COMPILER_ACL_CL_CONSTANT_INITIALIZER_H__
+
+#include "AclConstantInitializer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+class ConstantInitializer : public acl_common::AclConstantInitializer
+{
+public:
+ ConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg);
+
+public:
+ using acl_common::AclConstantInitializer::visit;
+ void visit(const ir::operation::EmbeddingLookup &) final;
+ void visit(const ir::operation::Gather &) final;
+ void visit(const ir::operation::HashtableLookup &) final;
+ void visit(const ir::operation::SpaceToBatchND &) final;
+ void visit(const ir::operation::Reverse &) final;
+};
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_COMPILER_ACL_CL_CONSTANT_INITIALIZER_H__
diff --git a/runtime/onert/backend/acl_cl/KernelGenerator.cc b/runtime/onert/backend/acl_cl/KernelGenerator.cc
new file mode 100644
index 000000000..e7690af2e
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/KernelGenerator.cc
@@ -0,0 +1,1622 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KernelGenerator.h"
+
+#include <arm_compute/runtime/CL/CLFunctions.h> // Include all ARM Compute CL functions
+#include <arm_compute/runtime/CL/CLFunctionsEx.h> // Include all ARM Compute EX CL functions
+
+#include <AclActivationBuilder.h>
+#include <AclFunction.h>
+#include <Convert.h>
+#include <Swizzle.h>
+
+#include "ir/Index.h"
+#include "ir/DataType.h"
+#include "ir/InternalType.h"
+#include "exec/NopFunction.h"
+#include "exec/FunctionSequence.h"
+#include "util/logging.h"
+#include "util/Utils.h"
+#include "AclKernelGen.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+using ::onert::backend::acl_common::asAclFunction;
+using ActivationBuilder = ::onert::backend::acl_common::AclActivationBuilder<
+ ::arm_compute::ICLTensor, ::arm_compute::CLActivationLayer, acl_common::AclFunction>;
+
+KernelGenerator::KernelGenerator(
+ const ir::Operands &operands_ctx, const ir::Operations &operations_ctx,
+ const std::shared_ptr<TensorBuilder> &tensor_builder,
+ const std::shared_ptr<acl_common::AclTensorRegistry<TensorManager>> &tensor_reg)
+ : _ctx(operands_ctx), _operations_ctx(operations_ctx), _tensor_builder(tensor_builder),
+ _tensor_reg(tensor_reg), _current_op_seq_layout(ir::Layout::UNKNOWN)
+{
+ // DO NOTHING
+}
+
+void KernelGenerator::visit(const ir::OpSequence &op_seq)
+{
+ // TODO Move this to IKernelGenerator
+ // (all derivatives have the same implementation for this)
+ assert(!_return_fn_seq);
+ _return_fn_seq = std::make_unique<exec::FunctionSequence>();
+ _return_fn_seq->enableDynamicShapeInferer(false);
+
+ _current_op_seq_layout = op_seq.getLayout();
+ for (const auto &operation_idx : op_seq.operations())
+ {
+ const auto &node = _operations_ctx.at(operation_idx);
+ node.accept(*this);
+ _return_fn_seq->append(releaseFunction());
+ }
+}
+
+void KernelGenerator::visit(const ir::operation::BatchToSpaceND &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)};
+ const auto block_size_index{
+ node.getInputs().at(ir::operation::BatchToSpaceND::Input::BLOCK_SIZE)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto block_size_tensor = _tensor_reg->getAclTensor(block_size_index);
+
+ assert(_ctx.at(block_size_index).data());
+
+ auto fn = acl_common::generateLayer<arm_compute::CLBatchToSpaceLayer>(
+ ifm_tensor->handle(), block_size_tensor->handle(), ofm_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::BinaryArithmetic &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::BinaryArithmetic::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::BinaryArithmetic::Input::RHS)};
+
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto lhs_tensor = _tensor_reg->getAclTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getAclTensor(rhs_index);
+
+ const auto act_info = acl_common::asActivationLayerInfo(activation);
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ switch (node.param().arithmetic_type)
+ {
+ case ir::operation::BinaryArithmetic::ArithmeticType::ADD:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLArithmeticAddition>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle(),
+ arm_compute::ConvertPolicy::SATURATE, act_info);
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::SUB:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLArithmeticSubtraction>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle(),
+ arm_compute::ConvertPolicy::SATURATE, act_info);
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::MUL:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLPixelWiseMultiplication>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle(), 1.0, // scale
+ arm_compute::ConvertPolicy::SATURATE, arm_compute::RoundingPolicy::TO_NEAREST_EVEN,
+ act_info);
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::DIV:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLArithmeticDivision>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle(), act_info);
+ break;
+ }
+ default:
+ assert(false && "The BinaryArithmetic operation supports only binary arithmetic operations");
+ break;
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Conv2D &node)
+{
+ using ir::operation::Conv2D;
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)};
+ const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)};
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
+ const auto &ker_shape = _ctx.at(ker_index).shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+
+ const auto stride = node.param().stride;
+ const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride,
+ ker_width, ker_height);
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto ker_tensor = _tensor_reg->getAclTensor(ker_index);
+ auto bias_tensor = _tensor_reg->getAclTensor(bias_index);
+
+ const auto conv_info = acl_common::asPadStrideInfo(padding, stride);
+ const auto act_info = acl_common::asActivationLayerInfo(activation);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLConvolutionLayer>(
+ _tensor_builder->acl_tensor_manager()->internal_buffer_manager(), ifm_tensor->handle(),
+ ker_tensor->handle(), bias_tensor->handle(), ofm_tensor->handle(), conv_info,
+ ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), act_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::DepthwiseConv2D &node)
+{
+ using ir::operation::DepthwiseConv2D;
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(DepthwiseConv2D::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)};
+ const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)};
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ // Kernel format is [1, kernel_height, kernel_width, depth_out].
+ const auto &ker_shape = _ctx.at(ker_index).shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+
+ const auto stride = node.param().stride;
+ const auto dilation = node.param().dilation;
+ const auto padding =
+ ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, ker_width,
+ ker_height, dilation.width_factor, dilation.height_factor);
+ const auto multiplier = node.param().multiplier;
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto ker_tensor = _tensor_reg->getAclTensor(ker_index);
+ auto bias_tensor = _tensor_reg->getAclTensor(bias_index);
+
+ const auto conv_info = acl_common::asPadStrideInfo(padding, stride);
+ const auto act_info = acl_common::asActivationLayerInfo(activation);
+ const auto dilation_info = acl_common::asDilation(dilation.width_factor, dilation.height_factor);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLDepthwiseConvolutionLayer>(
+ ifm_tensor->handle(), ker_tensor->handle(), bias_tensor->handle(), ofm_tensor->handle(),
+ conv_info, multiplier, act_info, dilation_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Concat &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ std::vector<ir::OperandIndex> input_indexes;
+
+ for (const auto &input : node.getInputs())
+ input_indexes.emplace_back(input);
+
+ const auto axis = node.param().axis;
+
+ // Concat elimination check
+ bool eliminated = _tensor_builder->areSubTensorsOf(ofm_index, node.getInputs());
+ if (eliminated)
+ {
+ // If concat eliminated, return a NOP IFunction
+ VERBOSE(acl_cl_KernelGenerator_Concat) << "Concat eliminated" << std::endl;
+ _return_fn = std::make_unique<exec::NopFunction>();
+ return;
+ }
+
+ auto output_tensor = _tensor_reg->getAclTensor(ofm_index);
+ std::vector<::arm_compute::ICLTensor *> input_tensors;
+ for (auto &ifm_ind : input_indexes)
+ input_tensors.emplace_back(_tensor_reg->getAclTensor(ifm_ind)->handle());
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+ if (input_indexes.size() < 2)
+ {
+ fn = acl_common::generateLayer<arm_compute::CLCopy>(input_tensors.at(0),
+ output_tensor->handle());
+ }
+ else
+ {
+ const auto rank = _ctx.at(ofm_index).shape().rank();
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = output_tensor->layout();
+ const auto fixed_axis =
+ acl_common::ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value();
+ fn = acl_common::generateLayer<::arm_compute::CLConcatenateLayer>(
+ input_tensors, output_tensor->handle(), fixed_axis);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::FullyConnected &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ const auto activation = node.param().activation;
+ if (node.param().weights_format == ir::FullyConnectedWeightsFormat::Shuffled16x1Float32)
+ throw std::runtime_error(
+ "KernelGenerator(acl_cl): FullyConnected 16x1Float32 weights is not supported.");
+
+ auto fn = acl_common::kernelGenFullyConnected<acl_common::AclFunction, ::arm_compute::ICLTensor,
+ ::arm_compute::CLFullyConnectedReshapingLayer>(
+ node, _ctx, _tensor_builder, _tensor_reg, _current_op_seq_layout);
+ _return_fn = std::make_unique<exec::FunctionSequence>(
+ std::move(fn), ActivationBuilder::generate(activation, output_tensor->handle()));
+}
+
+void KernelGenerator::visit(const ir::operation::Reduce &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Reduce::Input::INPUT)};
+ const auto axes_index{node.getInputs().at(ir::operation::Reduce::Input::AXES)};
+ const auto keep_dims{node.param().keep_dims};
+ const auto reduce_type = node.param().reduce_type;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ // Convert to ACL axes taking into account negative values and possible duplicates.
+ const auto &axes = _ctx.at(axes_index);
+ const auto input_rank = _ctx.at(input_index).shape().rank();
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = input_tensor->layout();
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ if (reduce_type == ir::operation::Reduce::ReduceType::MEAN)
+ {
+ const auto acl_axes =
+ acl_common::asCoordinates(axes, input_rank, frontend_layout, backend_layout);
+ fn = acl_common::generateLayer<arm_compute::CLReduceMean>(input_tensor->handle(), acl_axes,
+ keep_dims, output_tensor->handle());
+ }
+ else
+ {
+ const auto acl_axes = acl_common::asSet(axes, input_rank, frontend_layout, backend_layout);
+
+ fn = acl_common::generateLayer<arm_compute::CLReduceOperation>(
+ _tensor_builder->acl_tensor_manager()->internal_buffer_manager(), input_tensor->handle(),
+ output_tensor->handle(), acl_axes, keep_dims, acl_common::convertReduceType(reduce_type));
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Reshape &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Reshape::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ // NOTE This operation must not be changed the layout from frontend to backend
+ // So, PermutationOperationPass makes layouts of frontend and backend the same.
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = output_tensor->layout();
+ assert((_ctx.at(input_index).shape().rank() < 4 && _ctx.at(output_index).shape().rank() < 4) ||
+ frontend_layout == backend_layout);
+ UNUSED_RELEASE(frontend_layout);
+ UNUSED_RELEASE(backend_layout);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLReshapeLayer>(input_tensor->handle(),
+ output_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Squeeze &node)
+{
+ // Squeeze is identical to reshape except that it has an optional dimensions input.
+ // In addition, optional dims_index is ignored since output tensor already has squeezed shape
+ // by freezer and toco
+ // TODO Support multi-layout for frontend and backend
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Squeeze::Input::INPUT)};
+ const auto dims{node.param().dims};
+ const auto ndim{node.param().ndim};
+ (void)dims;
+ (void)ndim;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+ auto fn = acl_common::generateLayer<arm_compute::CLReshapeLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Softmax &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Softmax::Input::INPUT)};
+
+ const auto beta = node.param().beta;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLSoftmaxLayer>(
+ _tensor_builder->acl_tensor_manager()->internal_buffer_manager(), input_tensor->handle(),
+ output_tensor->handle(), beta);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Slice &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Slice::Input::INPUT)};
+ const auto begins_index{node.getInputs().at(ir::operation::Slice::Input::BEGINS)};
+ const auto sizes_index{node.getInputs().at(ir::operation::Slice::Input::SIZES)};
+
+ auto outputData_tensor = _tensor_reg->getAclTensor(output_index);
+ auto inputData_tensor = _tensor_reg->getAclTensor(input_index);
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = inputData_tensor->layout();
+
+ // Set initializers for indices data such as order of inputData
+ int input_rank = _ctx.at(input_index).shape().rank();
+ std::vector<int32_t> starts;
+ std::vector<int32_t> ends;
+ starts.resize(input_rank, 0);
+ ends.resize(input_rank, 0);
+ {
+ assert(_ctx.at(begins_index).data());
+ assert(_ctx.at(sizes_index).data());
+ auto beginData_base = _ctx.at(begins_index).data()->base();
+ auto sizeData_base = _ctx.at(sizes_index).data()->base();
+ const int beginData_size = _ctx.at(begins_index).shape().num_elements();
+ const int sizeData_size = _ctx.at(sizes_index).shape().num_elements();
+
+ using ir::DataType;
+
+ UNUSED_RELEASE(beginData_size);
+ UNUSED_RELEASE(sizeData_size);
+
+ assert(_ctx.at(begins_index).typeInfo().type() == DataType::INT32);
+ assert(_ctx.at(sizes_index).typeInfo().type() == DataType::INT32);
+ assert(beginData_size == input_rank);
+ assert(sizeData_size == input_rank);
+
+ assert(beginData_base != nullptr);
+ for (int n = 0; n < input_rank; ++n)
+ {
+ auto axis = ::onert::backend::acl_common::ToARMComputeAxis(input_rank, n, frontend_layout,
+ backend_layout)
+ .value();
+
+ int32_t begin_value = *(reinterpret_cast<const int32_t *>(beginData_base) + n);
+ starts[axis] = begin_value;
+
+ int32_t size_value = *(reinterpret_cast<const int32_t *>(sizeData_base) + n);
+ ends[axis] = begin_value + size_value;
+ }
+ }
+
+ ::arm_compute::Coordinates starts_set;
+ ::arm_compute::Coordinates ends_set;
+
+ for (size_t i = 0; i < starts.size(); ++i)
+ {
+ starts_set.set(i, starts[i]);
+ ends_set.set(i, ends[i]);
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::CLSlice>(
+ inputData_tensor->handle(), outputData_tensor->handle(), starts_set, ends_set);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::StridedSlice &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)};
+ const auto starts_index{node.getInputs().at(ir::operation::StridedSlice::Input::STARTS)};
+ const auto ends_index{node.getInputs().at(ir::operation::StridedSlice::Input::ENDS)};
+ const auto strides_index{node.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)};
+
+ auto outputData_tensor = _tensor_reg->getAclTensor(output_index);
+ auto inputData_tensor = _tensor_reg->getAclTensor(input_index);
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = inputData_tensor->layout();
+
+ // Set initializers for indices data such as order of inputData
+ int input_rank = _ctx.at(input_index).shape().rank();
+ std::vector<int32_t> starts;
+ std::vector<int32_t> ends;
+ std::vector<int32_t> strides;
+ starts.resize(input_rank, 0);
+ ends.resize(input_rank, 0);
+ strides.resize(input_rank, 0);
+ {
+ assert(_ctx.at(starts_index).data());
+ assert(_ctx.at(ends_index).data());
+ assert(_ctx.at(strides_index).data());
+ auto startData_base = _ctx.at(starts_index).data()->base();
+ auto endData_base = _ctx.at(ends_index).data()->base();
+ auto stridesData_base = _ctx.at(strides_index).data()->base();
+ const int startData_size = _ctx.at(starts_index).shape().num_elements();
+ const int endData_size = _ctx.at(ends_index).shape().num_elements();
+ const int stridesData_size = _ctx.at(strides_index).shape().num_elements();
+
+ using ir::DataType;
+
+ UNUSED_RELEASE(startData_size);
+ UNUSED_RELEASE(endData_size);
+ UNUSED_RELEASE(stridesData_size);
+
+ assert(_ctx.at(starts_index).typeInfo().type() == DataType::INT32);
+ assert(_ctx.at(ends_index).typeInfo().type() == DataType::INT32);
+ assert(_ctx.at(strides_index).typeInfo().type() == DataType::INT32);
+ assert(startData_size == input_rank);
+ assert(endData_size == input_rank);
+ assert(stridesData_size == input_rank);
+
+ assert(startData_base != nullptr);
+ for (int n = 0; n < input_rank; ++n)
+ {
+ auto axis = ::onert::backend::acl_common::ToARMComputeAxis(input_rank, n, frontend_layout,
+ backend_layout)
+ .value();
+
+ int32_t start_value = *(reinterpret_cast<const int32_t *>(startData_base) + n);
+ starts[axis] = start_value;
+
+ int32_t end_value = *(reinterpret_cast<const int32_t *>(endData_base) + n);
+ ends[axis] = end_value;
+
+ int32_t strides_value = *(reinterpret_cast<const int32_t *>(stridesData_base) + n);
+ strides[axis] = strides_value;
+ }
+ }
+
+ // Set mask bits such as order of inputData
+ const auto begin_mask = acl_common::ReorderBits<int32_t>(node.param().begin_mask, input_rank,
+ frontend_layout, backend_layout);
+ const auto end_mask = acl_common::ReorderBits<int32_t>(node.param().end_mask, input_rank,
+ frontend_layout, backend_layout);
+ const auto shrink_axis_mask = acl_common::ReorderBits<int32_t>(
+ node.param().shrink_axis_mask, input_rank, frontend_layout, backend_layout);
+
+ ::arm_compute::Coordinates starts_set;
+ ::arm_compute::Coordinates ends_set;
+ ::arm_compute::BiStrides strides_set;
+
+ for (size_t i = 0; i < starts.size(); ++i)
+ {
+ starts_set.set(i, starts[i]);
+ ends_set.set(i, ends[i]);
+ strides_set.set(i, strides[i]);
+ }
+
+ // Disable applied dim_correction
+ if (inputData_tensor->num_dimensions() != inputData_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and input tensor is applied dim_correction
+ acl_common::disableDimCorrection(inputData_tensor);
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::CLStridedSlice>(
+ inputData_tensor->handle(), outputData_tensor->handle(), starts_set, ends_set, strides_set,
+ begin_mask, end_mask, shrink_axis_mask);
+
+ // Revert disabling applied dim_correction
+ if (inputData_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(inputData_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Transpose &node)
+{
+ const auto ofm_idx{node.getOutputs().at(0)};
+ const auto ifm_idx{node.getInputs().at(ir::operation::Transpose::Input::INPUT)};
+ const auto perm_idx{node.getInputs().at(ir::operation::Transpose::Input::PERMUTATION)};
+
+ const auto rank = _ctx.at(ifm_idx).shape().rank();
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_idx);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_idx);
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = ifm_tensor->layout();
+
+ const auto &perms = _ctx.at(perm_idx);
+ std::vector<int32_t> pv;
+ if (perms.shape() == ir::Shape{0})
+ {
+ pv.resize(rank);
+ std::iota(pv.begin(), pv.end(), 0);
+ std::reverse(pv.begin(), pv.end());
+ }
+ else
+ {
+ pv = _ctx.at(perm_idx).asVector<int32_t>();
+ }
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ if (rank == 1)
+ {
+ fn = acl_common::generateLayer<arm_compute::CLCopy>(ifm_tensor->handle(), ofm_tensor->handle());
+ }
+ else if (rank == 2)
+ {
+ assert(pv.size() == 2 && pv.at(0) == 1 && pv.at(1) == 0);
+ fn = acl_common::generateLayer<arm_compute::CLTranspose>(ifm_tensor->handle(),
+ ofm_tensor->handle());
+ }
+ else
+ {
+ auto backend_pv =
+ acl_common::getARMComputePermutationVector(rank, pv, frontend_layout, backend_layout);
+
+ fn = acl_common::generateLayer<arm_compute::CLPermute>(ifm_tensor->handle(),
+ ofm_tensor->handle(), backend_pv);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseActivation &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ElementwiseActivation::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ const ::arm_compute::ActivationLayerInfo act_info = acl_common::asActivationLayerInfo(
+ node.param().op_type, node.param().alpha, node.param().beta);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLActivationLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), act_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseBinary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::ElementwiseBinary::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::ElementwiseBinary::Input::RHS)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto lhs_tensor = _tensor_reg->getAclTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getAclTensor(rhs_index);
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ switch (node.param().op_type)
+ {
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_AND:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLBinaryLogicalOp>(
+ lhs_tensor->handle(), rhs_tensor->handle(), output_tensor->handle(),
+ arm_compute::BinaryLogicalOperation::AND);
+ break;
+ }
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLBitwiseOr>(
+ lhs_tensor->handle(), rhs_tensor->handle(), output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::MAX:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLElementwiseMax>(
+ lhs_tensor->handle(), rhs_tensor->handle(), output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::MIN:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLElementwiseMin>(
+ lhs_tensor->handle(), rhs_tensor->handle(), output_tensor->handle());
+ break;
+ }
+ default:
+ {
+ std::string err_msg("acl_cl KernelGenerator : " + node.name() +
+ "is not elementwise-binary operations");
+ assert(false && err_msg.c_str());
+ break;
+ }
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseUnary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ElementwiseUnary::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ switch (node.param().op_type)
+ {
+ case ir::operation::ElementwiseUnary::Type::ABS:
+ {
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::ABS};
+
+ fn = acl_common::generateLayer<arm_compute::CLActivationLayer>(
+ input_tensor->handle(), output_tensor->handle(), act_info);
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::CAST:
+ {
+ if (input_tensor->data_type() == output_tensor->data_type())
+ {
+ fn = acl_common::generateLayer<arm_compute::CLCopy>(input_tensor->handle(),
+ output_tensor->handle());
+ }
+ else if (_ctx.at(input_index).typeInfo().type() == ir::DataType::BOOL8)
+ {
+ fn = acl_common::generateLayer<arm_compute::CLCastBool>(input_tensor->handle(),
+ output_tensor->handle());
+ }
+ else
+ {
+ // TODO Support converting float to int32 as round down
+ fn = acl_common::generateLayer<arm_compute::CLCast>(
+ input_tensor->handle(), output_tensor->handle(), arm_compute::ConvertPolicy::SATURATE);
+ }
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::DEQUANTIZE:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLDequantizationLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::EXP:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLExpLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::FLOOR:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLFloor>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::LOGICAL_NOT:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLBitwiseNot>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::NEG:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLNeg>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::RSQRT:
+ {
+ fn = acl_common::generateLayer<arm_compute::CLRsqrtLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::SQRT:
+ {
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::SQRT};
+
+ fn = acl_common::generateLayer<arm_compute::CLActivationLayer>(
+ input_tensor->handle(), output_tensor->handle(), act_info);
+ break;
+ }
+ default:
+ {
+ throw std::runtime_error("acl_cl KernelGenerator : " + node.name() + "is not supported yet");
+ break;
+ }
+ }
+
+ auto acl_fn = asAclFunction(std::move(fn));
+
+ _return_fn = std::move(acl_fn);
+}
+
+void KernelGenerator::visit(const ir::operation::ExpandDims &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ExpandDims::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLReshapeLayer>(input_tensor->handle(),
+ output_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::InstanceNorm &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::InstanceNorm::Input::INPUT)};
+ const auto gamma_index{node.getInputs().at(ir::operation::InstanceNorm::Input::GAMMA)};
+ const auto beta_index{node.getInputs().at(ir::operation::InstanceNorm::Input::BETA)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto gamma_tensor = _tensor_reg->getAclTensor(gamma_index);
+ auto beta_tensor = _tensor_reg->getAclTensor(beta_index);
+ auto epsilon = node.param().epsilon;
+ auto activation = node.param().activation;
+
+ auto fn = acl_common::generateLayer<arm_compute::CLInstanceNormalizationLayerEx>(
+ ifm_tensor->handle(), ofm_tensor->handle(), gamma_tensor->handle(), beta_tensor->handle(),
+ epsilon);
+
+ _return_fn = std::make_unique<exec::FunctionSequence>(
+ asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_tensor->handle()));
+}
+
+void KernelGenerator::visit(const ir::operation::LSTM &node)
+{
+ _return_fn = acl_common::kernelGenLSTM<acl_common::AclFunction, ::arm_compute::ICLTensor,
+ ::arm_compute::CLLSTMLayer>(node, _ctx, _tensor_reg);
+}
+
+void KernelGenerator::visit(const ir::operation::Comparison &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input0_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)};
+ const auto input1_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)};
+
+ const auto comparison_type = node.param().comparison_type;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input0_tensor = _tensor_reg->getAclTensor(input0_index);
+ auto input1_tensor = _tensor_reg->getAclTensor(input1_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLComparison>(
+ input0_tensor->handle(), input1_tensor->handle(), output_tensor->handle(),
+ (arm_compute::ComparisonOperation)comparison_type);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::OneHot &node)
+{
+ const auto output_idx{node.getOutputs().at(0)};
+ const auto indices_idx{node.getInputs().at(ir::operation::OneHot::Input::INDICES)};
+ const auto depth_idx{node.getInputs().at(ir::operation::OneHot::Input::DEPTH)};
+ const auto onvalue_idx{node.getInputs().at(ir::operation::OneHot::Input::ON_VALUE)};
+ const auto offvalue_idx{node.getInputs().at(ir::operation::OneHot::Input::OFF_VALUE)};
+ const auto depth = _ctx.at(depth_idx).asScalar<int32_t>();
+ assert(depth > 0);
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_idx);
+ auto indices_tensor = _tensor_reg->getAclTensor(indices_idx);
+ auto onvalue_tensor = _tensor_reg->getAclTensor(onvalue_idx);
+
+ const size_t output_rank = _ctx.at(output_idx).shape().rank();
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = output_tensor->layout();
+ int32_t axis = node.param().axis == -1 ? output_rank - 1 : node.param().axis;
+ axis = acl_common::ToARMComputeAxis(output_rank, axis, frontend_layout, backend_layout).value();
+
+ if (output_tensor->num_dimensions() != output_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and output_tensor is applied dim_correction
+ acl_common::disableDimCorrection(output_tensor);
+ }
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+ const auto &offvalue = _ctx.at(offvalue_idx);
+ if (offvalue.isConstant())
+ {
+ fn = acl_common::generateLayer<arm_compute::CLOneHot>(
+ indices_tensor->handle(), onvalue_tensor->handle(), output_tensor->handle(),
+ acl_common::asPixelValue(offvalue), static_cast<uint32_t>(depth), axis);
+ }
+ else
+ {
+ auto offvalue_tensor = _tensor_reg->getAclTensor(offvalue_idx);
+ fn = acl_common::generateLayer<arm_compute::CLOneHot>(
+ indices_tensor->handle(), onvalue_tensor->handle(), offvalue_tensor->handle(),
+ output_tensor->handle(), static_cast<uint32_t>(depth), axis);
+ }
+
+ if (output_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(output_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Pack &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ auto axis{node.param().axis};
+
+ const auto output_rank = _ctx.at(output_index).shape().rank();
+
+ std::vector<ir::OperandIndex> input_indexes;
+ for (const auto &input_index : node.getInputs())
+ input_indexes.emplace_back(input_index);
+
+ auto output = _tensor_reg->getAclTensor(output_index)->handle();
+ std::vector<arm_compute::ICLTensor *> inputs;
+ for (const auto &input_index : input_indexes)
+ inputs.emplace_back(_tensor_reg->getAclTensor(input_index)->handle());
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = _tensor_reg->getAclTensor(output_index)->layout();
+
+ if (axis < 0)
+ axis += output_rank;
+ axis = acl_common::ToARMComputeAxis(output_rank, axis, frontend_layout, backend_layout).value();
+
+ // Disable applied dim_correction
+ for (const auto &input_index : input_indexes)
+ {
+ const auto &input_tensor = _tensor_reg->getAclTensor(input_index);
+ if (input_tensor->num_dimensions() != input_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and input tensor is applied dim_correction
+ acl_common::disableDimCorrection(input_tensor);
+ }
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::CLStackLayer>(inputs, axis, output);
+
+ // Revert disabling applied dim_correction
+ for (const auto &input_index : input_indexes)
+ {
+ const auto &input_tensor = _tensor_reg->getAclTensor(input_index);
+ if (input_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(input_tensor);
+ }
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Pool2D &node)
+{
+ auto raw_fn = acl_common::kernelGenPool2D<::arm_compute::CLPoolingLayer>(
+ node, _ctx, _tensor_reg, _current_op_seq_layout,
+ acl_common::convertPoolType(node.param().op_type));
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ const auto activation = node.param().activation;
+ _return_fn = std::make_unique<exec::FunctionSequence>(
+ asAclFunction(std::move(raw_fn)),
+ ActivationBuilder::generate(activation, ofm_tensor->handle()));
+}
+
+void KernelGenerator::visit(const ir::operation::Permute &node)
+{
+ const auto ofm_idx{node.getOutputs().at(0)};
+ const auto ifm_idx{node.getInputs().at(0)};
+ const auto permute_type = node.getPermuteType();
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_idx);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_idx);
+ const auto rank = _ctx.at(ofm_idx).shape().rank();
+ assert(_ctx.at(ifm_idx).shape().rank() == _ctx.at(ofm_idx).shape().rank());
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+ arm_compute::PermutationVector pv;
+ if (permute_type == ir::operation::Permute::Type::NCHW_TO_NHWC && rank == 4)
+ {
+ // WHCN -> CWHN
+ pv = arm_compute::PermutationVector{2, 0, 1};
+
+ fn = acl_common::generateLayer<arm_compute::CLPermute>(ifm_tensor->handle(),
+ ofm_tensor->handle(), pv);
+ }
+ else if (permute_type == ir::operation::Permute::Type::NHWC_TO_NCHW && rank == 4)
+ {
+ // CWHN -> WHCN
+ pv = arm_compute::PermutationVector{1, 2, 0};
+
+ fn = acl_common::generateLayer<::arm_compute::CLPermute>(ifm_tensor->handle(),
+ ofm_tensor->handle(), pv);
+ }
+ else
+ {
+ fn = acl_common::generateLayer<arm_compute::CLCopy>(ifm_tensor->handle(), ofm_tensor->handle());
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ResizeBilinear &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ResizeBilinear::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLScale>(
+ ifm_tensor->handle(), ofm_tensor->handle(), ::arm_compute::InterpolationPolicy::BILINEAR,
+ ::arm_compute::BorderMode::REPLICATE, ::arm_compute::PixelValue(0.f),
+ ::arm_compute::SamplingPolicy::TOP_LEFT);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ResizeNearestNeighbor &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ResizeNearestNeighbor::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLScale>(
+ ifm_tensor->handle(), ofm_tensor->handle(),
+ ::arm_compute::InterpolationPolicy::NEAREST_NEIGHBOR, ::arm_compute::BorderMode::REPLICATE,
+ ::arm_compute::PixelValue(0.f), ::arm_compute::SamplingPolicy::TOP_LEFT);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::RNN &node)
+{
+ const auto output_index{node.getOutputs().at(ir::operation::RNN::Output::OUTPUT)};
+ const auto hidden_state_out_index{
+ node.getOutputs().at(ir::operation::RNN::Output::HIDDEN_STATE_OUT)};
+
+ const auto input_index{node.getInputs().at(ir::operation::RNN::Input::INPUT)};
+ const auto weights_index{node.getInputs().at(ir::operation::RNN::Input::WEIGHTS)};
+ const auto recurrent_weights_index{
+ node.getInputs().at(ir::operation::RNN::Input::RECURRENT_WEIGHTS)};
+ const auto bias_index{node.getInputs().at(ir::operation::RNN::Input::BIAS)};
+ const auto hidden_state_in_index{node.getInputs().at(ir::operation::RNN::Input::HIDDEN_STATE_IN)};
+
+ const auto activation = node.param().activation;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto hidden_state_out_tensor = _tensor_reg->getAclTensor(hidden_state_out_index);
+
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+ auto weights_tensor = _tensor_reg->getAclTensor(weights_index);
+ auto recurrent_weights_tensor = _tensor_reg->getAclTensor(recurrent_weights_index);
+ auto bias_tensor = _tensor_reg->getAclTensor(bias_index);
+ auto hidden_state_in_tensor = _tensor_reg->getAclTensor(hidden_state_in_index);
+ auto act_info = ::onert::backend::acl_common::asActivationLayerInfo(activation);
+
+ auto copy_layer = acl_common::generateLayer<arm_compute::CLCopy>(
+ hidden_state_in_tensor->handle(), hidden_state_out_tensor->handle());
+ _return_fn = asAclFunction(std::move(copy_layer));
+
+ auto fn = acl_common::generateLayer<arm_compute::CLRNNLayer>(
+ _tensor_builder->acl_tensor_manager()->internal_buffer_manager(), input_tensor->handle(),
+ weights_tensor->handle(), recurrent_weights_tensor->handle(), bias_tensor->handle(),
+ hidden_state_out_tensor->handle(), output_tensor->handle(), act_info);
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::SpaceToBatchND &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)};
+ const auto block_size_index{
+ node.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)};
+ const auto paddings_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto block_size_tensor = _tensor_reg->getAclTensor(block_size_index);
+ auto paddings_tensor = _tensor_reg->getAclTensor(paddings_index);
+
+ assert(_ctx.at(block_size_index).data());
+ assert(_ctx.at(paddings_index).data());
+
+ auto fn = acl_common::generateLayer<arm_compute::CLSpaceToBatchLayer>(
+ ifm_tensor->handle(), block_size_tensor->handle(), paddings_tensor->handle(),
+ ofm_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::SpaceToDepth &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)};
+
+ auto block_size = node.param().block_size;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLSpaceToDepthLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), block_size);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::EmbeddingLookup &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lookups_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::LOOKUPS)};
+ const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto lookups_tensor = _tensor_reg->getAclTensor(lookups_index);
+ auto values_tensor = _tensor_reg->getAclTensor(values_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLEmbeddingLookup>(
+ values_tensor->handle(), output_tensor->handle(), lookups_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::L2Normalization &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::L2Normalization::Input::INPUT)};
+
+ // {CL|Neon}L2Normalization performs the reduction only along dimension 0
+ // L2 Normalization always performs the reduction along the depth axis
+ // Thus, we repurpose {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by
+ // choosing normalization parameters as below
+
+ const auto &ifm_shape = _ctx.at(ifm_index).shape();
+ // TODO Support optional constant dimension that normalization would be performed on
+ const auto normalization_axis = _ctx.at(ifm_index).shape().rank() - 1;
+ int32_t radius =
+ 2 * ifm_shape.dim(normalization_axis) + 1; // normSize = depth(last dimension) * 2 + 1
+ float alpha = 1.0f; // In the implementation to make alpha_ become 1
+ float beta = 0.5f; // pow(reduction, -0.5) = 1 / sqrt(reduction)
+ float bias = 0.0f; // Don't offset the reduction.
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ const auto norm_info = ::arm_compute::NormalizationLayerInfo(::arm_compute::NormType::CROSS_MAP,
+ radius, alpha, beta, bias, false);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLNormalizationLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), norm_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::HashtableLookup &node)
+{
+ const auto output_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::OUTPUT)};
+ const auto hits_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::HITS)};
+
+ const auto lookups_index{node.getInputs().at(ir::operation::HashtableLookup::Input::LOOKUPS)};
+ const auto keys_index{node.getInputs().at(ir::operation::HashtableLookup::Input::KEYS)};
+ const auto values_index{node.getInputs().at(ir::operation::HashtableLookup::Input::VALUES)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto hits_tensor = _tensor_reg->getAclTensor(hits_index);
+
+ auto lookups_tensor = _tensor_reg->getAclTensor(lookups_index);
+ auto keys_tensor = _tensor_reg->getAclTensor(keys_index);
+ auto values_tensor = _tensor_reg->getAclTensor(values_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLHashtableLookup>(
+ lookups_tensor->handle(), keys_tensor->handle(), values_tensor->handle(),
+ output_tensor->handle(), hits_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::PReLU &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::PReLU::Input::INPUT)};
+ const auto alpha_index{node.getInputs().at(ir::operation::PReLU::Input::ALPHA)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto alpha_tensor = _tensor_reg->getAclTensor(alpha_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLPReluLayer>(
+ ifm_tensor->handle(), alpha_tensor->handle(), ofm_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::TransposeConv &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ker_index{node.getInputs().at(ir::operation::TransposeConv::Input::KERNEL)};
+ const auto ifm_index{node.getInputs().at(ir::operation::TransposeConv::Input::INPUT)};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ker_shape = _ctx.at(ker_index).shape().asFeature(_current_op_seq_layout);
+
+ const auto stride = node.param().stride;
+
+ assert((node.param().padding.type == ir::PaddingType::SAME) ||
+ (node.param().padding.type == ir::PaddingType::VALID));
+ auto padding = ir::calculatePadding(node.param().padding, ofm_shape, ifm_shape, stride,
+ ker_shape.W, ker_shape.H);
+ uint32_t invalid_horizontal = 0;
+ uint32_t invalid_vertical = 0;
+ if (node.param().padding.type == ir::PaddingType::VALID)
+ {
+ invalid_horizontal =
+ ofm_shape.W - (1 + (ifm_shape.W - 1) * stride.horizontal) - (ker_shape.W - 1);
+ invalid_vertical = ofm_shape.H - (1 + (ifm_shape.H - 1) * stride.vertical) - (ker_shape.H - 1);
+ }
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto ker_tensor = _tensor_reg->getAclTensor(ker_index);
+
+ const auto tconv_info = acl_common::asPadStrideInfo(padding, stride);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLTransposeConvLayer>(
+ _tensor_builder->acl_tensor_manager()->internal_buffer_manager(), ifm_tensor->handle(),
+ ker_tensor->handle(), nullptr, ofm_tensor->handle(), tconv_info, invalid_horizontal,
+ invalid_vertical);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::SquaredDifference &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::RHS)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto lhs_tensor = _tensor_reg->getAclTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getAclTensor(rhs_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLElementwiseSquaredDiff>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::TopKV2 &node)
+{
+ const auto outputValues_index{node.getOutputs().at(ir::operation::TopKV2::Output::OUTPUT_VALUES)};
+ const auto outputIndices_index{
+ node.getOutputs().at(ir::operation::TopKV2::Output::OUTPUT_INDICES)};
+
+ const auto inputData_index{node.getInputs().at(ir::operation::TopKV2::Input::INPUT)};
+
+ // Currently, we only support the vector input.
+ assert(_ctx.at(inputData_index).shape().rank() == 1 ||
+ _ctx.at(inputData_index).shape().rank() == 2);
+
+ const auto k = node.param().k;
+
+ auto values_tensor = _tensor_reg->getAclTensor(outputValues_index);
+ auto indices_tensor = _tensor_reg->getAclTensor(outputIndices_index);
+ auto input_tensor = _tensor_reg->getAclTensor(inputData_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLTopKV2>(
+ input_tensor->handle(), k, values_tensor->handle(), indices_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Gather &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)};
+ const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)};
+
+ const auto ifm_rank = _ctx.at(ifm_index).shape().rank();
+ const auto axis_raw = node.param().axis;
+ const auto axis_value = (axis_raw < 0 ? (ifm_rank + axis_raw) : axis_raw);
+ const int axis = ::onert::backend::acl_common::ToARMComputeAxis(ifm_rank, axis_value).value();
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto indices_tensor = _tensor_reg->getAclTensor(indices_index);
+
+ // NOTE The frontend layout and backend layout must be the same for this operation.
+ // If not the same, we have to add a stage(?) to perform permutation of output tensor. It
+ // is not not efficient even if it works well. If so, it would be better to set the
+ // layout of these backend tensors to the same layout.
+ // There is also one thing we have to think about. This operation depends on the layout of
+ // a model. For example, if a model in NHWC has this operation as output rank == 4, indices
+ // rank == 2 and axis == 2, this operation should work as the axis W and C, but the axis W
+ // and C are not sequential in NCHW. So the backend in NCHW cannot handle this case.
+ const auto backend_layout = ofm_tensor->layout();
+ UNUSED_RELEASE(backend_layout);
+ assert(backend_layout == ifm_tensor->layout());
+ assert(backend_layout == indices_tensor->layout());
+ assert(ifm_rank < 4 || _current_op_seq_layout == backend_layout);
+
+ // input is n-D, indices k-D, output is (n + k - 1)-D
+ size_t n = ifm_rank;
+ assert(n == ifm_tensor->num_dimensions());
+ size_t k = _ctx.at(indices_index).shape().rank();
+ assert(k == indices_tensor->num_dimensions());
+
+ // Disable applied dim_correction
+ if (n != ifm_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and ifm tensor is applied dim_correction
+ acl_common::disableDimCorrection(ifm_tensor);
+ }
+ if (k != indices_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and indices tensor is applied dim_correction
+ acl_common::disableDimCorrection(indices_tensor);
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::CLGatherEx>(
+ ifm_tensor->handle(), indices_tensor->handle(), ofm_tensor->handle(), axis);
+
+ // Revert disabling applied dim_correction
+ if (ifm_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(ifm_tensor);
+ }
+ if (indices_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(indices_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ArgMax &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ArgMax::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::ArgMax::Input::AXIS)};
+
+ auto ifm_shape = _ctx.at(ifm_index).shape();
+ auto ofm_shape = _ctx.at(ofm_index).shape();
+
+ assert((ifm_shape.rank() - 1) == ofm_shape.rank());
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ const auto ifm_rank = _ctx.at(ifm_index).shape().rank();
+ auto frontend_layout = _current_op_seq_layout;
+ auto backend_layout = ifm_tensor->layout();
+
+ int axis_value = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis_value < 0)
+ {
+ axis_value += ifm_rank;
+ }
+
+ auto acl_axis =
+ acl_common::ToARMComputeAxis(ifm_rank, axis_value, frontend_layout, backend_layout).value();
+
+ auto fn = acl_common::generateLayer<arm_compute::CLArgMinMaxLayerEx>(
+ ifm_tensor->handle(), acl_axis, ofm_tensor->handle(),
+ ::arm_compute::ReductionOperation::ARG_IDX_MAX);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::LocalResponseNormalization &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{
+ node.getInputs().at(ir::operation::LocalResponseNormalization::Input::INPUT)};
+
+ auto radius = node.param().radius;
+ auto alpha = node.param().alpha;
+ auto beta = node.param().beta;
+ auto bias = node.param().bias;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ const auto norm_info = ::arm_compute::NormalizationLayerInfo(
+ ::arm_compute::NormType::CROSS_MAP, radius * 2 + 1, alpha, beta, bias, false);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLNormalizationLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), norm_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::DepthToSpace &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::DepthToSpace::Input::INPUT)};
+
+ auto block_size = node.param().block_size;
+ assert(block_size > 0);
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLDepthToSpaceLayer>(
+ input_tensor->handle(), output_tensor->handle(), block_size);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Split &node)
+{
+ const auto ifm_index{node.getInputs().at(ir::operation::Split::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::Split::Input::AXIS)};
+
+ assert(node.param().num_splits == static_cast<int>(node.getOutputs().size()));
+ if (!_ctx.at(axis_index).isConstant())
+ {
+ throw std::runtime_error("Non-constant axis_index NYI for acl_cl backend");
+ }
+
+ const auto ifm_rank = _ctx.at(ifm_index).shape().rank();
+ std::vector<ir::OperandIndex> output_indexes;
+ for (const auto &output : node.getOutputs())
+ output_indexes.emplace_back(output);
+
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ std::vector<arm_compute::ICLTensor *> output_tensors;
+ for (const auto &ofm_ind : output_indexes)
+ output_tensors.emplace_back(_tensor_reg->getAclTensor(ofm_ind)->handle());
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = ifm_tensor->layout();
+ auto axis = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis < 0)
+ axis += ifm_rank;
+ axis = acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value();
+
+ auto fn =
+ acl_common::generateLayer<arm_compute::CLSplit>(ifm_tensor->handle(), output_tensors, axis);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::SplitV &node)
+{
+ const auto ifm_index{node.getInputs().at(ir::operation::SplitV::Input::INPUT)};
+ const auto size_split_index{node.getInputs().at(ir::operation::SplitV::Input::SIZE_SPLITS)};
+ const auto split_dim_index{node.getInputs().at(ir::operation::SplitV::Input::SPLIT_DIM)};
+
+ assert(node.param().num_splits == static_cast<int>(node.getOutputs().size()));
+
+ const size_t ifm_rank = _ctx.at(ifm_index).shape().rank();
+ std::vector<ir::OperandIndex> output_indexes;
+ for (const auto &output : node.getOutputs())
+ output_indexes.emplace_back(output);
+
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto size_split_tensor = _tensor_reg->getAclTensor(size_split_index);
+
+ std::vector<arm_compute::ICLTensor *> output_tensors;
+ for (const auto &ofm_ind : output_indexes)
+ output_tensors.emplace_back(_tensor_reg->getAclTensor(ofm_ind)->handle());
+
+ auto fn = std::make_unique<arm_compute::CLSplitVEx>();
+ const auto &split_dim_op = _ctx.at(split_dim_index);
+ if (split_dim_op.isConstant())
+ {
+ int32_t split_dim = split_dim_op.asScalar<int32_t>();
+ uint32_t split_dim_revised = (split_dim < 0) ? (split_dim + ifm_rank) : split_dim;
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = ifm_tensor->layout();
+
+ if (ifm_tensor->num_dimensions() != ifm_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and ifm tensor is applied dim_correction
+ acl_common::disableDimCorrection(ifm_tensor);
+ }
+
+ split_dim_revised =
+ acl_common::ToARMComputeAxis(ifm_rank, split_dim_revised, frontend_layout, backend_layout)
+ .value();
+ fn->configure(ifm_tensor->handle(), size_split_tensor->handle(), split_dim_revised,
+ output_tensors, node.param().num_splits);
+
+ if (ifm_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(ifm_tensor);
+ }
+ }
+ else
+ {
+ throw std::runtime_error("Non-constant split_dim NYI for acl_cl backend");
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Unpack &node)
+{
+ const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)};
+ auto axis{node.param().axis};
+
+ const auto input_rank = _ctx.at(input_index).shape().rank();
+
+ std::vector<ir::OperandIndex> output_indexes;
+ for (const auto &output_index : node.getOutputs())
+ output_indexes.emplace_back(output_index);
+
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+ std::vector<arm_compute::ICLTensor *> outputs;
+ for (const auto &output_index : output_indexes)
+ outputs.emplace_back(_tensor_reg->getAclTensor(output_index)->handle());
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = _tensor_reg->getAclTensor(input_index)->layout();
+ if (axis < 0)
+ axis += input_rank;
+ axis = acl_common::ToARMComputeAxis(input_rank, axis, frontend_layout, backend_layout).value();
+
+ // Disable applied dim_correction
+ if (input_tensor->num_dimensions() != input_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and input tensor is applied dim_correction
+ acl_common::disableDimCorrection(input_tensor);
+ }
+
+ auto fn =
+ acl_common::generateLayer<arm_compute::CLUnstack>(input_tensor->handle(), outputs, axis);
+
+ // Revert disabling applied dim_correction
+ if (input_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(input_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Pad &node)
+{
+ const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)};
+ const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)};
+ const auto output_index{node.getOutputs().at(0)};
+ assert(_ctx.at(pad_index).data());
+
+ auto rank = _ctx.at(input_index).shape().rank();
+ auto pad_base = _ctx.at(pad_index).data()->base();
+
+ auto input_type = _ctx.at(input_index).typeInfo();
+ auto data_type = acl_common::asDataType(input_type.type());
+ auto quant_info = ::arm_compute::QuantizationInfo(input_type.scale(), input_type.offset());
+ const auto pixel_value = ::arm_compute::PixelValue(0, data_type, quant_info);
+
+ auto input = _tensor_reg->getAclTensor(input_index)->handle();
+ auto output = _tensor_reg->getAclTensor(output_index)->handle();
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = _tensor_reg->getAclTensor(input_index)->layout();
+
+ ::arm_compute::PaddingList padding_list;
+ padding_list.resize(rank);
+ for (int32_t n = 0; n < rank; ++n)
+ {
+ const int32_t *from = reinterpret_cast<const int32_t *>(pad_base) + (n * 2);
+
+ const auto axis =
+ acl_common::ToARMComputeAxis(rank, n, frontend_layout, backend_layout).value();
+ padding_list[axis] = ::arm_compute::PaddingInfo{from[0], from[1]};
+ }
+
+ // Disable applied dim_correction
+ const auto &input_tensor = _tensor_reg->getAclTensor(input_index);
+ if (input_tensor->num_dimensions() != input_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and input tensor is applied dim_correction
+ acl_common::disableDimCorrection(input_tensor);
+ }
+
+ auto fn =
+ acl_common::generateLayer<arm_compute::CLPadLayer>(input, output, padding_list, pixel_value);
+
+ // NOTE Do not revert disabling applied dim_correction for 4D.
+ // It would produce a mistach of result by incorrect offset_first_element in
+ // ICLKernel::add_tensor_argument<3>().
+ // We have to disable applied dim_correction and not to revert enabling for the kernel that slices
+ // 4D to 3D because slicing arm_compute::Window can causes incorrect offset_first_element if the
+ // used tensor is 4D and the tensor's high dimention is 1
+ if (input_tensor->num_dimensions() < 4 && input_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(input_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ConvertFp32ToFp16 &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ConvertFp32ToFp16::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLDepthConvertLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), ::arm_compute::ConvertPolicy::SATURATE, 0);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ConvertFp16ToFp32 &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ConvertFp16ToFp32::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::CLDepthConvertLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), ::arm_compute::ConvertPolicy::SATURATE, 0);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Reverse &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::Reverse::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::Reverse::Input::AXIS)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto axis_tensor = _tensor_reg->getAclTensor(axis_index);
+
+ // WORKAROUND: acl-cl backend only allow U32 type for axis
+ // ConstantInitializer will resolve S32 type to U32 type
+ if (_ctx.at(axis_index).isConstant() &&
+ (axis_tensor->handle()->info()->data_type() == arm_compute::DataType::S32))
+ {
+ axis_tensor->handle()->info()->set_data_type(arm_compute::DataType::U32);
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::CLReverse>(
+ ifm_tensor->handle(), ofm_tensor->handle(), axis_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_cl/KernelGenerator.h b/runtime/onert/backend/acl_cl/KernelGenerator.h
new file mode 100644
index 000000000..e8a922677
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/KernelGenerator.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_KERNEL_GENERATOR_H__
+#define __ONERT_BACKEND_ACL_CL_KERNEL_GENERATOR_H__
+
+#include <backend/IKernelGenerator.h>
+
+#include "ir/Operands.h"
+#include "TensorBuilder.h"
+#include "AclTensorRegistry.h"
+#include "TensorManager.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+class KernelGenerator : public IKernelGenerator
+{
+public:
+ KernelGenerator(const ir::Operands &operands_ctx, const ir::Operations &operations_ctx,
+ const std::shared_ptr<TensorBuilder> &tensor_builder,
+ const std::shared_ptr<acl_common::AclTensorRegistry<TensorManager>> &_tensor_reg);
+
+ void visit(const ir::OpSequence &) override;
+ void visit(const ir::operation::BatchToSpaceND &) override;
+ void visit(const ir::operation::BinaryArithmetic &) override;
+ void visit(const ir::operation::Conv2D &) override;
+ void visit(const ir::operation::DepthwiseConv2D &) override;
+ void visit(const ir::operation::Concat &) override;
+ void visit(const ir::operation::FullyConnected &) override;
+ void visit(const ir::operation::Reduce &) override;
+ void visit(const ir::operation::Reshape &) override;
+ void visit(const ir::operation::Squeeze &) override;
+ void visit(const ir::operation::Softmax &) override;
+ void visit(const ir::operation::Slice &) override;
+ void visit(const ir::operation::StridedSlice &) override;
+ void visit(const ir::operation::Transpose &) override;
+ void visit(const ir::operation::ElementwiseActivation &) override;
+ void visit(const ir::operation::ElementwiseBinary &) override;
+ void visit(const ir::operation::ElementwiseUnary &) override;
+ void visit(const ir::operation::ExpandDims &) override;
+ void visit(const ir::operation::InstanceNorm &) override;
+ void visit(const ir::operation::Comparison &) override;
+ void visit(const ir::operation::LSTM &) override;
+ void visit(const ir::operation::OneHot &) override;
+ void visit(const ir::operation::Pack &) override;
+ void visit(const ir::operation::Pool2D &) override;
+ void visit(const ir::operation::Permute &) override;
+ void visit(const ir::operation::ResizeBilinear &) override;
+ void visit(const ir::operation::ResizeNearestNeighbor &) override;
+ void visit(const ir::operation::RNN &) override;
+ void visit(const ir::operation::SpaceToBatchND &) override;
+ void visit(const ir::operation::SpaceToDepth &) override;
+ void visit(const ir::operation::EmbeddingLookup &) override;
+ void visit(const ir::operation::L2Normalization &) override;
+ void visit(const ir::operation::HashtableLookup &) override;
+ void visit(const ir::operation::PReLU &) override;
+ void visit(const ir::operation::TransposeConv &) override;
+ void visit(const ir::operation::SquaredDifference &) override;
+ void visit(const ir::operation::TopKV2 &) override;
+ void visit(const ir::operation::Gather &) override;
+ void visit(const ir::operation::ArgMax &) override;
+ void visit(const ir::operation::LocalResponseNormalization &) override;
+ void visit(const ir::operation::DepthToSpace &) override;
+ void visit(const ir::operation::Split &) override;
+ void visit(const ir::operation::SplitV &) override;
+ void visit(const ir::operation::Unpack &) override;
+ void visit(const ir::operation::Pad &) override;
+ void visit(const ir::operation::ConvertFp32ToFp16 &) override;
+ void visit(const ir::operation::ConvertFp16ToFp32 &) override;
+ void visit(const ir::operation::Reverse &) override;
+
+private:
+ const ir::Operands &_ctx;
+ const ir::Operations &_operations_ctx;
+ std::shared_ptr<TensorBuilder> _tensor_builder;
+ std::shared_ptr<acl_common::AclTensorRegistry<TensorManager>> _tensor_reg;
+ ir::Layout _current_op_seq_layout;
+};
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_KERNEL_GENERATOR_H__
diff --git a/runtime/onert/backend/acl_cl/Optimizer.cc b/runtime/onert/backend/acl_cl/Optimizer.cc
new file mode 100644
index 000000000..7290c5688
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/Optimizer.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Optimizer.h"
+
+#include "ParentInfo.h"
+
+#include <cassert>
+#include <compiler/LoweredGraph.h>
+#include <util/logging.h>
+#include "AclSubTensorAnalyzer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+Optimizer::Optimizer(BackendContext *context)
+ : _context{context},
+ _tensor_builder{std::dynamic_pointer_cast<TensorBuilder>(context->tensor_builder)}
+{
+ assert(context);
+}
+
+void Optimizer::optimize()
+{
+ // Concat elimination (build subtensor info)
+ {
+ acl_common::AclSubTensorAnalyzer sa{*_context->graph()};
+ sa.setUsePadding();
+ for (auto op_info : _context->operation_list())
+ {
+ auto &op = _context->graph()->operations().at(op_info.index);
+ sa.setLayout(op_info.layout);
+ op.accept(sa);
+ }
+
+ _tensor_builder->parent_map(sa.releaseParentMap());
+ }
+}
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_cl/Optimizer.h b/runtime/onert/backend/acl_cl/Optimizer.h
new file mode 100644
index 000000000..18d38ec1b
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/Optimizer.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_OPTIMIZER_H__
+#define __ONERT_BACKEND_ACL_CL_OPTIMIZER_H__
+
+#include <backend/IOptimizer.h>
+#include <backend/BackendContext.h>
+#include "TensorBuilder.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+class Optimizer : public IOptimizer
+{
+public:
+ Optimizer(BackendContext *context);
+
+ void optimize() override;
+
+private:
+ BackendContext *_context;
+ std::shared_ptr<TensorBuilder> _tensor_builder;
+};
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_OPTIMIZER_H__
diff --git a/runtime/onert/backend/acl_cl/TensorBuilder.h b/runtime/onert/backend/acl_cl/TensorBuilder.h
new file mode 100644
index 000000000..91502d39a
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/TensorBuilder.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_TENSOR_BUILDER_H__
+#define __ONERT_BACKEND_ACL_CL_TENSOR_BUILDER_H__
+
+#include <AclTensorBuilder.h>
+
+#include "operand/CLTensor.h"
+#include "operand/CLSubTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+using TensorBuilder =
+ acl_common::AclTensorBuilder<operand::ICLTensor, operand::CLTensor, operand::CLSubTensor>;
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_TENSOR_BUILDER_H__
diff --git a/runtime/onert/backend/acl_cl/TensorManager.h b/runtime/onert/backend/acl_cl/TensorManager.h
new file mode 100644
index 000000000..ab295dbec
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/TensorManager.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_TENSOR_MANAGER_H__
+#define __ONERT_BACKEND_ACL_CL_TENSOR_MANAGER_H__
+
+#include <arm_compute/runtime/CL/CLBufferAllocator.h>
+#include <arm_compute/runtime/PoolManager.h>
+#include <arm_compute/runtime/BlobLifetimeManager.h>
+#include <arm_compute/runtime/MemoryManagerOnDemand.h>
+#include <arm_compute/runtime/MemoryGroup.h>
+
+#include <AclMemoryManager.h>
+#include <AclLinearMemoryManager.h>
+#include <AclInternalBufferManager.h>
+#include <AclTensorManager.h>
+
+#include "operand/CLTensor.h"
+#include "operand/CLSubTensor.h"
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+using MemoryManager =
+ acl_common::AclMemoryManager<operand::ICLTensor, operand::CLTensor, operand::CLSubTensor>;
+
+using LinearMemoryManager = acl_common::AclLinearMemoryManager<
+ operand::ICLTensor, operand::CLTensor, operand::CLSubTensor,
+ ::arm_compute::MemoryManagerOnDemand, ::arm_compute::PoolManager,
+ ::arm_compute::BlobLifetimeManager, ::arm_compute::CLBufferAllocator,
+ ::arm_compute::MemoryGroup>;
+
+using InternalBufferManager = acl_common::AclInternalBufferManager<
+ ::arm_compute::MemoryManagerOnDemand, ::arm_compute::PoolManager,
+ ::arm_compute::BlobLifetimeManager, ::arm_compute::CLBufferAllocator>;
+
+using TensorManager =
+ acl_common::AclTensorManager<operand::ICLTensor, operand::CLTensor, operand::CLSubTensor>;
+
+inline TensorManager *createTensorManager(bool is_linear_executor)
+{
+ if (is_linear_executor)
+ {
+ VERBOSE(acl_cl_createTensorManager) << "AclTensorManager as Linear" << std::endl;
+ return new TensorManager(new MemoryManager(), new LinearMemoryManager(),
+ new InternalBufferManager());
+ }
+ else
+ {
+ VERBOSE(acl_cl_createTensorManager) << "AclTensorManager" << std::endl;
+ return new TensorManager(new MemoryManager(), new MemoryManager(), new InternalBufferManager());
+ }
+}
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_TENSOR_MANAGER_H__
diff --git a/runtime/onert/backend/acl_cl/acl_cl.cc b/runtime/onert/backend/acl_cl/acl_cl.cc
new file mode 100644
index 000000000..88378b13a
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/acl_cl.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <util/logging.h>
+
+#include "Backend.h"
+
+extern "C" {
+onert::backend::Backend *onert_backend_create()
+{
+ VERBOSE(onert_backend_create) << "'acl_cl' loaded\n";
+ return new onert::backend::acl_cl::Backend;
+}
+
+void onert_backend_destroy(onert::backend::Backend *backend)
+{
+ VERBOSE(onert_backend_create) << "'acl_cl' unloaded\n";
+ delete backend;
+}
+}
diff --git a/runtime/onert/backend/acl_cl/operand/CLSubTensor.cc b/runtime/onert/backend/acl_cl/operand/CLSubTensor.cc
new file mode 100644
index 000000000..234229787
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/operand/CLSubTensor.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CLSubTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+CLSubTensor::CLSubTensor(ICLTensor *parent, const arm_compute::TensorShape &tensor_shape,
+ const arm_compute::Coordinates &coords, size_t rank, bool extend_parent)
+ : _cl_sub_tensor(std::make_shared<arm_compute::CLSubTensor>(parent->handle(), tensor_shape,
+ coords, extend_parent)),
+ _rank{rank}
+{
+ // DO NOTHING
+}
+
+const arm_compute::CLSubTensor *CLSubTensor::handle() const { return _cl_sub_tensor.get(); }
+
+arm_compute::CLSubTensor *CLSubTensor::handle() { return _cl_sub_tensor.get(); }
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_cl/operand/CLSubTensor.h b/runtime/onert/backend/acl_cl/operand/CLSubTensor.h
new file mode 100644
index 000000000..91f74f3d5
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/operand/CLSubTensor.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__
+#define __ONERT_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__
+
+#include <arm_compute/runtime/CL/CLSubTensor.h>
+#include "ICLTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+class CLSubTensor : public ICLTensor
+{
+public:
+ CLSubTensor() = delete;
+
+public:
+ CLSubTensor(ICLTensor *parent, const arm_compute::TensorShape &tensor_shape,
+ const arm_compute::Coordinates &coords, size_t rank, bool extend_parent = false);
+
+public:
+ size_t num_dimensions() const final { return _rank; }
+
+public:
+ const arm_compute::CLSubTensor *handle() const override;
+ arm_compute::CLSubTensor *handle() override;
+
+public:
+ // This method is used to prevent the use of memcpy for SubTensor
+ bool has_padding() const override { return true; }
+ bool is_subtensor() const final { return true; }
+
+private:
+ std::shared_ptr<arm_compute::CLSubTensor> _cl_sub_tensor;
+ size_t _rank;
+};
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__
diff --git a/runtime/onert/backend/acl_cl/operand/CLTensor.cc b/runtime/onert/backend/acl_cl/operand/CLTensor.cc
new file mode 100644
index 000000000..f37edff51
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/operand/CLTensor.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CLTensor.h"
+
+#include <arm_compute/runtime/CL/CLScheduler.h>
+#include <arm_compute/runtime/CL/CLMemory.h>
+#include <arm_compute/runtime/CL/CLMemoryRegion.h>
+
+#include <Convert.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+CLTensor::CLTensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses)
+ : _cl_tensor(std::make_shared<arm_compute::CLTensor>()), _rank{rank}, _num_uses{num_uses}
+{
+ allocator()->init(info);
+}
+
+const arm_compute::CLTensor *CLTensor::handle() const { return _cl_tensor.get(); }
+
+arm_compute::CLTensor *CLTensor::handle() { return _cl_tensor.get(); }
+
+arm_compute::CLTensorAllocator *CLTensor::allocator() { return _cl_tensor->allocator(); }
+
+void CLTensor::setBuffer(void *host_ptr)
+{
+ // Constructs a Buffer on a user-supplied memory
+ auto buffer = cl::Buffer(arm_compute::CLScheduler::get().context(),
+ CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, info()->total_size(), host_ptr);
+ // import memory
+ allocator()->import_memory(buffer);
+}
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_cl/operand/CLTensor.h b/runtime/onert/backend/acl_cl/operand/CLTensor.h
new file mode 100644
index 000000000..c92208803
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/operand/CLTensor.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__
+#define __ONERT_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__
+
+#include <arm_compute/core/TensorInfo.h>
+#include <arm_compute/runtime/CL/CLTensor.h>
+#include <arm_compute/runtime/CL/CLScheduler.h>
+#include "arm_compute/runtime/CL/CLTensorAllocator.h"
+#include "ICLTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+class CLTensor : public ICLTensor
+{
+public:
+ CLTensor() = delete;
+
+public:
+ CLTensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses);
+
+public:
+ size_t num_dimensions() const final { return _rank; }
+
+public:
+ const arm_compute::CLTensor *handle() const override;
+ arm_compute::CLTensor *handle() override;
+ size_t num_uses() const { return _num_uses; }
+
+public:
+ arm_compute::CLTensorAllocator *allocator();
+ /** Set given buffer as the buffer of the tensor
+ *
+ * @note Ownership of the memory is not transferred to this object.
+ * Thus management (allocate/free) should be done by the client.
+ *
+ * @param[in] host_ptr Storage to be used.
+ */
+ void setBuffer(void *host_ptr);
+
+private:
+ std::shared_ptr<arm_compute::CLTensor> _cl_tensor;
+ size_t _rank;
+ size_t _num_uses;
+};
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__
diff --git a/runtime/onert/backend/acl_cl/operand/ICLTensor.cc b/runtime/onert/backend/acl_cl/operand/ICLTensor.cc
new file mode 100644
index 000000000..2cee0b474
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/operand/ICLTensor.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ICLTensor.h"
+
+#include <arm_compute/runtime/CL/CLScheduler.h>
+#include <arm_compute/core/CL/OpenCL.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+void ICLTensor::access(const std::function<void(ITensor &tensor)> &fn)
+{
+ auto &queue = ::arm_compute::CLScheduler::get().queue();
+
+ // This is an optional input
+ if (total_size() == 0)
+ return;
+
+ map(queue);
+ fn(*this);
+ unmap(queue);
+}
+
+void ICLTensor::enqueueWriteBuffer(const void *ptr, bool blocking)
+{
+ auto &queue = ::arm_compute::CLScheduler::get().queue();
+ queue.enqueueWriteBuffer(handle()->cl_buffer(), blocking ? CL_TRUE : CL_FALSE, 0,
+ info()->total_size(), ptr);
+}
+
+void ICLTensor::enqueueReadBuffer(void *ptr, bool blocking)
+{
+ auto &queue = ::arm_compute::CLScheduler::get().queue();
+ queue.enqueueReadBuffer(handle()->cl_buffer(), blocking ? CL_TRUE : CL_FALSE, 0,
+ info()->total_size(), ptr);
+}
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_cl/operand/ICLTensor.h b/runtime/onert/backend/acl_cl/operand/ICLTensor.h
new file mode 100644
index 000000000..e6e20a8bf
--- /dev/null
+++ b/runtime/onert/backend/acl_cl/operand/ICLTensor.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__
+#define __ONERT_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__
+
+#include <arm_compute/core/CL/ICLTensor.h>
+
+#include <IACLTensor.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+class ICLTensor : public acl_common::IACLTensor
+{
+public:
+ const arm_compute::ICLTensor *handle() const override = 0;
+ arm_compute::ICLTensor *handle() override = 0;
+
+public:
+ void access(const std::function<void(ITensor &tensor)> &fn) final;
+ bool needMemoryMap() const final { return true; }
+ void enqueueWriteBuffer(const void *ptr, bool blocking = true) final;
+ void enqueueReadBuffer(void *ptr, bool blocking = true) final;
+
+private:
+ void map(cl::CommandQueue &q, bool blocking = true) { return handle()->map(q, blocking); }
+ void unmap(cl::CommandQueue &q) { return handle()->unmap(q); }
+};
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__
diff --git a/runtime/onert/backend/acl_common/AclActivationBuilder.h b/runtime/onert/backend/acl_common/AclActivationBuilder.h
new file mode 100644
index 000000000..bfdea6ea0
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclActivationBuilder.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_ACL_ACTIVATION_BUILDER_H__
+#define __ONERT_BACKEND_ACL_COMMON_ACL_ACTIVATION_BUILDER_H__
+
+#include <memory>
+
+#include <ir/InternalType.h>
+#include <exec/IFunction.h>
+#include <exec/NopFunction.h>
+
+#include "Convert.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+template <typename T_Tensor, typename T_ActivationLayer, typename T_ExecFunction>
+class AclActivationBuilder
+{
+private:
+ static std::unique_ptr<exec::IFunction> generateReLU(T_Tensor *ifm_alloc);
+ static std::unique_ptr<exec::IFunction> generateReLU1(T_Tensor *ifm_alloc);
+ static std::unique_ptr<exec::IFunction> generateReLU6(T_Tensor *ifm_alloc);
+
+public:
+ static std::unique_ptr<exec::IFunction> generate(ir::Activation code, T_Tensor *ifm_alloc);
+};
+
+template <typename T_Tensor, typename T_ActivationLayer, typename T_ExecFunction>
+std::unique_ptr<exec::IFunction>
+AclActivationBuilder<T_Tensor, T_ActivationLayer, T_ExecFunction>::generateReLU(T_Tensor *ifm_alloc)
+{
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU};
+
+ auto fn = std::make_unique<T_ActivationLayer>();
+
+ fn->configure(ifm_alloc, nullptr, act_info);
+
+ return asFunction<T_ExecFunction>(std::move(fn));
+}
+
+template <typename T_Tensor, typename T_ActivationLayer, typename T_ExecFunction>
+std::unique_ptr<exec::IFunction>
+AclActivationBuilder<T_Tensor, T_ActivationLayer, T_ExecFunction>::generateReLU1(
+ T_Tensor *ifm_alloc)
+{
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f};
+
+ auto fn = std::make_unique<T_ActivationLayer>();
+
+ fn->configure(ifm_alloc, nullptr, act_info);
+
+ return asFunction<T_ExecFunction>(std::move(fn));
+}
+
+template <typename T_Tensor, typename T_ActivationLayer, typename T_ExecFunction>
+std::unique_ptr<exec::IFunction>
+AclActivationBuilder<T_Tensor, T_ActivationLayer, T_ExecFunction>::generateReLU6(
+ T_Tensor *ifm_alloc)
+{
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f};
+
+ auto fn = std::make_unique<T_ActivationLayer>();
+
+ fn->configure(ifm_alloc, nullptr, act_info);
+
+ return asFunction<T_ExecFunction>(std::move(fn));
+}
+
+template <typename T_Tensor, typename T_ActivationLayer, typename T_ExecFunction>
+std::unique_ptr<exec::IFunction>
+AclActivationBuilder<T_Tensor, T_ActivationLayer, T_ExecFunction>::generate(ir::Activation code,
+ T_Tensor *ifm_alloc)
+{
+ switch (code)
+ {
+ case ir::Activation::NONE:
+ {
+ return std::make_unique<exec::NopFunction>();
+ }
+ case ir::Activation::RELU:
+ {
+ return generateReLU(ifm_alloc);
+ }
+ case ir::Activation::RELU1:
+ {
+ return generateReLU1(ifm_alloc);
+ }
+ case ir::Activation::RELU6:
+ {
+ return generateReLU6(ifm_alloc);
+ }
+ default:
+ {
+ throw std::runtime_error("Not supported, yet");
+ }
+ }
+}
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_ACL_ACTIVATION_BUILDER_H__
diff --git a/runtime/onert/backend/acl_common/AclConstantInitializer.cc b/runtime/onert/backend/acl_common/AclConstantInitializer.cc
new file mode 100644
index 000000000..21f41a3e6
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclConstantInitializer.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AclConstantInitializer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+AclConstantInitializer::AclConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg)
+ : IConstantInitializer{operands}, _tensor_reg{tensor_reg}
+{
+ // DO NOTHING
+}
+
+void AclConstantInitializer::copyInputInitialize(const ir::Operation &node, uint32_t index)
+{
+ assert(node.getInputs().size() > index);
+
+ const auto &input_index = node.getInputs().at(index);
+ if (input_index.valid())
+ {
+ const auto &input_obj = _operands.at(input_index);
+ registerCopyInitializer(input_index, input_obj);
+ }
+}
+
+void AclConstantInitializer::permuteInputInitialize(const ir::Operation &node, uint32_t index)
+{
+ assert(node.getInputs().size() > index);
+
+ const auto &input_index = node.getInputs().at(index);
+ const auto &input_obj = _operands.at(input_index);
+ registerPermuteInitializer(input_index, input_obj);
+}
+
+void AclConstantInitializer::visit(const ir::operation::BatchToSpaceND &node)
+{
+ const auto &block_size_index = node.getInputs().at(ir::operation::BatchToSpaceND::BLOCK_SIZE);
+ const auto &block_size_obj = _operands.at(block_size_index);
+
+ if (block_size_obj.isConstant())
+ {
+ _init_map[block_size_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) {
+ assert(model_obj.data());
+ const auto &shape = model_obj.shape();
+ const auto base = reinterpret_cast<const int32_t *>(model_obj.data()->base());
+ assert(model_obj.shape().rank() == 1);
+ obj.access([&](ITensor &tensor) {
+ for (size_t i = 0; i < shape.num_elements(); ++i)
+ {
+ const int32_t value = base[shape.num_elements() - i - 1];
+ int32_t *into = reinterpret_cast<int32_t *>(tensor.buffer() +
+ tensor.calcOffset({static_cast<int32_t>(i)}));
+ *into = value;
+ }
+ });
+ };
+ }
+}
+
+void AclConstantInitializer::visit(const ir::operation::Conv2D &node)
+{
+ permuteInputInitialize(node, ir::operation::Conv2D::KERNEL);
+ copyInputInitialize(node, ir::operation::Conv2D::BIAS);
+}
+
+void AclConstantInitializer::visit(const ir::operation::DepthwiseConv2D &node)
+{
+ permuteInputInitialize(node, ir::operation::DepthwiseConv2D::KERNEL);
+ copyInputInitialize(node, ir::operation::DepthwiseConv2D::BIAS);
+}
+
+void AclConstantInitializer::visit(const ir::operation::FullyConnected &node)
+{
+ copyInputInitialize(node, ir::operation::FullyConnected::WEIGHT);
+ copyInputInitialize(node, ir::operation::FullyConnected::BIAS);
+}
+
+void AclConstantInitializer::visit(const ir::operation::LSTM &node)
+{
+ copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_INPUT_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_FORGET_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_CELL_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_OUTPUT_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_INPUT_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_FORGET_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_CELL_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_OUTPUT_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::CELL_TO_INPUT_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::CELL_TO_FORGET_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::CELL_TO_OUTPUT_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::INPUT_GATE_BIAS);
+ copyInputInitialize(node, ir::operation::LSTM::FORGET_GATE_BIAS);
+ copyInputInitialize(node, ir::operation::LSTM::OUTPUT_GATE_BIAS);
+ copyInputInitialize(node, ir::operation::LSTM::PROJECTION_WEIGHTS);
+ copyInputInitialize(node, ir::operation::LSTM::PROJECTION_BIAS);
+}
+
+void AclConstantInitializer::visit(const ir::operation::RNN &node)
+{
+ copyInputInitialize(node, ir::operation::RNN::WEIGHTS);
+ copyInputInitialize(node, ir::operation::RNN::RECURRENT_WEIGHTS);
+ copyInputInitialize(node, ir::operation::RNN::BIAS);
+}
+
+void AclConstantInitializer::visit(const ir::operation::TransposeConv &node)
+{
+ permuteInputInitialize(node, ir::operation::TransposeConv::KERNEL);
+}
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_common/AclConstantInitializer.h b/runtime/onert/backend/acl_common/AclConstantInitializer.h
new file mode 100644
index 000000000..52f4c54cf
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclConstantInitializer.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_ACL_COMMON_ACLCONSTANT_INITIALIZER_H__
+#define __ONERT_COMPILER_ACL_COMMON_ACLCONSTANT_INITIALIZER_H__
+
+#include <backend/IConstantInitializer.h>
+#include <ir/Operands.h>
+#include "AclTensorRegistry.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+class AclConstantInitializer : public IConstantInitializer
+{
+public:
+ AclConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg);
+
+public:
+ void visit(const ir::operation::BatchToSpaceND &) override;
+ void visit(const ir::operation::Conv2D &) override;
+ void visit(const ir::operation::DepthwiseConv2D &) override;
+ void visit(const ir::operation::FullyConnected &) override;
+ void visit(const ir::operation::LSTM &) override;
+ void visit(const ir::operation::RNN &) override;
+ void visit(const ir::operation::TransposeConv &) override;
+
+protected:
+ void copyInputInitialize(const ir::Operation &node, uint32_t index);
+ void permuteInputInitialize(const ir::Operation &node, uint32_t index);
+
+private:
+ std::shared_ptr<ITensorRegistry> tensor_registry() const final { return _tensor_reg; }
+
+protected:
+ std::shared_ptr<ITensorRegistry> _tensor_reg;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_COMPILER_ACL_COMMON_ACLCONSTANT_INITIALIZER_H__
diff --git a/runtime/onert/backend/acl_common/AclFunction.h b/runtime/onert/backend/acl_common/AclFunction.h
new file mode 100644
index 000000000..94b65863a
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclFunction.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_KERNEL_ACL_FUNCTION_H__
+#define __ONERT_BACKEND_ACL_COMMON_KERNEL_ACL_FUNCTION_H__
+
+#include <exec/IFunction.h>
+#include <arm_compute/runtime/IFunction.h>
+#include <memory>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+class AclFunction : public ::onert::exec::IFunction
+{
+public:
+ AclFunction() = delete;
+
+public:
+ AclFunction(std::unique_ptr<::arm_compute::IFunction> &&func) : _func(std::move(func))
+ {
+ // DO NOTHING
+ }
+
+public:
+ void run() override { _func->run(); }
+ void prepare() override { _func->prepare(); }
+
+private:
+ std::unique_ptr<::arm_compute::IFunction> _func;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_KERNEL_ACL_FUNCTION_H__
diff --git a/runtime/onert/backend/acl_common/AclInternalBufferManager.h b/runtime/onert/backend/acl_common/AclInternalBufferManager.h
new file mode 100644
index 000000000..f893bb44b
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclInternalBufferManager.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_INTERNAL_BUFFER_MANAGER_H__
+#define __ONERT_BACKEND_ACL_COMMON_INTERNAL_BUFFER_MANAGER_H__
+
+#include <arm_compute/runtime/IMemoryManager.h>
+#include <cassert>
+#include <memory>
+#include <backend/IMemoryManager.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+// NOTE. If any backend can use something like InternalBufferManager,
+// this interface can be moved to core/include/backend/
+/**
+ * @brief Interface for InternalBufferManager which has ::arm_compute::IMemoryManager pointer
+ */
+struct IInternalBufferManager : public backend::IMemoryManager
+{
+ virtual ~IInternalBufferManager() = default;
+
+ /**
+ * @brief Get shared_ptr of ::arm_compute::IMemoryManager
+ */
+ virtual std::shared_ptr<::arm_compute::IMemoryManager> internal_buffer_manager(void) = 0;
+};
+
+/**
+ * @brief class for InternalBufferManager which has ::arm_compute::IMemoryManager pointer
+ */
+template <typename T_MemoryManager, typename T_PoolManager, typename T_LifetimeManager,
+ typename T_Allocator>
+class AclInternalBufferManager : public IInternalBufferManager
+{
+public:
+ AclInternalBufferManager() : _allocator{nullptr}
+ {
+ std::shared_ptr<T_LifetimeManager> lifetime_mgr = std::make_shared<T_LifetimeManager>();
+ std::shared_ptr<T_PoolManager> pool_mgr = std::make_shared<T_PoolManager>();
+
+ _internal_manager = std::make_shared<T_MemoryManager>(lifetime_mgr, pool_mgr);
+ assert(_internal_manager);
+ }
+
+ virtual ~AclInternalBufferManager() = default;
+
+ /**
+ * @brief Allocate the internal buffer manager on acl
+ */
+ void allocate(void) override
+ {
+ _allocator = std::make_shared<T_Allocator>();
+ _internal_manager->populate(*_allocator, 1);
+ }
+
+ /**
+ * @brief Deallocate the internal buffer manager on acl
+ */
+ void deallocate(void) override { _internal_manager->clear(); }
+
+ /**
+ * @brief Get shared_ptr of ::arm_compute::IMemoryManager
+ */
+ std::shared_ptr<::arm_compute::IMemoryManager> internal_buffer_manager(void) override
+ {
+ return _internal_manager;
+ }
+
+private:
+ std::shared_ptr<T_Allocator> _allocator;
+ std::shared_ptr<T_MemoryManager> _internal_manager;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_INTERNAL_BUFFER_MANAGER_H__
diff --git a/runtime/onert/backend/acl_common/AclKernelGen.h b/runtime/onert/backend/acl_common/AclKernelGen.h
new file mode 100644
index 000000000..3d0813f81
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclKernelGen.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_ACL_KERNEL_GEN_H_
+#define __ONERT_BACKEND_ACL_COMMON_ACL_KERNEL_GEN_H_
+
+#include <exec/IFunction.h>
+#include <ir/Operands.h>
+
+#include <ir/operation/LSTM.h>
+#include <arm_compute/runtime/CL/CLFunctions.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+void enableDimCorrection(IACLTensor *tensor)
+{
+ size_t input_rank = tensor->num_dimensions();
+ const_cast<arm_compute::TensorShape &>(tensor->info()->tensor_shape())
+ .set(input_rank - 1, tensor->info()->dimension(input_rank - 1), true);
+}
+
+void disableDimCorrection(IACLTensor *tensor)
+{
+ size_t input_rank = tensor->num_dimensions();
+ const_cast<arm_compute::TensorShape &>(tensor->info()->tensor_shape())
+ .set(input_rank - 1, tensor->info()->dimension(input_rank - 1), false);
+}
+
+template <typename Layer, typename... Args>
+std::unique_ptr<arm_compute::IFunction> generateLayer(Args &&... args)
+{
+ auto l = std::make_unique<Layer>();
+
+ l->configure(std::forward<Args>(args)...);
+
+ return l;
+}
+
+template <typename Layer, typename... Args>
+std::unique_ptr<arm_compute::IFunction>
+generateLayer(std::shared_ptr<arm_compute::IMemoryManager> memory_manager, Args &&... args)
+{
+ auto l = std::make_unique<Layer>(memory_manager);
+
+ l->configure(std::forward<Args>(args)...);
+
+ return l;
+}
+
+template <typename T_FunctionWrapper, typename T_Tensor, typename T_ACLLayer,
+ typename T_TensorRegistry>
+std::unique_ptr<exec::IFunction> kernelGenLSTM(const ir::operation::LSTM &node,
+ const ir::Operands &operands,
+ const std::shared_ptr<T_TensorRegistry> &tensor_reg)
+{
+ // TODO Support dynamic rnn
+ // TODO Fix subtle error in the case of non-CIFG, non-peephole and No Projection.
+ const auto scratch_buffer_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)};
+ const auto output_state_out_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)};
+ const auto cell_state_out_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)};
+ const auto output_index{node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)};
+
+ const auto input_index{node.getInputs().at(ir::operation::LSTM::Input::INPUT)};
+ const auto input_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)}; // optional
+ const auto input_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_FORGET_WEIGHTS)};
+ const auto input_to_cell_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_CELL_WEIGHTS)};
+ const auto input_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)};
+ const auto recurrent_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)}; // optional
+ const auto recurrent_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS)};
+ const auto recurrent_to_cell_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_CELL_WEIGHTS)};
+ const auto recurrent_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS)};
+ const auto cell_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_INPUT_WEIGHTS)}; // optional
+ const auto cell_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_FORGET_WEIGHTS)}; // optional
+ const auto cell_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_OUTPUT_WEIGHTS)}; // optional
+ const auto input_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_GATE_BIAS)};
+ const auto forget_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::FORGET_GATE_BIAS)};
+ const auto cell_bias_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_BIAS)};
+ const auto output_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_GATE_BIAS)};
+ const auto projection_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_WEIGHTS)}; // optional
+ const auto projection_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_BIAS)}; // optional
+ const auto output_state_in_index{
+ node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_STATE_IN)};
+ const auto cell_state_in_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_STATE_IN)};
+ const auto cell_threshold = node.param().cell_threshold;
+ const auto projection_threshold = node.param().projection_threshold;
+
+ bool has_input_to_input_weights = operands.at(input_to_input_weights_index).shape().dim(0) != 0 &&
+ operands.at(input_to_input_weights_index).shape().dim(1) != 0;
+ bool has_recurrent_to_input_weights =
+ operands.at(recurrent_to_input_weights_index).shape().dim(0) != 0 &&
+ operands.at(recurrent_to_input_weights_index).shape().dim(1) != 0;
+ bool has_cell_to_forget_weights = operands.at(cell_to_forget_weights_index).shape().dim(0) != 0;
+ bool has_cell_to_output_weights = operands.at(cell_to_output_weights_index).shape().dim(0) != 0;
+ bool has_projection_weights = operands.at(projection_weights_index).shape().dim(0) != 0 &&
+ operands.at(projection_weights_index).shape().dim(1) != 0;
+ bool has_projection_bias = operands.at(projection_bias_index).shape().dim(0);
+
+ // NOTE The input_to_input_weights and the recurrent_to_input_weights do not exist in CIFG.
+ // true: no CIFG
+ // false: CIFG
+ // NOTE The cell_to_input_weights does not exist in non-peephole although regular LSTM(non-CIFG).
+ bool has_cifg_param = has_input_to_input_weights && has_recurrent_to_input_weights;
+
+ // NOTE The cell_to_forget_weights and the cell_to_output_weights exist in peephole.
+ // But the cell_to_input_weights does not exist in regular CIFG although peephole.
+ // true: peephole
+ // false: no peephole
+ bool has_peephole_param = has_cell_to_forget_weights && has_cell_to_output_weights;
+
+ // NOTE Although the projection weights has data the projection bias may not have data.
+ bool has_projection_param = has_projection_weights;
+
+ const auto activation = node.param().activation;
+ const auto cell_clip = cell_threshold;
+ const auto projection_clip = projection_threshold;
+ assert(cell_clip >= 0.f && projection_clip >= 0.f);
+
+ auto scratch_buffer_tensor = tensor_reg->getAclTensor(scratch_buffer_index);
+ auto output_state_out_tensor = tensor_reg->getAclTensor(output_state_out_index);
+ auto cell_state_out_tensor = tensor_reg->getAclTensor(cell_state_out_index);
+ auto output_tensor = tensor_reg->getAclTensor(output_index);
+
+ auto input_tensor = tensor_reg->getAclTensor(input_index);
+
+ auto input_to_forget_weights_tensor = tensor_reg->getAclTensor(input_to_forget_weights_index);
+ auto input_to_cell_weights_tensor = tensor_reg->getAclTensor(input_to_cell_weights_index);
+ auto input_to_output_weights_tensor = tensor_reg->getAclTensor(input_to_output_weights_index);
+ auto recurrent_to_forget_weights_tensor =
+ tensor_reg->getAclTensor(recurrent_to_forget_weights_index);
+ auto recurrent_to_cell_weights_tensor = tensor_reg->getAclTensor(recurrent_to_cell_weights_index);
+ auto recurrent_to_output_weights_tensor =
+ tensor_reg->getAclTensor(recurrent_to_output_weights_index);
+
+ auto forget_gate_bias_tensor = tensor_reg->getAclTensor(forget_gate_bias_index);
+ auto cell_bias_tensor = tensor_reg->getAclTensor(cell_bias_index);
+ auto output_gate_bias_tensor = tensor_reg->getAclTensor(output_gate_bias_index);
+ auto output_state_in_tensor = tensor_reg->getAclTensor(output_state_in_index);
+ auto cell_state_in_tensor = tensor_reg->getAclTensor(cell_state_in_index);
+
+ auto act_info = asActivationLayerInfo(activation);
+
+ ::arm_compute::LSTMParams<T_Tensor> lstm_params{};
+ if (has_cifg_param)
+ {
+ auto input_to_input_weights_tensor =
+ tensor_reg->getAclTensor(input_to_input_weights_index); // optional
+ auto recurrent_to_input_weights_tensor =
+ tensor_reg->getAclTensor(recurrent_to_input_weights_index); // optional
+ auto cell_to_input_weights_handle =
+ has_peephole_param ? tensor_reg->getAclTensor(cell_to_input_weights_index)->handle()
+ : nullptr; // optional (non-cifg && peephole)
+ auto input_gate_bias_tensor = tensor_reg->getAclTensor(input_gate_bias_index); // optional
+ lstm_params.set_cifg_params(input_to_input_weights_tensor->handle(),
+ recurrent_to_input_weights_tensor->handle(),
+ cell_to_input_weights_handle, input_gate_bias_tensor->handle());
+ }
+ if (has_peephole_param)
+ {
+ auto cell_to_forget_weights_tensor =
+ tensor_reg->getAclTensor(cell_to_forget_weights_index); // optional
+ auto cell_to_output_weights_tensor =
+ tensor_reg->getAclTensor(cell_to_output_weights_index); // optional
+ lstm_params.set_peephole_params(cell_to_forget_weights_tensor->handle(),
+ cell_to_output_weights_tensor->handle());
+ }
+ if (has_projection_param)
+ {
+ auto projection_weights_tensor = tensor_reg->getAclTensor(projection_weights_index); // optional
+ auto projection_bias_handle = has_projection_bias
+ ? tensor_reg->getAclTensor(projection_bias_index)->handle()
+ : nullptr; // optional
+ lstm_params.set_projection_params(projection_weights_tensor->handle(), projection_bias_handle);
+ }
+
+ auto fn = generateLayer<T_ACLLayer>(
+ input_tensor->handle(), input_to_forget_weights_tensor->handle(),
+ input_to_cell_weights_tensor->handle(), input_to_output_weights_tensor->handle(),
+ recurrent_to_forget_weights_tensor->handle(), recurrent_to_cell_weights_tensor->handle(),
+ recurrent_to_output_weights_tensor->handle(), forget_gate_bias_tensor->handle(),
+ cell_bias_tensor->handle(), output_gate_bias_tensor->handle(),
+ output_state_in_tensor->handle(), cell_state_in_tensor->handle(),
+ scratch_buffer_tensor->handle(), output_state_out_tensor->handle(),
+ cell_state_out_tensor->handle(), output_tensor->handle(), lstm_params, act_info, cell_clip,
+ projection_clip);
+
+ return std::make_unique<T_FunctionWrapper>(std::move(fn));
+}
+
+template <typename T_FunctionWrapper, typename T_Tensor, typename T_ACLLayer,
+ typename T_TensorBuilder, typename T_TensorRegistry>
+std::unique_ptr<exec::IFunction>
+kernelGenFullyConnected(const ir::operation::FullyConnected &node, const ir::Operands &operands,
+ const std::shared_ptr<T_TensorBuilder> &tensor_builder,
+ const std::shared_ptr<T_TensorRegistry> &tensor_reg, ir::Layout layout)
+{
+ using ir::operation::FullyConnected;
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)};
+ const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)};
+ const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)};
+
+ const auto input_rank = operands.at(input_index).shape().rank();
+
+ const auto output_size =
+ operands.at(output_index).shape().dim(operands.at(output_index).shape().rank() - 1);
+ UNUSED_RELEASE(output_size);
+ assert(bias_index.undefined() || operands.at(bias_index).shape().dim(0) == output_size);
+ assert(operands.at(weight_index).shape().dim(0) == output_size);
+ const auto batch_size =
+ operands.at(output_index).shape().dim(operands.at(output_index).shape().rank() - 2);
+ const auto input_size =
+ operands.at(weight_index).shape().dim(operands.at(weight_index).shape().rank() - 1);
+
+ // Check for reshaping input's shape into rank-2
+ bool needs_reshape = false;
+ ir::Shape reshape(2);
+ if (input_rank == 3 || input_rank == 4)
+ {
+ const auto &ifm_shape = operands.at(input_index).shape();
+ auto feature_size = 1;
+ for (int i = 0; i < ifm_shape.rank(); ++i)
+ {
+ feature_size *= ifm_shape.dim(i);
+ }
+
+ UNUSED_RELEASE(feature_size);
+ assert(feature_size == batch_size * input_size);
+
+ // for reshaping
+ needs_reshape = true;
+ reshape.dim(0) = batch_size; /* H */
+ reshape.dim(1) = input_size; /* W */
+ }
+
+ auto output_tensor = tensor_reg->getAclTensor(output_index);
+ const auto input_tensor = tensor_reg->getAclTensor(input_index);
+ const auto weight_tensor = tensor_reg->getAclTensor(weight_index);
+ const auto bias_tensor = bias_index.undefined() ? nullptr : tensor_reg->getAclTensor(bias_index);
+ const auto frontend_layout = layout;
+ const auto acl_layout = output_tensor->handle()->info()->data_layout();
+
+ typename T_ACLLayer::KernelType kernel_type = T_ACLLayer::KernelType::GENERAL;
+ if (operands.at(weight_index).isConstant())
+ {
+ kernel_type = T_ACLLayer::KernelType::PREPROCESSED_WEIGHTS;
+ assert(operands.at(weight_index).data());
+ }
+
+ auto fn = generateLayer<T_ACLLayer>(
+ tensor_builder->acl_tensor_manager()->internal_buffer_manager(), input_tensor->handle(),
+ weight_tensor->handle(), bias_tensor != nullptr ? bias_tensor->handle() : nullptr,
+ output_tensor->handle(), needs_reshape,
+ asTensorShape(reshape, frontend_layout, asRuntimeLayout(acl_layout)), kernel_type);
+
+ return std::make_unique<T_FunctionWrapper>(std::move(fn));
+}
+
+template <typename T_ACLLayer, typename T_PoolOp, typename T_AclTensorRegistry>
+std::unique_ptr<::arm_compute::IFunction>
+kernelGenPool2D(const T_PoolOp &node, const ir::Operands &operands,
+ const std::shared_ptr<T_AclTensorRegistry> &tensor_reg, ir::Layout layout,
+ ::arm_compute::PoolingType pooling_type)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(0)};
+
+ const auto ofm_shape = operands.at(ofm_index).shape().asFeature(layout);
+ const auto ifm_shape = operands.at(ifm_index).shape().asFeature(layout);
+
+ const auto kh = node.param().kh;
+ const auto kw = node.param().kw;
+ const auto stride = node.param().stride;
+ const auto padding =
+ ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh);
+
+ VERBOSE(Pool2DParam) << "IFM_H: " << ifm_shape.H << std::endl;
+ VERBOSE(Pool2DParam) << "IFM_W: " << ifm_shape.W << std::endl;
+ VERBOSE(Pool2DParam) << "OFM_H: " << ofm_shape.H << std::endl;
+ VERBOSE(Pool2DParam) << "OFM_W: " << ofm_shape.W << std::endl;
+ VERBOSE(Pool2DParam) << "KER_H: " << kh << std::endl;
+ VERBOSE(Pool2DParam) << "KER_W: " << kw << std::endl;
+ VERBOSE(Pool2DParam) << "STRIDE_H: " << stride.vertical << std::endl;
+ VERBOSE(Pool2DParam) << "STRIDE_W: " << stride.horizontal << std::endl;
+ VERBOSE(Pool2DParam) << "PAD(T): " << padding.top << std::endl;
+ VERBOSE(Pool2DParam) << "PAD(B): " << padding.bottom << std::endl;
+ VERBOSE(Pool2DParam) << "PAD(L): " << padding.left << std::endl;
+ VERBOSE(Pool2DParam) << "PAD(R): " << padding.right << std::endl;
+
+ auto ofm_tensor = tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = tensor_reg->getAclTensor(ifm_index);
+
+ ::arm_compute::PoolingLayerInfo info{
+ pooling_type, ::arm_compute::Size2D{kw, kh}, ifm_tensor->info()->data_layout(),
+ asPadStrideInfo(padding, stride), true /* exclude_padding */};
+
+ auto fn = generateLayer<T_ACLLayer>(ifm_tensor->handle(), ofm_tensor->handle(), info);
+
+ return fn;
+}
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_ACL_KERNEL_GEN_H_
diff --git a/runtime/onert/backend/acl_common/AclLinearMemoryManager.h b/runtime/onert/backend/acl_common/AclLinearMemoryManager.h
new file mode 100644
index 000000000..09f25e7a8
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclLinearMemoryManager.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_LINEAR_MEMORY_MANAGER_H__
+#define __ONERT_BACKEND_ACL_COMMON_LINEAR_MEMORY_MANAGER_H__
+
+#include <cassert>
+
+#include "AclMemoryManager.h"
+#include "ir/OperandIndexMap.h"
+#include "util/logging.h"
+
+namespace
+{
+
+template <typename T_MemoryManager, typename T_PoolManager, typename T_LifetimeManager>
+std::shared_ptr<T_MemoryManager> createMemoryManager()
+{
+ std::shared_ptr<T_LifetimeManager> lifetime_mgr = std::make_shared<T_LifetimeManager>();
+ std::shared_ptr<T_PoolManager> pool_mgr = std::make_shared<T_PoolManager>();
+
+ std::shared_ptr<T_MemoryManager> mem_mgr =
+ std::make_shared<T_MemoryManager>(lifetime_mgr, pool_mgr);
+ return mem_mgr;
+}
+
+} // namespace
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor, typename T_MemoryManager,
+ typename T_PoolManager, typename T_LifetimeManager, typename T_Allocator,
+ typename T_MemoryGroup>
+class AclLinearMemoryManager : public AclMemoryManager<T_ITensor, T_Tensor, T_SubTensor>
+{
+public:
+ AclLinearMemoryManager()
+ : _allocator{nullptr},
+ _io_manager{createMemoryManager<T_MemoryManager, T_PoolManager, T_LifetimeManager>()},
+ _io_group{std::make_shared<T_MemoryGroup>(_io_manager)}
+ {
+ // DO NOTHING
+ }
+
+ virtual ~AclLinearMemoryManager() = default;
+
+ void allocate(void) override
+ {
+ _allocator = std::make_shared<T_Allocator>();
+ _io_manager->populate(*_allocator, 1);
+ _io_group->acquire();
+ }
+
+ void deallocate(void) override
+ {
+ _io_group->release();
+ _io_manager->clear();
+ }
+
+ void startLifetime(const ir::OperandIndex &ind) override
+ {
+ auto &tensors = this->tensors();
+ assert(tensors.find(ind) != tensors.end());
+
+ auto tensor = tensors[ind];
+ assert(tensor->handle());
+
+ _io_group->manage(tensor->handle());
+ }
+
+ void finishLifetime(const ir::OperandIndex &ind) override
+ {
+ auto &tensors = this->tensors();
+ assert(tensors.find(ind) != tensors.end());
+
+ auto tensor = tensors[ind];
+ assert(tensor->allocator());
+
+ tensor->allocator()->allocate();
+ }
+
+private:
+ std::shared_ptr<T_Allocator> _allocator;
+ std::shared_ptr<T_MemoryManager> _io_manager;
+ std::shared_ptr<T_MemoryGroup> _io_group;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_LINEAR_MEMORY_MANAGER_H__
diff --git a/runtime/onert/backend/acl_common/AclMemoryManager.h b/runtime/onert/backend/acl_common/AclMemoryManager.h
new file mode 100644
index 000000000..eefcec130
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclMemoryManager.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_MEMORY_MANAGER_H__
+#define __ONERT_BACKEND_ACL_COMMON_MEMORY_MANAGER_H__
+
+#include <arm_compute/core/Types.h>
+#include <arm_compute/runtime/IMemoryManager.h>
+#include <cassert>
+
+#include "backend/IMemoryManager.h"
+#include "ir/OperandIndexMap.h"
+#include "Convert.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+class AclMemoryManager : public backend::IMemoryManager
+{
+public:
+ AclMemoryManager()
+ {
+ // DO NOTHING
+ }
+
+ virtual ~AclMemoryManager() = default;
+
+ void allocate(void) override
+ {
+ for (const auto &tensor_entry : _tensors)
+ {
+ auto tensor = tensor_entry.second;
+ tensor->allocator()->allocate();
+ }
+ }
+
+ void deallocate(void) override
+ {
+ for (const auto &tensor_entry : _tensors)
+ {
+ auto tensor = tensor_entry.second;
+ tensor->allocator()->free();
+ }
+ }
+
+ virtual void startLifetime(const ir::OperandIndex &) { /* DO NOTHING */}
+ virtual void finishLifetime(const ir::OperandIndex &) { /* DO NOTHING */}
+
+ void buildTensor(const ir::OperandIndex &ind, const ::arm_compute::TensorInfo &info, size_t rank,
+ size_t num_uses)
+ {
+ auto tensor = std::make_shared<T_Tensor>(info, rank, num_uses);
+ _tensors[ind] = tensor;
+ }
+
+ void buildSubtensor(std::shared_ptr<T_ITensor> parent_tensor, const ir::OperandIndex &child_ind,
+ const ::arm_compute::TensorShape &shape,
+ const ::arm_compute::Coordinates &coordinates, size_t rank,
+ bool extent_parent)
+ {
+ auto subtensor =
+ std::make_shared<T_SubTensor>(parent_tensor.get(), shape, coordinates, rank, extent_parent);
+ _subtensors[child_ind] = subtensor;
+ }
+
+ ir::OperandIndexMap<std::shared_ptr<T_Tensor>> &tensors(void) { return _tensors; }
+
+ ir::OperandIndexMap<std::shared_ptr<T_SubTensor>> &subtensors(void) { return _subtensors; }
+
+private:
+ ir::OperandIndexMap<std::shared_ptr<T_Tensor>> _tensors;
+ ir::OperandIndexMap<std::shared_ptr<T_SubTensor>> _subtensors;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_MEMORY_MANAGER_H__
diff --git a/runtime/onert/backend/acl_common/AclSubTensorAnalyzer.h b/runtime/onert/backend/acl_common/AclSubTensorAnalyzer.h
new file mode 100644
index 000000000..3367f748f
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclSubTensorAnalyzer.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_ACL_SUB_TENSOR_ANALYZER_H__
+#define __ONERT_BACKEND_ACL_COMMON_ACL_SUB_TENSOR_ANALYZER_H__
+
+#include <ir/OperationVisitor.h>
+#include <ir/Graph.h>
+#include "ParentInfo.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+/**
+ * @brief Class to analyze tensor subsumption
+ */
+class AclSubTensorAnalyzer : public ir::OperationVisitor
+{
+public:
+ /**
+ * @brief Construct a new SubTensorAnalyzer object
+ * @param[in] ctx Graph operand set
+ */
+ AclSubTensorAnalyzer(const ir::Graph &graph) : _graph{graph}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void setLayout(ir::Layout layout) { _current_op_layout = layout; }
+
+ void setUsePadding() { usePadding = true; }
+
+ void visit(const ir::operation::Concat &node) override
+ {
+ // If operator is concat, fill subsumption info
+ int32_t axis_raw = node.param().axis;
+
+ const auto &output_index = node.getOutputs().at(0);
+ const auto &inputs = node.getInputs();
+
+ int32_t axis_point = 0;
+ const auto rank = _graph.operands().at(output_index).shape().rank();
+ int32_t axis = axis_raw < 0 ? (axis_raw + rank) : axis_raw;
+ assert(rank > axis);
+
+ // Concat elimination when axis is last dimension is not supported
+ // https://github.com/Samsung/ONE/issues/4407
+ // TODO Enable if backend don't use padding
+ if ((axis == rank - 1) && usePadding)
+ return;
+
+ for (const auto &ind : inputs)
+ {
+ /**
+ * NOTE Not support below cases.
+ * 1. concat's input is a constant.
+ * 2. concat's input is a input of model.
+ * 3. concat's input already becomes a subtensor of another concat.
+ */
+ if (_graph.operands().at(ind).isConstant() || _graph.getInputs().contains(ind) ||
+ _parent_map.find(ind) != _parent_map.end())
+ {
+ return;
+ }
+ }
+
+ for (const auto &input_index : inputs)
+ {
+ auto input_shape = _graph.operands().at(input_index).shape();
+ assert(rank == input_shape.rank());
+
+ ir::Coordinates coordinate_info{};
+ for (int i = 0; i < rank; i++)
+ {
+ coordinate_info.set(i, 0);
+ }
+ coordinate_info.set(axis, axis_point);
+
+ _parent_map.emplace(
+ input_index, acl_common::ParentInfo{output_index, _current_op_layout, coordinate_info});
+
+ axis_point += input_shape.dim(axis);
+ }
+ }
+
+ std::unordered_map<ir::OperandIndex, ParentInfo> &&releaseParentMap()
+ {
+ return std::move(_parent_map);
+ }
+
+private:
+ const ir::Graph &_graph;
+ std::unordered_map<ir::OperandIndex, ParentInfo> _parent_map;
+ ir::Layout _current_op_layout{ir::Layout::UNKNOWN};
+ bool usePadding{false};
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_ACL_SUB_TENSOR_ANALYZER_H__
diff --git a/runtime/onert/backend/acl_common/AclTensorBuilder.h b/runtime/onert/backend/acl_common/AclTensorBuilder.h
new file mode 100644
index 000000000..bb7abc95d
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclTensorBuilder.h
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__
+#define __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__
+
+#include <memory>
+#include <queue>
+
+#include <arm_compute/core/Types.h>
+#include <backend/ITensorBuilder.h>
+#include "ir/OperandIndexMap.h"
+#include <ir/Operands.h>
+#include "AclTensorManager.h"
+#include "AclTensorRegistry.h"
+#include <memory>
+#include "ParentInfo.h"
+#include <util/Utils.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+enum class UsesType
+{
+ FIRST,
+ LAST
+};
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+class AclTensorBuilder : public ITensorBuilder
+{
+public:
+ using T_AclTensorManager = AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>;
+
+ AclTensorBuilder(const ir::Operands &operands, T_AclTensorManager *tensor_mgr,
+ const std::shared_ptr<AclTensorRegistry<T_AclTensorManager>> &tensor_reg);
+
+ /**
+ * @brief Register tensor information to allocate on ACL-CL backend
+ * @param[in] ind Operand index
+ * @param[in] info Tensor information
+ * @param[in] layout Tensor data layout
+ */
+ void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
+ ir::Layout backend_layout) override;
+
+ void notifyFirstUse(const ir::OperandIndex &) override;
+ void notifyLastUse(const ir::OperandIndex &) override;
+
+ bool isRegistered(const ir::OperandIndex &) const override;
+
+ void prepare(void) override;
+ void allocate() override;
+ void postFunctionPrepare() override;
+
+ T_AclTensorManager *acl_tensor_manager(void) { return _tensor_mgr.get(); }
+
+ void setUsesCount(const ir::OperandIndex &index, size_t num_uses)
+ {
+ assert(_uses_count_map.find(index) != _uses_count_map.end() ? _uses_count_map[index] == num_uses
+ : true);
+ _uses_count_map[index] = num_uses;
+ }
+
+ void parent_map(std::unordered_map<ir::OperandIndex, ParentInfo> &&parent_map)
+ {
+ _parent_map = std::move(parent_map);
+ }
+
+ bool areSubTensorsOf(const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq);
+
+ /**
+ * @brief Check child tensor is allocated as subtensor of parent tensor
+ * @param[in] parent Index of parent
+ * @param[in] child Index of child
+ * @return @c true if child is allocated as subtensor of parent, otherwise @c false
+ */
+ bool isSubTensorOf(const ir::OperandIndex &parent, const ir::OperandIndex &child);
+
+private:
+ void buildTensors(void);
+ ir::OperandIndex findRootParent(ir::OperandIndex index);
+
+private:
+ const ir::Operands &_operands;
+ ir::OperandIndexMap<ir::OperandInfo> _tensor_info_map;
+ ir::OperandIndexMap<ir::Layout> _tensor_layout_map;
+ ir::OperandIndexMap<size_t> _uses_count_map;
+
+ std::unique_ptr<T_AclTensorManager> _tensor_mgr;
+ std::shared_ptr<AclTensorRegistry<T_AclTensorManager>> _tensor_reg;
+
+ // for linear executor
+ std::vector<std::pair<UsesType, ir::OperandIndex>> _lifetime_seq;
+
+ // Extra info for concat elimination
+ ir::OperandIndexMap<ParentInfo> _parent_map;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#include <cassert>
+#include <stack>
+
+#include "Convert.h"
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::AclTensorBuilder(
+ const ir::Operands &operands, T_AclTensorManager *tensor_mgr,
+ const std::shared_ptr<AclTensorRegistry<T_AclTensorManager>> &tensor_reg)
+ : _operands{operands}, _tensor_mgr{tensor_mgr}, _tensor_reg{tensor_reg}
+{
+ assert(_tensor_mgr);
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::registerTensorInfo(
+ const ir::OperandIndex &ind, const ir::OperandInfo &info, ir::Layout backend_layout)
+{
+ assert(_tensor_mgr->constTensors().size() == 0);
+ assert(_tensor_mgr->nonconstTensors().size() == 0);
+
+ _uses_count_map[ind] = _operands.at(ind).getUses().size();
+
+ if (_parent_map.count(ind) == 0)
+ {
+ // Normal Tensors
+ _tensor_info_map.emplace(ind, info);
+ _tensor_layout_map.insert({ind, backend_layout});
+ }
+ else
+ {
+ // SubTensors
+ assert(!info.isConstant() && "Subtensors of constants are not supported yet.");
+
+ // Update offset info and emplace
+ auto &parent_info = _parent_map[ind];
+ const auto &obj = _operands.at(ind);
+ auto parent_index = parent_info.parent;
+ auto &offset = parent_info.coordinates;
+ auto frontend_layout = parent_info.frontend_layout;
+
+ assert(obj.shape().rank() <= ir::Shape::MAX_RANK);
+ auto shape = obj.shape();
+ if (_operands.at(parent_index).shape().rank() >= 4 && frontend_layout == ir::Layout::NHWC &&
+ backend_layout == ir::Layout::NCHW)
+ {
+ // Permutation changing layout beyond 4-D is not supported yet
+ const auto parent_rank = _operands.at(parent_index).shape().rank();
+ assert(parent_rank == 4);
+ shape.extendRank(parent_rank);
+ offset = {offset[0], offset[3], offset[1], offset[2]};
+ }
+ else if (_operands.at(parent_index).shape().rank() >= 4 &&
+ frontend_layout == ir::Layout::NHWC && backend_layout == ir::Layout::NCHW)
+ {
+ // Permutation changing layout beyond 4-D is not supported yet
+ const auto parent_rank = _operands.at(parent_index).shape().rank();
+ assert(parent_rank == 4);
+ shape.extendRank(parent_rank);
+ offset = {offset[0], offset[2], offset[3], offset[1]};
+ }
+ auto new_shape = permuteShape(shape, frontend_layout, backend_layout);
+ auto oi = ir::OperandInfo::createStaticInfo(new_shape, obj.typeInfo());
+ _tensor_info_map.emplace(ind, oi);
+ }
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::notifyFirstUse(const ir::OperandIndex &ind)
+{
+ _lifetime_seq.emplace_back(UsesType::FIRST, ind);
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::notifyLastUse(const ir::OperandIndex &ind)
+{
+ _lifetime_seq.emplace_back(UsesType::LAST, ind);
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::isRegistered(
+ const ir::OperandIndex &ind) const
+{
+ return _tensor_info_map.find(ind) != _tensor_info_map.end();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::prepare(void)
+{
+ buildTensors();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::allocate(void)
+{
+ // Update lifetime sequence to apply subtensor optimization
+
+ std::unordered_map<ir::OperandIndex, ir::OperandIndex> root_map;
+ std::function<ir::OperandIndex &(ir::OperandIndex)> find_root =
+ [&](ir::OperandIndex ind) -> ir::OperandIndex & {
+ ir::OperandIndex &ret = root_map[ind];
+
+ // We know the root parent value already
+ if (ret.valid())
+ return ret;
+
+ auto itr = _parent_map.find(ind);
+ if (itr == _parent_map.end())
+ {
+ // If there is no parent, let's store the value of itself
+ return ret = ind;
+ }
+ else
+ {
+ return ret = find_root(itr->second.parent);
+ }
+ };
+
+ ir::OperandIndexMap<bool> first_use_check;
+ ir::OperandIndexMap<bool> last_use_check;
+ std::map<size_t, std::pair<UsesType, ir::OperandIndex>> lifetime_map;
+ for (size_t i = 0; i < _lifetime_seq.size(); i++)
+ {
+ auto &entry = _lifetime_seq[i];
+ if (entry.first != UsesType::FIRST)
+ continue;
+ auto root_ind = find_root(entry.second);
+ if (first_use_check[root_ind])
+ continue;
+ first_use_check[root_ind] = true;
+ lifetime_map[i] = {UsesType::FIRST, root_ind};
+ }
+
+ for (int i = _lifetime_seq.size() - 1; i >= 0; i--)
+ {
+ auto &entry = _lifetime_seq[i];
+ if (entry.first != UsesType::LAST)
+ continue;
+ auto root_ind = find_root(entry.second);
+ if (last_use_check[root_ind])
+ continue;
+ last_use_check[root_ind] = true;
+ lifetime_map[i] = {UsesType::LAST, root_ind};
+ }
+
+ for (auto &entry : lifetime_map)
+ {
+ auto &use = entry.second;
+ auto use_type = use.first;
+ auto use_index = use.second;
+ assert(use_index.valid());
+ if (use_type == UsesType::FIRST)
+ _tensor_mgr->startLifetime(use_index);
+ else
+ _tensor_mgr->finishLifetime(use_index);
+ }
+
+ _tensor_mgr->allocateConsts();
+
+ // TODO Since `_parent_map` is filled for all Concat nodes even if the node this backend uses
+ // After refactoring BackendContext we can uncomment this
+ // assert(_tensor_info_map.size() ==
+ // _tensor_mgr->nonconstTensors().size() + num of constants of _tensor_info_map +
+ // _parent_map.size());
+ _tensor_mgr->allocateNonconsts();
+
+ _tensor_mgr->allocateInternalBufferManager();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::postFunctionPrepare(void)
+{
+ _tensor_mgr->tryDeallocConstants();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::buildTensors(void)
+{
+ assert(_tensor_mgr->constTensors().size() == 0);
+ assert(_tensor_mgr->nonconstTensors().size() == 0);
+
+ // Normal tensors
+ for (auto &entry : _tensor_info_map)
+ {
+ auto ind = entry.first;
+ if (_parent_map.count(ind) > 0)
+ continue;
+
+ const auto &info = entry.second;
+ const auto &backend_layout = _tensor_layout_map[ind];
+ auto tensor_info =
+ asTensorInfo(info.shape(), info.typeInfo(), ir::Layout::UNKNOWN, backend_layout, true);
+ _tensor_mgr->buildTensor(ind, tensor_info, info.shape().rank(), info.isConstant(),
+ _uses_count_map[ind]);
+ }
+
+ // Subtensors
+ assert(_tensor_mgr->nonconstSubtensors().size() == 0);
+ // TODO Iterate `_parent_map` instead, once the optimizer bug is fixed
+ // `Optimizer` iterates the entire OpSequences, so there is a bug if iterating _parent_map
+ for (auto &entry : _tensor_info_map)
+ {
+ auto ind = entry.first;
+ if (_parent_map.count(ind) == 0)
+ continue;
+
+ // To make subtensor, parent tensor must be made first
+ // For this condition, use stack
+ // 1) Push one subtensor index to stack (iterate subtensors)
+ // 2) If tensor at stack top is already made, pop and go to 4)
+ // 3) If tensor pushed at 1) is not made, check parent tensor
+ // 3-1) If parent tensor is already made, we can make child tensor
+ // Make child tensor and pop, go to 4)
+ // 3-2) If parent tensor is not made, we can't make child tensor yet
+ // Push parent tensor index to stack and return to 4)
+ // 4) If stack is empty, return to 1), else return to 2)
+ auto &subtensors = _tensor_mgr->nonconstSubtensors();
+
+ std::stack<ir::OperandIndex> stack;
+ stack.push(ind);
+
+ while (!stack.empty())
+ {
+ const auto current = stack.top();
+ const auto &tensor_info = _tensor_info_map.at(current);
+ const auto &parent_info = _parent_map.at(current);
+
+ // Already generated SubTensor
+ if (subtensors.find(current) != subtensors.end())
+ {
+ stack.pop();
+ continue;
+ }
+
+ auto parent = parent_info.parent;
+ std::shared_ptr<T_ITensor> parent_tensor = _tensor_mgr->findTensorAsParent(parent);
+ if (!parent_tensor)
+ {
+ // Cannot find allocated parent tensor: allocate parent first
+ assert(_parent_map.count(parent) > 0);
+ stack.push(parent);
+ continue;
+ }
+ assert(parent_tensor != nullptr);
+
+ // Child's type should be same with parent
+ assert(tensor_info.typeInfo().offset() ==
+ parent_tensor->info()->quantization_info().uniform().offset);
+ assert(tensor_info.typeInfo().scale() ==
+ parent_tensor->info()->quantization_info().uniform().scale);
+ assert(tensor_info.typeInfo().type() == parent_tensor->data_type());
+
+ // NOTE SubTensor's layout must be the same with layout of parent tensor
+ const auto &root_parent = findRootParent(parent);
+ const auto &backend_layout = _tensor_layout_map[root_parent];
+
+ auto shape = asTensorShape(tensor_info.shape(), ir::Layout::UNKNOWN, backend_layout, true);
+ ::arm_compute::Coordinates coordinates =
+ asTensorCoordinate(parent_info.coordinates, ir::Layout::UNKNOWN, backend_layout);
+ _tensor_mgr->buildSubtensor(parent, current, shape, coordinates, tensor_info.shape().rank(),
+ true);
+ stack.pop();
+ }
+ }
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::areSubTensorsOf(
+ const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq)
+{
+ for (auto &cand : seq)
+ {
+ if (!isSubTensorOf(parent, cand))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::isSubTensorOf(
+ const ir::OperandIndex &parent, const ir::OperandIndex &child)
+{
+ auto itr = _parent_map.find(child);
+ if (itr == _parent_map.end())
+ {
+ return false;
+ }
+
+ return itr->second.parent == parent;
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+ir::OperandIndex
+AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::findRootParent(ir::OperandIndex ind)
+{
+ if (_parent_map.find(ind) == _parent_map.end())
+ return ind;
+
+ auto parent_ind = _parent_map.at(ind).parent;
+ return findRootParent(parent_ind);
+}
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__
diff --git a/runtime/onert/backend/acl_common/AclTensorManager.h b/runtime/onert/backend/acl_common/AclTensorManager.h
new file mode 100644
index 000000000..d0a56c762
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclTensorManager.h
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_TENSOR_MANAGER_H__
+#define __ONERT_BACKEND_ACL_COMMON_TENSOR_MANAGER_H__
+
+#include <arm_compute/runtime/IMemoryManager.h>
+
+#include "backend/ITensorManager.h"
+#include "AclMemoryManager.h"
+#include "AclInternalBufferManager.h"
+#include "ir/OperandIndexMap.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+class AclTensorManager : public backend::ITensorManager
+{
+public:
+ using T_AclMemoryManager = AclMemoryManager<T_ITensor, T_Tensor, T_SubTensor>;
+
+ AclTensorManager(T_AclMemoryManager *const_mgr, T_AclMemoryManager *nonconst_mgr,
+ IInternalBufferManager *inter_mgr);
+
+ virtual ~AclTensorManager() = default;
+
+ void allocateConsts(void);
+ void allocateNonconsts(void);
+ void deallocateConsts(void);
+ void deallocateNonconsts(void);
+
+ void allocateInternalBufferManager(void);
+ void deallocateInternalBufferManager(void);
+
+ void buildTensor(const ir::OperandIndex &ind, const ::arm_compute::TensorInfo &info, size_t rank,
+ bool as_const, size_t num_uses);
+ void buildSubtensor(const ir::OperandIndex &parent, const ir::OperandIndex &child,
+ const ::arm_compute::TensorShape &shape,
+ const ::arm_compute::Coordinates &coordinates, size_t rank,
+ bool extent_parent);
+
+ std::shared_ptr<T_ITensor> findTensorAsParent(const ir::OperandIndex &ind);
+
+ void startLifetime(const ir::OperandIndex &ind);
+ void finishLifetime(const ir::OperandIndex &ind);
+
+ std::shared_ptr<T_ITensor> at(const ir::OperandIndex &ind);
+
+ ir::OperandIndexMap<std::shared_ptr<T_Tensor>> &constTensors(void);
+ ir::OperandIndexMap<std::shared_ptr<T_Tensor>> &nonconstTensors(void);
+ ir::OperandIndexMap<std::shared_ptr<T_SubTensor>> &nonconstSubtensors(void);
+
+ std::shared_ptr<::arm_compute::IMemoryManager> internal_buffer_manager(void);
+
+ void iterate(const std::function<void(const ir::OperandIndex &)> &fn);
+
+ void tryDeallocConstants(void);
+
+private:
+ std::unique_ptr<T_AclMemoryManager> _const_mgr;
+ std::unique_ptr<T_AclMemoryManager> _nonconst_mgr;
+ std::unique_ptr<IInternalBufferManager> _inter_mgr;
+ ir::OperandIndexMap<T_AclMemoryManager &> _ind_to_mgr;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#include <cassert>
+#include "util/logging.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::AclTensorManager(
+ T_AclMemoryManager *const_mgr, T_AclMemoryManager *nonconst_mgr,
+ IInternalBufferManager *inter_mgr)
+ : _const_mgr{const_mgr}, _nonconst_mgr{nonconst_mgr}, _inter_mgr{inter_mgr}
+{
+ // DO NOTHING
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::allocateConsts(void)
+{
+ _const_mgr->allocate();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::allocateNonconsts(void)
+{
+ _nonconst_mgr->allocate();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::deallocateConsts(void)
+{
+ _const_mgr->deallocate();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::deallocateNonconsts(void)
+{
+ _nonconst_mgr->deallocate();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::allocateInternalBufferManager(void)
+{
+ _inter_mgr->allocate();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::deallocateInternalBufferManager(void)
+{
+ _inter_mgr->deallocate();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::buildTensor(
+ const ir::OperandIndex &ind, const ::arm_compute::TensorInfo &info, size_t rank, bool as_const,
+ size_t num_uses)
+{
+ assert(_ind_to_mgr.find(ind) == _ind_to_mgr.end());
+ if (as_const)
+ {
+ _const_mgr->buildTensor(ind, info, rank, num_uses);
+ _ind_to_mgr.insert({ind, *_const_mgr});
+ }
+ else
+ {
+ _nonconst_mgr->buildTensor(ind, info, rank, num_uses);
+ _ind_to_mgr.insert({ind, *_nonconst_mgr});
+ }
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::buildSubtensor(
+ const ir::OperandIndex &parent, const ir::OperandIndex &child,
+ const ::arm_compute::TensorShape &shape, const ::arm_compute::Coordinates &coordinates,
+ size_t rank, bool extent_parent)
+{
+ assert(_ind_to_mgr.find(child) == _ind_to_mgr.end());
+ std::shared_ptr<T_ITensor> parent_tensor = findTensorAsParent(parent);
+ assert(parent_tensor);
+ _nonconst_mgr->buildSubtensor(parent_tensor, child, shape, coordinates, rank, extent_parent);
+ _ind_to_mgr.insert({child, *_nonconst_mgr});
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+std::shared_ptr<T_ITensor>
+AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::findTensorAsParent(const ir::OperandIndex &ind)
+{
+
+ auto &tensors = _nonconst_mgr->tensors();
+ auto &subtensors = _nonconst_mgr->subtensors();
+ if (tensors.find(ind) != tensors.end())
+ {
+ // Parent is allocated as tensor
+ return tensors[ind];
+ }
+ else if (subtensors.find(ind) != subtensors.end())
+ {
+ // Parent is allocated as subtensor
+ return subtensors[ind];
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::startLifetime(const ir::OperandIndex &ind)
+{
+ assert(_ind_to_mgr.find(ind) != _ind_to_mgr.end());
+ _ind_to_mgr.at(ind).startLifetime(ind);
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::finishLifetime(const ir::OperandIndex &ind)
+{
+ assert(_ind_to_mgr.find(ind) != _ind_to_mgr.end());
+ _ind_to_mgr.at(ind).finishLifetime(ind);
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+std::shared_ptr<T_ITensor>
+AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::at(const ir::OperandIndex &ind)
+{
+ if (_ind_to_mgr.find(ind) == _ind_to_mgr.end())
+ return nullptr;
+
+ auto &tensors = _ind_to_mgr.at(ind).tensors();
+ if (tensors.find(ind) != tensors.end())
+ {
+ return tensors.at(ind);
+ }
+ else
+ {
+ auto subtensors = _ind_to_mgr.at(ind).subtensors();
+ auto itr = subtensors.find(ind);
+ if (itr == subtensors.end())
+ return nullptr;
+ else
+ return itr->second;
+ }
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+ir::OperandIndexMap<std::shared_ptr<T_Tensor>> &
+AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::constTensors(void)
+{
+ return _const_mgr->tensors();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+ir::OperandIndexMap<std::shared_ptr<T_Tensor>> &
+AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::nonconstTensors(void)
+{
+ return _nonconst_mgr->tensors();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+ir::OperandIndexMap<std::shared_ptr<T_SubTensor>> &
+AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::nonconstSubtensors(void)
+{
+ return _nonconst_mgr->subtensors();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+std::shared_ptr<::arm_compute::IMemoryManager>
+AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::internal_buffer_manager(void)
+{
+ return _inter_mgr->internal_buffer_manager();
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::iterate(
+ const std::function<void(const ir::OperandIndex &)> &fn)
+{
+ for (auto it : _nonconst_mgr->tensors())
+ fn(it.first);
+
+ for (auto it : _nonconst_mgr->subtensors())
+ fn(it.first);
+
+ for (auto it : _const_mgr->tensors())
+ fn(it.first);
+}
+
+template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
+void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>::tryDeallocConstants(void)
+{
+ auto &tensors = _const_mgr->tensors();
+
+ for (auto it = tensors.begin(); it != tensors.end();)
+ {
+ const auto &ind = it->first;
+ auto tensor = it->second;
+ // NOTE The condition "tensor->num_uses() < 2" is used to prevent deallocating a constant tensor
+ // used in several nodes.
+ if (tensor->handle() && !tensor->handle()->is_used() && tensor->num_uses() < 2)
+ {
+ VERBOSE(AclTensorManager) << "Tensor #" << ind.value()
+ << " will be deallocated as an unused constant tensor" << std::endl;
+ tensor->allocator()->free();
+ tensor.reset();
+ it = tensors.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_TENSOR_MANAGER_H__
diff --git a/runtime/onert/backend/acl_common/AclTensorRegistry.h b/runtime/onert/backend/acl_common/AclTensorRegistry.h
new file mode 100644
index 000000000..02d66db99
--- /dev/null
+++ b/runtime/onert/backend/acl_common/AclTensorRegistry.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_ACL_TENSOR_REGISTRY_H__
+#define __ONERT_BACKEND_ACL_COMMON_ACL_TENSOR_REGISTRY_H__
+
+#include "backend/ITensorRegistry.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+/**
+ * @brief Tensor registry class for acl backends
+ *
+ * This is implemented as a wrapper of AclTensorManager.
+ */
+template <typename T_AclTensorManager> class AclTensorRegistry : public ITensorRegistry
+{
+public:
+ AclTensorRegistry(T_AclTensorManager *tensor_mgr) : _tensor_mgr{tensor_mgr} {}
+
+ ITensor *getITensor(const ir::OperandIndex &ind) override { return _tensor_mgr->at(ind).get(); }
+
+ ITensor *getNativeITensor(const ir::OperandIndex &ind) override { return getITensor(ind); }
+
+ auto getAclTensor(const ir::OperandIndex &ind) { return _tensor_mgr->at(ind).get(); }
+
+private:
+ T_AclTensorManager *_tensor_mgr;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_ACL_TENSOR_REGISTRY_H__
diff --git a/runtime/onert/backend/acl_common/CMakeLists.txt b/runtime/onert/backend/acl_common/CMakeLists.txt
new file mode 100644
index 000000000..d3ae5acf7
--- /dev/null
+++ b/runtime/onert/backend/acl_common/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Unsupported architecture
+nnfw_find_package(ARMCompute QUIET)
+if(NOT ARMCompute_FOUND)
+ return()
+endif(NOT ARMCompute_FOUND)
+
+file(GLOB SOURCES "*.cc")
+
+add_library(${LIB_ONERT_BACKEND_ACL_COMMON} STATIC ${SOURCES})
+
+target_include_directories(${LIB_ONERT_BACKEND_ACL_COMMON} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PUBLIC onert_core)
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PUBLIC arm_compute arm_compute_ex)
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PUBLIC nnfw_lib_misc)
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PRIVATE nnfw_common)
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PRIVATE nnfw_coverage)
+
+set_target_properties(${LIB_ONERT_BACKEND_ACL_COMMON} PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(${LIB_ONERT_BACKEND_ACL_COMMON} PROPERTIES OUTPUT_NAME backend_acl_common)
diff --git a/runtime/onert/backend/acl_common/Convert.cc b/runtime/onert/backend/acl_common/Convert.cc
new file mode 100644
index 000000000..67d9d7176
--- /dev/null
+++ b/runtime/onert/backend/acl_common/Convert.cc
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Convert.h"
+
+#include "Swizzle.h"
+#include "ir/DataType.h"
+#include "ir/operation/ElementwiseActivation.h"
+#include <memory>
+
+namespace
+{
+
+::arm_compute::DataLayout asDataLayout(onert::ir::Layout layout)
+{
+ switch (layout)
+ {
+ case onert::ir::Layout::NHWC:
+ return ::arm_compute::DataLayout::NHWC;
+ case onert::ir::Layout::NCHW:
+ return ::arm_compute::DataLayout::NCHW;
+ default:
+ return ::arm_compute::DataLayout::UNKNOWN;
+ }
+}
+
+} // namespace
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+::arm_compute::TensorShape asTensorShape(const ir::Shape &shape, ir::Layout frontend_layout,
+ ir::Layout backend_layout, bool apply_dim_correction)
+{
+ // If shape's rank is 0, the tensor is a scalar
+ // Sometimes, some ACL kernel can use a scalar as tensor. But ACL does not allocate buffer for
+ // tensor having rank as 0.
+ const auto tensor_shape = shape.rank() == 0 ? ir::Shape{1} : shape;
+
+ const uint32_t rank = tensor_shape.rank();
+
+ ::arm_compute::TensorShape res{};
+
+ res.set_num_dimensions(rank);
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ // NOTE In some cases, in incorrect dimensions is required.
+ // For example, intput_size is 1 in LSTM. The input-to-input weights([num_units, input_size]) of
+ // LSTM is used as the weight of the FullyConnected.
+ // The FullyConnected's weight must be greater or equal than 2-dimensions.
+ // However, if the dimension correction is applied to input_to_input_weights with input_size
+ // equal to 1, it will be changed to 1-D.
+ // So input_to_input_weights is not used by the weight of FullyConnected.
+ res.set(ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value(),
+ tensor_shape.dim(axis), apply_dim_correction);
+ }
+
+ return res;
+}
+
+::arm_compute::Coordinates asTensorCoordinate(const ir::Coordinates &coord,
+ ir::Layout frontend_layout, ir::Layout backend_layout)
+{
+ const uint32_t rank = coord.size();
+
+ ::arm_compute::Coordinates res{};
+
+ res.set_num_dimensions(rank);
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ res.set(ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value(), coord[axis]);
+ }
+
+ return res;
+}
+
+::arm_compute::DataType asDataType(const ir::DataType type)
+{
+ switch (type)
+ {
+ case ir::DataType::FLOAT32:
+ return ::arm_compute::DataType::F32;
+ case ir::DataType::INT32:
+ return ::arm_compute::DataType::S32;
+ case ir::DataType::UINT32:
+ return ::arm_compute::DataType::U32;
+ case ir::DataType::QUANT_UINT8_ASYMM:
+ return ::arm_compute::DataType::QASYMM8;
+ case ir::DataType::BOOL8:
+ case ir::DataType::UINT8:
+ return ::arm_compute::DataType::U8;
+ case ir::DataType::QUANT_INT8_SYMM:
+ return ::arm_compute::DataType::S8;
+ case ir::DataType::FLOAT16:
+ return ::arm_compute::DataType::F16;
+ case ir::DataType::INT64:
+ return ::arm_compute::DataType::S64;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+::arm_compute::QuantizationInfo asQuantizationInfo(const float scale, const int32_t offset)
+{
+ return ::arm_compute::QuantizationInfo(scale, offset);
+}
+
+::arm_compute::TensorInfo asTensorInfo(const ir::Shape &shape, const ir::TypeInfo &typeInfo,
+ ir::Layout frontend_layout, ir::Layout backend_layout,
+ bool apply_dim_correction)
+{
+ ::arm_compute::TensorInfo info(
+ asTensorShape(shape, frontend_layout, backend_layout, apply_dim_correction), 1,
+ asDataType(typeInfo.type()), asQuantizationInfo(typeInfo.scale(), typeInfo.offset()));
+ info.set_data_layout(asDataLayout(backend_layout));
+ return info;
+}
+
+::arm_compute::PadStrideInfo asPadStrideInfo(const ir::ExplicitPadding &padding,
+ const ir::Stride &stride)
+{
+ return ::arm_compute::PadStrideInfo{stride.horizontal,
+ stride.vertical,
+ padding.left,
+ padding.right,
+ padding.top,
+ padding.bottom,
+ ::arm_compute::DimensionRoundingType::FLOOR};
+}
+
+::arm_compute::ActivationLayerInfo asActivationLayerInfo(const ir::Activation act_code)
+{
+ switch (act_code)
+ {
+ case ir::Activation::NONE:
+ return ::arm_compute::ActivationLayerInfo{};
+ case ir::Activation::RELU:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU};
+ case ir::Activation::RELU1:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f};
+ case ir::Activation::RELU6:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f};
+ // Cases for activation of LSTM.
+ case ir::Activation::TANH:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::TANH, 1.0f, 1.0f};
+ case ir::Activation::SIGMOID:
+ // NOTE The sigmoid function is a special case of the Logistic function when L=1, k=1, x0=0.
+ // TODO In ACL and nnapi sepc, currently, Logistic's L always is 1, k always is 1, x0 always
+ // 0(always sigmoid) regardless of values of the parameter.
+ // If ACL support non-sigmoid logistic, should fix param values.
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LOGISTIC, 0.0f, 0.0f};
+ default:
+ throw std::runtime_error{"Not supported, yet"};
+ break;
+ }
+}
+
+::arm_compute::ActivationLayerInfo
+asActivationLayerInfo(const ir::operation::ElementwiseActivation::Type op_type, float alpha,
+ float beta)
+{
+ switch (op_type)
+ {
+ case ir::operation::ElementwiseActivation::Type::RELU:
+ if (beta == 0.f)
+ {
+ if (alpha == ir::operation::ElementwiseActivation::infinity)
+ {
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU};
+ }
+ else
+ {
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, alpha};
+ }
+ }
+ else
+ {
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, alpha, beta};
+ }
+ case ir::operation::ElementwiseActivation::Type::TANH:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::TANH, alpha, beta};
+ case ir::operation::ElementwiseActivation::Type::LOGISTIC:
+ // NOTE The sigmoid function is a special case of the Logistic function when L=1, k=1, x0=0.
+ // TODO In ACL and nnapi sepc, currently, Logistic's L always is 1, k always is 1, x0 always
+ // 0(always sigmoid) regardless of values of the parameter.
+ // If ACL support non-sigmoid logistic, should fix param values.
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LOGISTIC};
+ case ir::operation::ElementwiseActivation::Type::LEAKY_RELU:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LEAKY_RELU, alpha};
+ default:
+ throw std::runtime_error{"Not supported, yet"};
+ break;
+ }
+}
+
+arm_compute::Coordinates asCoordinates(const ir::Operand &operand, int32_t rank,
+ ir::Layout frontend_layout, ir::Layout backend_layout)
+{
+ std::set<uint32_t> axes = asSet(operand, rank, frontend_layout, backend_layout);
+
+ arm_compute::Coordinates reduce_axes;
+ for (const int32_t axis : axes)
+ {
+ reduce_axes.set(reduce_axes.num_dimensions(), axis);
+ }
+
+ return reduce_axes;
+}
+
+std::set<uint32_t> asSet(const ir::Operand &operand, int32_t rank, ir::Layout frontend_layout,
+ ir::Layout backend_layout)
+{
+ std::set<std::uint32_t> axes;
+
+ for (size_t i = 0; i < operand.shape().num_elements(); ++i)
+ {
+ int32_t axis = 0;
+ switch (operand.typeInfo().type())
+ {
+ case ir::DataType::INT32:
+ axis = reinterpret_cast<const int32_t *>(operand.data()->base())[i];
+ break;
+ case ir::DataType::INT64:
+ axis = reinterpret_cast<const int64_t *>(operand.data()->base())[i];
+ break;
+ default:
+ throw std::runtime_error("acl_common::asSet: Not supported data type");
+ }
+ if (axis < 0)
+ axis += rank;
+ axes.insert(ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value());
+ }
+
+ return axes;
+}
+
+std::unique_ptr<AclFunction> asAclFunction(std::unique_ptr<::arm_compute::IFunction> &&layer)
+{
+ return std::make_unique<AclFunction>(std::move(layer));
+}
+
+ir::Layout asRuntimeLayout(::arm_compute::DataLayout data_layout)
+{
+ switch (data_layout)
+ {
+ case ::arm_compute::DataLayout::NHWC:
+ return ir::Layout::NHWC;
+ case ::arm_compute::DataLayout::NCHW:
+ return ir::Layout::NCHW;
+ default:
+ return ir::Layout::UNKNOWN;
+ }
+}
+
+ir::DataType asRuntimeDataType(::arm_compute::DataType data_type)
+{
+ switch (data_type)
+ {
+ case ::arm_compute::DataType::F32:
+ return ir::DataType::FLOAT32;
+ case ::arm_compute::DataType::S32:
+ return ir::DataType::INT32;
+ case ::arm_compute::DataType::U32:
+ return ir::DataType::UINT32;
+ case ::arm_compute::DataType::QASYMM8:
+ return ir::DataType::QUANT_UINT8_ASYMM;
+ case ::arm_compute::DataType::U8:
+ return ir::DataType::UINT8;
+ case ::arm_compute::DataType::QSYMM8:
+ return ir::DataType::QUANT_INT8_SYMM;
+ case ::arm_compute::DataType::F16:
+ return ir::DataType::FLOAT16;
+ case ::arm_compute::DataType::S64:
+ return ir::DataType::INT64;
+ default:
+ throw std::runtime_error{"Not supported, yet"};
+ break;
+ }
+}
+
+arm_compute::PoolingType convertPoolType(ir::operation::Pool2D::PoolType pool_type_ir)
+{
+ switch (pool_type_ir)
+ {
+ case ir::operation::Pool2D::PoolType::AVG:
+ return arm_compute::PoolingType::AVG;
+ case ir::operation::Pool2D::PoolType::L2:
+ return arm_compute::PoolingType::L2;
+ case ir::operation::Pool2D::PoolType::MAX:
+ return arm_compute::PoolingType::MAX;
+ default:
+ throw std::runtime_error("convertPoolType: Not supported operation yet");
+ }
+}
+
+arm_compute::ReductionOperation convertReduceType(ir::operation::Reduce::ReduceType reduce_type_ir)
+{
+ switch (reduce_type_ir)
+ {
+ case ir::operation::Reduce::ReduceType::MAX:
+ return arm_compute::ReductionOperation::MAX;
+ case ir::operation::Reduce::ReduceType::MIN:
+ return arm_compute::ReductionOperation::MIN;
+ case ir::operation::Reduce::ReduceType::SUM:
+ return arm_compute::ReductionOperation::SUM;
+ default:
+ throw std::runtime_error("convertReduceType: Not supported operation yet");
+ }
+}
+
+arm_compute::PixelValue asPixelValue(const ir::Operand &operand)
+{
+ assert(operand.isConstant());
+ assert(operand.shape().num_elements() == 1);
+ switch (operand.typeInfo().type())
+ {
+ case ir::DataType::INT32:
+ return arm_compute::PixelValue(operand.asScalar<int32_t>());
+ case ir::DataType::INT64:
+ return arm_compute::PixelValue(operand.asScalar<int64_t>());
+ case ir::DataType::UINT32:
+ return arm_compute::PixelValue(operand.asScalar<uint64_t>());
+ case ir::DataType::UINT8:
+ return arm_compute::PixelValue(operand.asScalar<uint8_t>());
+ case ir::DataType::FLOAT32:
+ return arm_compute::PixelValue(operand.asScalar<float>());
+ default:
+ throw std::runtime_error("asPixelValue : Not supported datatype yet");
+ }
+}
+
+arm_compute::Size2D asDilation(uint32_t dilation_width, uint32_t dilation_height)
+{
+ assert(dilation_width != 0);
+ assert(dilation_height != 0);
+
+ return arm_compute::Size2D(dilation_width, dilation_height);
+}
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_common/Convert.h b/runtime/onert/backend/acl_common/Convert.h
new file mode 100644
index 000000000..c98db14bb
--- /dev/null
+++ b/runtime/onert/backend/acl_common/Convert.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_CONVERT_H__
+#define __ONERT_BACKEND_ACL_COMMON_CONVERT_H__
+
+#include <arm_compute/core/PixelValue.h>
+#include <arm_compute/core/TensorInfo.h>
+#include <arm_compute/core/SubTensorInfo.h>
+#include <arm_compute/core/TensorShape.h>
+#include <arm_compute/core/TypesEx.h>
+
+#include "ir/Layout.h"
+#include "ir/InternalType.h"
+#include "ir/Operand.h"
+#include "ir/operation/Pool2D.h"
+#include "ir/operation/Reduce.h"
+#include "ir/operation/ElementwiseActivation.h"
+#include "ir/Shape.h"
+#include "ir/TypeInfo.h"
+#include "ir/Coordinates.h"
+#include "ir/Padding.h"
+#include "misc/feature/Shape.h"
+#include "misc/kernel/Shape.h"
+
+#include "AclFunction.h"
+
+#include <set>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+::arm_compute::TensorShape asTensorShape(const ir::Shape &shape, ir::Layout frontend_layout,
+ ir::Layout backend_layout,
+ bool apply_dim_correction = true);
+::arm_compute::Coordinates asTensorCoordinate(const ir::Coordinates &coord,
+ ir::Layout frontend_layout,
+ ir::Layout backend_layout);
+::arm_compute::DataType asDataType(ir::DataType type);
+::arm_compute::TensorInfo asTensorInfo(const ir::Shape &shape, const ir::TypeInfo &typeInfo,
+ ir::Layout frontend_layout, ir::Layout backend_layout,
+ bool apply_dim_correction = true);
+
+::arm_compute::PadStrideInfo asPadStrideInfo(const ir::ExplicitPadding &padding,
+ const ir::Stride &stride);
+
+::arm_compute::ActivationLayerInfo asActivationLayerInfo(ir::Activation act_code);
+::arm_compute::ActivationLayerInfo
+asActivationLayerInfo(const ir::operation::ElementwiseActivation::Type op_type, float alpha,
+ float beta);
+
+arm_compute::Coordinates asCoordinates(const ir::Operand &operand, int32_t rank,
+ ir::Layout frontend_layout, ir::Layout backend_layout);
+
+std::set<uint32_t> asSet(const ir::Operand &operand, int32_t rank, ir::Layout frontend_layout,
+ ir::Layout backend_layout);
+
+std::unique_ptr<AclFunction> asAclFunction(std::unique_ptr<::arm_compute::IFunction> &&layer);
+
+template <typename T_Function>
+std::unique_ptr<T_Function> asFunction(std::unique_ptr<::arm_compute::IFunction> &&fn)
+{
+ return std::make_unique<T_Function>(std::move(fn));
+}
+
+ir::Layout asRuntimeLayout(::arm_compute::DataLayout data_layout);
+ir::DataType asRuntimeDataType(::arm_compute::DataType data_type);
+
+arm_compute::PoolingType convertPoolType(ir::operation::Pool2D::PoolType pool_type_ir);
+arm_compute::ReductionOperation convertReduceType(ir::operation::Reduce::ReduceType reduce_type_ir);
+
+arm_compute::PixelValue asPixelValue(const ir::Operand &operand);
+arm_compute::Size2D asDilation(uint32_t dilation_width, uint32_t dilation_height);
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_CONVERT_H__
diff --git a/runtime/onert/backend/acl_common/IACLTensor.cc b/runtime/onert/backend/acl_common/IACLTensor.cc
new file mode 100644
index 000000000..70988bd11
--- /dev/null
+++ b/runtime/onert/backend/acl_common/IACLTensor.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "IACLTensor.h"
+#include "Convert.h"
+#include "Swizzle.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+size_t IACLTensor::dimension(size_t index) const
+{
+ // Assume that the front is higher dimensional.
+ // i.g. N: 0, C: 1, H: 2, W: 3 for NCHW layout
+ // NOTE This tensor must not be applied dim correction
+ auto rank = num_dimensions();
+ rank = rank == 0 ? 1 : rank;
+ assert(rank > index);
+ const ARMComputeAxis reversed{(static_cast<uint32_t>(rank - index) - 1)};
+ return info()->dimension(reversed.value());
+}
+
+size_t IACLTensor::calcOffset(const ir::Coordinates &coords) const
+{
+ auto rank = num_dimensions();
+ rank = rank == 0 ? 1 : rank;
+ assert(rank == coords.size());
+
+ ::arm_compute::Coordinates acl_coords;
+ for (uint32_t i = 0; i < rank; ++i)
+ {
+ const ARMComputeAxis reversed{static_cast<uint32_t>((rank - i) - 1)};
+ acl_coords.set(reversed.value(), coords[i]);
+ }
+
+ return info()->offset_element_in_bytes(acl_coords);
+}
+
+ir::Layout IACLTensor::layout() const { return acl_common::asRuntimeLayout(info()->data_layout()); }
+
+ir::DataType IACLTensor::data_type() const
+{
+ return acl_common::asRuntimeDataType(info()->data_type());
+}
+
+float IACLTensor::data_scale() const
+{
+ // FIXME What if quantization info is non-uniform?
+ return info()->quantization_info().uniform().scale;
+}
+
+int32_t IACLTensor::data_offset() const
+{
+ // FIXME What if quantization info is non-uniform?
+ return info()->quantization_info().uniform().offset;
+}
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_common/IACLTensor.h b/runtime/onert/backend/acl_common/IACLTensor.h
new file mode 100644
index 000000000..3d1268940
--- /dev/null
+++ b/runtime/onert/backend/acl_common/IACLTensor.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_I_ACL_TENSOR_H__
+#define __ONERT_BACKEND_ACL_COMMON_I_ACL_TENSOR_H__
+
+#include <backend/ITensor.h>
+#include <arm_compute/core/ITensor.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+/**
+ * @brief Class representing Tensor for ACL
+ * @todo Override is_dynamic() method. We don't support dynamic tensor for ACL yet as of Apr, 2020.
+ * FYI, ACL ITensorInfo has is_dynamic() method, which seems currently not used.
+ * Maybe for ACL, this method can be implemented using ITensorInfo::is_dynamic() in future.
+ */
+class IACLTensor : public ITensor
+{
+public:
+ IACLTensor() = default;
+ IACLTensor(const IACLTensor &) = delete;
+ IACLTensor &operator=(const IACLTensor &) = delete;
+ IACLTensor(IACLTensor &&) = default;
+ IACLTensor &operator=(IACLTensor &&) = default;
+
+public:
+ uint8_t *buffer() const final { return handle()->buffer(); }
+ size_t total_size() const final { return info()->total_size(); }
+ size_t dimension(size_t index) const final;
+ size_t calcOffset(const ir::Coordinates &coords) const final;
+ ir::Layout layout() const final;
+ ir::DataType data_type() const final;
+ float data_scale() const override;
+ int32_t data_offset() const override;
+ bool has_padding() const override { return info()->has_padding(); }
+ bool is_dynamic() const override { return false; }
+
+public:
+ virtual const arm_compute::ITensor *handle() const = 0;
+ virtual arm_compute::ITensor *handle() = 0;
+
+ const arm_compute::ITensorInfo *info() const { return handle()->info(); }
+ arm_compute::ITensorInfo *info() { return handle()->info(); }
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif //__ONERT_BACKEND_ACL_COMMON_I_ACL_TENSOR_H__
diff --git a/runtime/onert/backend/acl_common/ParentInfo.h b/runtime/onert/backend/acl_common/ParentInfo.h
new file mode 100644
index 000000000..708436327
--- /dev/null
+++ b/runtime/onert/backend/acl_common/ParentInfo.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_PARENT_INFO_H__
+#define __ONERT_BACKEND_ACL_COMMON_PARENT_INFO_H__
+
+#include <ir/Index.h>
+#include <ir/Coordinates.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+/**
+ * @brief Struct to represent parent operand in child operand
+ */
+struct ParentInfo
+{
+ ir::OperandIndex parent;
+ ir::Layout frontend_layout;
+ ir::Coordinates coordinates;
+};
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_PARENT_INFO_H__
diff --git a/runtime/onert/backend/acl_common/Swizzle.h b/runtime/onert/backend/acl_common/Swizzle.h
new file mode 100644
index 000000000..e1c7f8041
--- /dev/null
+++ b/runtime/onert/backend/acl_common/Swizzle.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_COMMON_SWIZZLE_H__
+#define __ONERT_BACKEND_ACL_COMMON_SWIZZLE_H__
+
+#include <cassert>
+#include <ir/Layout.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_common
+{
+
+class ARMComputeAxis
+{
+public:
+ ARMComputeAxis() = default;
+
+public:
+ explicit ARMComputeAxis(uint32_t value) : _value{value}
+ {
+ // DO NOTHING
+ }
+
+public:
+ uint32_t value(void) const { return _value; }
+
+private:
+ uint32_t _value;
+};
+
+// Convert axis in acl order
+inline ARMComputeAxis ToARMComputeAxis(uint32_t rank, uint32_t axis,
+ const ir::Layout org_layout = ir::Layout::UNKNOWN,
+ const ir::Layout acl_layout = ir::Layout::UNKNOWN)
+{
+ assert(rank > axis);
+
+ const ARMComputeAxis reversed{(rank - axis) - 1};
+
+ if (rank >= 4 && org_layout == ir::Layout::NHWC && acl_layout == ir::Layout::NCHW)
+ {
+ // NHWC -> WHCN
+ // DEPTH
+ if (0 == reversed.value())
+ {
+ return ARMComputeAxis{2};
+ }
+ // WIDTH
+ if (1 == reversed.value())
+ {
+ return ARMComputeAxis{0};
+ }
+ // HEIGHT
+ if (2 == reversed.value())
+ {
+ return ARMComputeAxis{1};
+ }
+ }
+ if (rank >= 4 && org_layout == ir::Layout::NCHW && acl_layout == ir::Layout::NHWC)
+ {
+ // NCHW -> CWHN
+ // WIDTH
+ if (0 == reversed.value())
+ {
+ return ARMComputeAxis{1};
+ }
+ // HEIGHT
+ if (1 == reversed.value())
+ {
+ return ARMComputeAxis{2};
+ }
+ // DEPTH
+ if (2 == reversed.value())
+ {
+ return ARMComputeAxis{0};
+ }
+ }
+
+ return reversed;
+}
+
+inline ::arm_compute::Coordinates
+getARMComputeAxises(uint32_t rank, const ir::Layout org_layout = ir::Layout::UNKNOWN,
+ const ir::Layout acl_layout = ir::Layout::UNKNOWN)
+{
+ ::arm_compute::Coordinates res{};
+
+ res.set_num_dimensions(rank);
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ res.set(axis, ToARMComputeAxis(rank, axis, org_layout, acl_layout).value());
+ }
+
+ return res;
+}
+
+// Restructure runtime_permutationVector to ACL_permutationVector
+inline ::arm_compute::PermutationVector
+getARMComputePermutationVector(uint32_t rank, const std::vector<int32_t> runtime_pv,
+ const ir::Layout org_layout = ir::Layout::UNKNOWN,
+ const ir::Layout acl_layout = ir::Layout::UNKNOWN)
+{
+ // rank upto 4 is supported
+ assert(rank <= 4);
+ assert(runtime_pv.size() > 0);
+
+ int new_pv[4] = {0};
+ ::arm_compute::Coordinates axises = getARMComputeAxises(rank, org_layout, acl_layout);
+
+ for (uint32_t i = 0; i < rank; ++i)
+ {
+ new_pv[axises[i]] = ToARMComputeAxis(rank, runtime_pv[i], org_layout, acl_layout).value();
+ }
+
+ ::arm_compute::PermutationVector ACL_PV =
+ ::arm_compute::PermutationVector{new_pv[0], new_pv[1], new_pv[2], new_pv[3]};
+ ACL_PV.set_num_dimensions(rank);
+
+ return ACL_PV;
+}
+
+template <typename T>
+inline T ReorderBits(T in, size_t numOfBits, const ir::Layout org_layout = ir::Layout::UNKNOWN,
+ const ir::Layout acl_layout = ir::Layout::UNKNOWN)
+{
+ assert(numOfBits > 0);
+ T out = 0;
+ for (int32_t i = numOfBits - 1; i >= 0; --i)
+ {
+ const uint32_t toShift =
+ numOfBits - ToARMComputeAxis(numOfBits, i, org_layout, acl_layout).value() - 1;
+ out += ((in & 1) << toShift);
+ in >>= 1;
+ }
+ return out;
+}
+
+} // namespace acl_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_COMMON_SWIZZLE_H__
diff --git a/runtime/onert/backend/acl_neon/Backend.h b/runtime/onert/backend/acl_neon/Backend.h
new file mode 100644
index 000000000..35d6e4e8e
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/Backend.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_BACKEND_H__
+#define __ONERT_BACKEND_ACL_NEON_BACKEND_H__
+
+#include <memory>
+#include <backend/Backend.h>
+#include <ir/Operands.h>
+
+#include "Config.h"
+#include "ConstantInitializer.h"
+#include "KernelGenerator.h"
+#include "TensorManager.h"
+#include "Optimizer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+class Backend : public ::onert::backend::Backend
+{
+public:
+ Backend() : _config{std::make_shared<Config>()} {}
+
+ std::shared_ptr<IConfig> config() const override { return _config; }
+
+ std::unique_ptr<BackendContext> newContext(const ir::Graph &graph,
+ const std::shared_ptr<custom::IKernelBuilder> &,
+ bool is_linear_executor) const override
+ {
+ const auto &operands = graph.operands();
+ const auto &operations = graph.operations();
+ auto context = std::make_unique<BackendContext>(this, &graph);
+ auto tm = createTensorManager(is_linear_executor);
+ auto tr = std::make_shared<acl_common::AclTensorRegistry<TensorManager>>(tm);
+ auto tb = std::make_shared<TensorBuilder>(operands, tm, tr);
+ context->tensor_registry = tr;
+ context->tensor_builder = tb;
+ context->constant_initializer = std::make_shared<ConstantInitializer>(operands, tr);
+ context->kernel_gen = std::make_shared<KernelGenerator>(operands, operations, tb, tr);
+ context->tensor_register = nullptr;
+ context->optimizer = std::make_shared<Optimizer>(context.get());
+ return context;
+ }
+
+private:
+ std::shared_ptr<IConfig> _config;
+};
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_BACKEND_H__
diff --git a/runtime/onert/backend/acl_neon/CMakeLists.txt b/runtime/onert/backend/acl_neon/CMakeLists.txt
new file mode 100644
index 000000000..a37256c7c
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Unsupported architecture
+nnfw_find_package(ARMCompute QUIET)
+if(NOT ARMCompute_FOUND)
+ return()
+endif(NOT ARMCompute_FOUND)
+
+set(LIB_ONERT_BACKEND_ACL_NEON onert_backend_acl_neon)
+
+file(GLOB_RECURSE SOURCES "*.cc")
+
+add_library(${LIB_ONERT_BACKEND_ACL_NEON} SHARED ${SOURCES})
+
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_NEON} PRIVATE ${LIB_ONERT_BACKEND_ACL_COMMON})
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_NEON} PRIVATE nnfw_common)
+target_link_libraries(${LIB_ONERT_BACKEND_ACL_NEON} PRIVATE nnfw_coverage)
+
+set_target_properties(${LIB_ONERT_BACKEND_ACL_NEON} PROPERTIES OUTPUT_NAME backend_acl_neon)
+
+if(CMAKE_BUILD_TYPE_LC STREQUAL "release")
+ add_custom_command(TARGET onert_backend_acl_neon POST_BUILD
+ COMMAND ${CMAKE_STRIP} "--strip-unneeded" $<TARGET_FILE_NAME:onert_backend_acl_neon>)
+endif()
+
+install(TARGETS ${LIB_ONERT_BACKEND_ACL_NEON} DESTINATION lib)
diff --git a/runtime/onert/backend/acl_neon/Config.cc b/runtime/onert/backend/acl_neon/Config.cc
new file mode 100644
index 000000000..4e78efd2d
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/Config.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Config.h"
+
+#include <util/ConfigSource.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+bool Config::initialize() { return true; }
+
+ir::Layout Config::supportLayout(const ir::Operation &, ir::Layout frontend_layout)
+{
+ const std::string acl_layout_str = util::getConfigString(util::config::ACL_LAYOUT);
+ if (acl_layout_str == "NHWC")
+ {
+ return ir::Layout::NHWC;
+ }
+ else if (acl_layout_str == "NCHW")
+ {
+ return ir::Layout::NCHW;
+ }
+
+ return frontend_layout;
+}
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_neon/Config.h b/runtime/onert/backend/acl_neon/Config.h
new file mode 100644
index 000000000..089d9479a
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/Config.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_CONFIG_H__
+#define __ONERT_BACKEND_ACL_NEON_CONFIG_H__
+
+#include <backend/IConfig.h>
+#include <memory>
+#include <util/ITimer.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+class Config : public IConfig
+{
+public:
+ std::string id() override { return "acl_neon"; }
+ bool initialize() override;
+ ir::Layout supportLayout(const ir::Operation &node, ir::Layout frontend_layout) override;
+ bool supportPermutation() override { return true; }
+ bool supportDynamicTensor() override { return false; }
+ bool supportFP16() override { return false; }
+
+ std::unique_ptr<util::ITimer> timer() override { return std::make_unique<util::CPUTimer>(); }
+};
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_CONFIG_H__
diff --git a/runtime/onert/backend/acl_neon/ConstantInitializer.cc b/runtime/onert/backend/acl_neon/ConstantInitializer.cc
new file mode 100644
index 000000000..79edb9ded
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/ConstantInitializer.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConstantInitializer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+ConstantInitializer::ConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg)
+ : acl_common::AclConstantInitializer{operands, tensor_reg}
+{
+ // DO NOTHING
+}
+
+void ConstantInitializer::visit(const ir::operation::SpaceToBatchND &node)
+{
+ const auto &block_size_index = node.getInputs().at(ir::operation::SpaceToBatchND::BLOCK_SIZE);
+ const auto &block_size_obj = _operands.at(block_size_index);
+
+ if (block_size_obj.isConstant())
+ {
+ _init_map[block_size_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) {
+ assert(model_obj.data());
+ const auto &shape = model_obj.shape();
+ const auto base = reinterpret_cast<const int32_t *>(model_obj.data()->base());
+ assert(model_obj.shape().rank() == 1);
+ obj.access([&](ITensor &tensor) {
+ for (size_t i = 0; i < shape.num_elements(); ++i)
+ {
+ const int32_t value = base[shape.num_elements() - i - 1];
+ int32_t *into = reinterpret_cast<int32_t *>(tensor.buffer() +
+ tensor.calcOffset({static_cast<int32_t>(i)}));
+ *into = value;
+ }
+ });
+ };
+ }
+
+ const auto &paddings_index = node.getInputs().at(ir::operation::SpaceToBatchND::PADDINGS);
+ const auto &paddings_obj = _operands.at(paddings_index);
+ if (paddings_obj.isConstant())
+ {
+ _init_map[paddings_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) {
+ assert(model_obj.data());
+ const auto &shape = model_obj.shape();
+ const auto base = reinterpret_cast<const int32_t *>(model_obj.data()->base());
+ assert(model_obj.shape().rank() == 2);
+ assert(shape.dim(0) == 2);
+ assert(shape.dim(1) == 2);
+ obj.access([&](ITensor &tensor) {
+ for (auto i = 0; i < shape.dim(0); ++i)
+ {
+ for (auto j = 0; j < shape.dim(1); ++j)
+ {
+ const int32_t value = base[i * 2 + j];
+ int32_t *into = reinterpret_cast<int32_t *>(
+ // The coordinates of NETensor are different from the coordiantes of CLTensor in
+ // this operand.
+ // NEON : {j, reversed i}
+ // CL : {reversed i, j}
+ tensor.buffer() + tensor.calcOffset({j, shape.dim(0) - i - 1}));
+ *into = value;
+ }
+ }
+ });
+ };
+ }
+}
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_neon/ConstantInitializer.h b/runtime/onert/backend/acl_neon/ConstantInitializer.h
new file mode 100644
index 000000000..c7d71cdcf
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/ConstantInitializer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_ACL_NEON_CONSTANT_INITIALIZER_H__
+#define __ONERT_COMPILER_ACL_NEON_CONSTANT_INITIALIZER_H__
+
+#include "AclConstantInitializer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+class ConstantInitializer : public acl_common::AclConstantInitializer
+{
+public:
+ ConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg);
+
+public:
+ using acl_common::AclConstantInitializer::visit;
+ void visit(const ir::operation::SpaceToBatchND &node) final;
+};
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_COMPILER_ACL_NEON_CONSTANT_INITIALIZER_H__
diff --git a/runtime/onert/backend/acl_neon/KernelGenerator.cc b/runtime/onert/backend/acl_neon/KernelGenerator.cc
new file mode 100644
index 000000000..ffaee3b3e
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/KernelGenerator.cc
@@ -0,0 +1,1429 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KernelGenerator.h"
+
+#include <arm_compute/runtime/NEON/NEFunctions.h> // Include all ARM Compute NEON functions
+#include <arm_compute/runtime/NEON/NEFunctionsEx.h> // Include all ARM Compute EX NEON functions
+
+#include <AclActivationBuilder.h>
+#include <AclFunction.h>
+#include <Convert.h>
+#include <Swizzle.h>
+
+#include "ir/Index.h"
+#include "ir/DataType.h"
+#include "ir/InternalType.h"
+#include "exec/NopFunction.h"
+#include "util/logging.h"
+#include "util/Utils.h"
+#include "AclKernelGen.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+using ::onert::backend::acl_common::asAclFunction;
+using ActivationBuilder = ::onert::backend::acl_common::AclActivationBuilder<
+ ::arm_compute::ITensor, ::arm_compute::NEActivationLayer, acl_common::AclFunction>;
+
+KernelGenerator::KernelGenerator(
+ const ir::Operands &operands_ctx, const ir::Operations &operations_ctx,
+ const std::shared_ptr<TensorBuilder> &tensor_builder,
+ const std::shared_ptr<acl_common::AclTensorRegistry<TensorManager>> &tensor_reg)
+ : _ctx(operands_ctx), _operations_ctx(operations_ctx), _tensor_builder(tensor_builder),
+ _tensor_reg(tensor_reg), _current_op_seq_layout(ir::Layout::UNKNOWN)
+{
+ // DO NOTHING
+}
+
+void KernelGenerator::visit(const ir::OpSequence &op_seq)
+{
+ // TODO Move this to IKernelGenerator
+ // (all derivatives have the same implementation for this)
+ assert(!_return_fn_seq);
+ _return_fn_seq = std::make_unique<exec::FunctionSequence>();
+ _return_fn_seq->enableDynamicShapeInferer(false);
+
+ _current_op_seq_layout = op_seq.getLayout();
+ for (const auto &operation_idx : op_seq.operations())
+ {
+ const auto &node = _operations_ctx.at(operation_idx);
+ node.accept(*this);
+ _return_fn_seq->append(releaseFunction());
+ }
+}
+
+void KernelGenerator::visit(const ir::operation::ArgMax &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ArgMax::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::ArgMax::Input::AXIS)};
+
+ const auto ifm_rank = _ctx.at(ifm_index).shape().rank();
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto frontend_layout = _current_op_seq_layout;
+ auto backend_layout = ifm_tensor->layout();
+
+ int axis_value = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis_value < 0)
+ {
+ axis_value += ifm_rank;
+ }
+ assert(axis_value >= 0 && axis_value < ifm_rank);
+ const auto fixed_axis =
+ acl_common::ToARMComputeAxis(ifm_rank, axis_value, frontend_layout, backend_layout).value();
+
+ auto fn = acl_common::generateLayer<arm_compute::NEArgMinMaxLayer>(
+ ifm_tensor->handle(), fixed_axis, ofm_tensor->handle(),
+ arm_compute::ReductionOperation::ARG_IDX_MAX);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::BatchToSpaceND &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)};
+ const auto block_size_index{
+ node.getInputs().at(ir::operation::BatchToSpaceND::Input::BLOCK_SIZE)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto block_size_tensor = _tensor_reg->getAclTensor(block_size_index);
+
+ assert(_ctx.at(block_size_index).data());
+
+ auto fn = acl_common::generateLayer<arm_compute::NEBatchToSpaceLayer>(
+ ifm_tensor->handle(), block_size_tensor->handle(), ofm_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::BinaryArithmetic &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::BinaryArithmetic::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::BinaryArithmetic::Input::RHS)};
+
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto lhs_tensor = _tensor_reg->getAclTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getAclTensor(rhs_index);
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ switch (node.param().arithmetic_type)
+ {
+ case ir::operation::BinaryArithmetic::ArithmeticType::ADD:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEArithmeticAddition>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle(),
+ arm_compute::ConvertPolicy::SATURATE);
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::SUB:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEArithmeticSubtraction>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle(),
+ arm_compute::ConvertPolicy::SATURATE);
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::MUL:
+ {
+ // RoundingPolicy for scale:1.0 is only allowed RoundingPolicy::TO_ZERO
+ fn = acl_common::generateLayer<arm_compute::NEPixelWiseMultiplication>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle(), 1.0, // scale
+ arm_compute::ConvertPolicy::SATURATE, arm_compute::RoundingPolicy::TO_ZERO);
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::DIV:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEElementwiseDivision>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle());
+ break;
+ }
+ default:
+ assert(false && "The BinaryArithmetic operation supports only binary arithmetic operations");
+ break;
+ }
+ _return_fn = std::make_unique<exec::FunctionSequence>(
+ asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_tensor->handle()));
+}
+
+void KernelGenerator::visit(const ir::operation::Conv2D &node)
+{
+ using ir::operation::Conv2D;
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)};
+ const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
+ const auto &ker_shape = _ctx.at(ker_index).shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+
+ const auto stride = node.param().stride;
+ const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride,
+ ker_width, ker_height);
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto ker_tensor = _tensor_reg->getAclTensor(ker_index);
+ auto bias_tensor = _tensor_reg->getAclTensor(bias_index);
+
+ const auto conv_info = acl_common::asPadStrideInfo(padding, stride);
+ const auto act_info = acl_common::asActivationLayerInfo(activation);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEConvolutionLayer>(
+ _tensor_builder->acl_tensor_manager()->internal_buffer_manager(), ifm_tensor->handle(),
+ ker_tensor->handle(), bias_tensor->handle(), ofm_tensor->handle(), conv_info,
+ ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), act_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::DepthToSpace &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::DepthToSpace::Input::INPUT)};
+
+ auto block_size = node.param().block_size;
+ assert(block_size > 0);
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEDepthToSpaceLayer>(
+ input_tensor->handle(), output_tensor->handle(), block_size);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::DepthwiseConv2D &node)
+{
+ using ir::operation::DepthwiseConv2D;
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(DepthwiseConv2D::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)};
+ const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)};
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ // Kernel format is [1, kernel_height, kernel_width, depth_out].
+ const auto &ker_shape = _ctx.at(ker_index).shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+
+ const auto stride = node.param().stride;
+ const auto dilation = node.param().dilation;
+ const auto padding =
+ ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, ker_width,
+ ker_height, dilation.width_factor, dilation.height_factor);
+ const auto multiplier = node.param().multiplier;
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto ker_tensor = _tensor_reg->getAclTensor(ker_index);
+ auto bias_tensor = _tensor_reg->getAclTensor(bias_index);
+
+ const auto conv_info = acl_common::asPadStrideInfo(padding, stride);
+ const auto act_info = acl_common::asActivationLayerInfo(activation);
+ const auto dilation_info = acl_common::asDilation(dilation.width_factor, dilation.height_factor);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEDepthwiseConvolutionLayer>(
+ ifm_tensor->handle(), ker_tensor->handle(), bias_tensor->handle(), ofm_tensor->handle(),
+ conv_info, multiplier, act_info, dilation_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Concat &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ std::vector<ir::OperandIndex> input_indexes;
+ for (const auto &input : node.getInputs())
+ input_indexes.emplace_back(input);
+
+ const auto axis = node.param().axis;
+
+ // Concat elimination check
+ bool eliminated = _tensor_builder->areSubTensorsOf(ofm_index, node.getInputs());
+ if (eliminated)
+ {
+ // If concat eliminated, return a NOP IFunction
+ VERBOSE(acl_neon_KernelGenerator_Concat) << "Concat eliminated" << std::endl;
+ _return_fn = std::make_unique<exec::NopFunction>();
+ return;
+ }
+
+ auto output_tensor = _tensor_reg->getAclTensor(ofm_index);
+ std::vector<::arm_compute::ITensor *> input_tensors;
+ for (const auto &ifm_ind : input_indexes)
+ input_tensors.emplace_back(_tensor_reg->getAclTensor(ifm_ind)->handle());
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+ if (input_indexes.size() < 2)
+ {
+ fn = acl_common::generateLayer<arm_compute::NECopy>(input_tensors.at(0),
+ output_tensor->handle());
+ }
+ else
+ {
+ const auto rank = _ctx.at(ofm_index).shape().rank();
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = output_tensor->layout();
+ const auto fixed_axis =
+ acl_common::ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value();
+ fn = acl_common::generateLayer<arm_compute::NEConcatenateLayer>(
+ input_tensors, output_tensor->handle(), fixed_axis);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseActivation &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ElementwiseActivation::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ const ::arm_compute::ActivationLayerInfo act_info = acl_common::asActivationLayerInfo(
+ node.param().op_type, node.param().alpha, node.param().beta);
+
+ std::unique_ptr<arm_compute::IFunction> fn =
+ acl_common::generateLayer<arm_compute::NEActivationLayer>(ifm_tensor->handle(),
+ ofm_tensor->handle(), act_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseBinary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::ElementwiseBinary::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::ElementwiseBinary::Input::RHS)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto lhs_tensor = _tensor_reg->getAclTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getAclTensor(rhs_index);
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ switch (node.param().op_type)
+ {
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_AND:
+ {
+ fn = acl_common::generateLayer<arm_compute::NELogicalAnd>(
+ lhs_tensor->handle(), rhs_tensor->handle(), output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR:
+ {
+ fn = acl_common::generateLayer<arm_compute::NELogicalOr>(
+ lhs_tensor->handle(), rhs_tensor->handle(), output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::MAX:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEElementwiseMax>(
+ lhs_tensor->handle(), rhs_tensor->handle(), output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::MIN:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEElementwiseMin>(
+ lhs_tensor->handle(), rhs_tensor->handle(), output_tensor->handle());
+ break;
+ }
+ default:
+ {
+ std::string err_msg("acl_neon KernelGenerator : " + node.name() +
+ "is not elementwise-binary operations");
+ assert(false && err_msg.c_str());
+ break;
+ }
+ }
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseUnary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ElementwiseUnary::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ switch (node.param().op_type)
+ {
+ case ir::operation::ElementwiseUnary::Type::ABS:
+ {
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::ABS};
+
+ fn = acl_common::generateLayer<arm_compute::NEActivationLayer>(
+ input_tensor->handle(), output_tensor->handle(), act_info);
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::CAST:
+ {
+ if (input_tensor->data_type() == output_tensor->data_type())
+ {
+ fn = acl_common::generateLayer<arm_compute::NECopy>(input_tensor->handle(),
+ output_tensor->handle());
+ }
+ else if (_ctx.at(input_index).typeInfo().type() == ir::DataType::BOOL8)
+ {
+ fn = acl_common::generateLayer<arm_compute::NECastBool>(input_tensor->handle(),
+ output_tensor->handle());
+ }
+ else
+ {
+ fn = acl_common::generateLayer<arm_compute::NECast>(
+ input_tensor->handle(), output_tensor->handle(), arm_compute::ConvertPolicy::SATURATE);
+ }
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::DEQUANTIZE:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEDequantizationLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::EXP:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEExpLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::FLOOR:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEFloor>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::LOGICAL_NOT:
+ {
+ fn = acl_common::generateLayer<arm_compute::NEBitwiseNot>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::NEG:
+ {
+ fn = acl_common::generateLayer<arm_compute::NENegLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::RSQRT:
+ {
+ fn = acl_common::generateLayer<arm_compute::NERsqrtLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ break;
+ }
+ case ir::operation::ElementwiseUnary::Type::SQRT:
+ {
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::SQRT};
+
+ fn = acl_common::generateLayer<arm_compute::NEActivationLayer>(
+ input_tensor->handle(), output_tensor->handle(), act_info);
+ break;
+ }
+ default:
+ {
+ throw std::runtime_error("acl_neon KernelGenerator : " + node.name() +
+ "is not supported yet");
+ break;
+ }
+ }
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::EmbeddingLookup &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lookups_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::LOOKUPS)};
+ const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto lookups_tensor = _tensor_reg->getAclTensor(lookups_index);
+ auto values_tensor = _tensor_reg->getAclTensor(values_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEEmbeddingLookup>(
+ values_tensor->handle(), output_tensor->handle(), lookups_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::FullyConnected &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ const auto activation = node.param().activation;
+ if (node.param().weights_format == ir::FullyConnectedWeightsFormat::Shuffled16x1Float32)
+ throw std::runtime_error(
+ "KernelGenerator(acl_neon): FullyConnected 16x1Float32 weights is not supported.");
+
+ auto fn = acl_common::kernelGenFullyConnected<acl_common::AclFunction, ::arm_compute::ITensor,
+ ::arm_compute::NEFullyConnectedReshapingLayer>(
+ node, _ctx, _tensor_builder, _tensor_reg, _current_op_seq_layout);
+ _return_fn = std::make_unique<exec::FunctionSequence>(
+ std::move(fn), ActivationBuilder::generate(activation, output_tensor->handle()));
+}
+
+void KernelGenerator::visit(const ir::operation::HashtableLookup &node)
+{
+ const auto output_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::OUTPUT)};
+ const auto hits_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::HITS)};
+
+ const auto lookups_index{node.getInputs().at(ir::operation::HashtableLookup::Input::LOOKUPS)};
+ const auto keys_index{node.getInputs().at(ir::operation::HashtableLookup::Input::KEYS)};
+ const auto values_index{node.getInputs().at(ir::operation::HashtableLookup::Input::VALUES)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto hits_tensor = _tensor_reg->getAclTensor(hits_index);
+
+ auto lookups_tensor = _tensor_reg->getAclTensor(lookups_index);
+ auto keys_tensor = _tensor_reg->getAclTensor(keys_index);
+ auto values_tensor = _tensor_reg->getAclTensor(values_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEHashtableLookup>(
+ lookups_tensor->handle(), keys_tensor->handle(), values_tensor->handle(),
+ output_tensor->handle(), hits_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Gather &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)};
+ const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)};
+
+ const auto ifm_rank = _ctx.at(ifm_index).shape().rank();
+ const auto axis_raw = node.param().axis;
+ const auto axis_value = (axis_raw < 0 ? (ifm_rank + axis_raw) : axis_raw);
+ // Converting in reverse order
+ const int axis = ::onert::backend::acl_common::ToARMComputeAxis(ifm_rank, axis_value).value();
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto indices_tensor = _tensor_reg->getAclTensor(indices_index);
+ const auto backend_layout = ofm_tensor->layout();
+ UNUSED_RELEASE(backend_layout);
+
+ // NOTE The frontend layout and backend layout must be the same for this operation.
+ // If not the same, we have to add a stage(?) to perform permutation of output tensor. It
+ // is not not efficient even if it works well. If so, it would be better to set the
+ // layout of these backend tensors to the same layout.
+ // There is also one thing we have to think about. This operation depends on the layout of
+ // a model. For example, if a model in NHWC has this operation as output rank == 4, indices
+ // rank == 2 and axis == 2, this operation should work as the axis W and C, but the axis W
+ // and C are not sequential in NCHW. So the backend in NCHW cannot handle this case.
+ assert(backend_layout == ifm_tensor->layout());
+ assert(backend_layout == indices_tensor->layout());
+ assert(ifm_rank < 4 || _current_op_seq_layout == backend_layout);
+
+ // input is n-D, indices k-D, output is (n + k - 1)-D
+ size_t n = ifm_rank;
+ assert(n == ifm_tensor->num_dimensions());
+ size_t k = _ctx.at(indices_index).shape().rank();
+ assert(k == indices_tensor->num_dimensions());
+
+ // Disable applied dim_correction
+ if (n != ifm_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and ifm tensor is applied dim_correction
+ acl_common::disableDimCorrection(ifm_tensor);
+ }
+ if (k != indices_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and indices tensor is applied dim_correction
+ acl_common::disableDimCorrection(indices_tensor);
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::NEGatherEx>(
+ ifm_tensor->handle(), indices_tensor->handle(), ofm_tensor->handle(), axis);
+
+ // Revert disabling applied dim_correction
+ if (ifm_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(ifm_tensor);
+ }
+ if (indices_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(indices_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::InstanceNorm &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::InstanceNorm::Input::INPUT)};
+ const auto gamma_index{node.getInputs().at(ir::operation::InstanceNorm::Input::GAMMA)};
+ const auto beta_index{node.getInputs().at(ir::operation::InstanceNorm::Input::BETA)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto gamma_tensor = _tensor_reg->getAclTensor(gamma_index);
+ auto beta_tensor = _tensor_reg->getAclTensor(beta_index);
+ auto epsilon = node.param().epsilon;
+ auto activation = node.param().activation;
+
+ auto fn = acl_common::generateLayer<arm_compute::NEInstanceNormalizationLayerEx>(
+ ifm_tensor->handle(), ofm_tensor->handle(), gamma_tensor->handle(), beta_tensor->handle(),
+ epsilon);
+
+ _return_fn = std::make_unique<exec::FunctionSequence>(
+ asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_tensor->handle()));
+}
+
+void KernelGenerator::visit(const ir::operation::L2Normalization &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::L2Normalization::Input::INPUT)};
+
+ // {CL|Neon}L2Normalization performs the reduction only along dimension 0
+ // L2 Normalization always performs the reduction along the depth axis
+ // Thus, we repurpose {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by
+ // choosing normalization parameters as below
+
+ const auto &ifm_shape = _ctx.at(ifm_index).shape();
+ // TODO Support optional constant dimension that normalization would be performed on
+ const auto normalization_axis = _ctx.at(ifm_index).shape().rank() - 1;
+ int32_t radius =
+ 2 * ifm_shape.dim(normalization_axis) + 1; // normSize = depth(last dimension) * 2 + 1
+ float alpha = 1.0f; // In the implementation to make alpha_ become 1
+ float beta = 0.5f; // pow(reduction, -0.5) = 1 / sqrt(reduction)
+ float bias = 0.0f; // Don't offset the reduction.
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ const auto norm_info = ::arm_compute::NormalizationLayerInfo(::arm_compute::NormType::CROSS_MAP,
+ radius, alpha, beta, bias, false);
+
+ auto fn = acl_common::generateLayer<arm_compute::NENormalizationLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), norm_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::LocalResponseNormalization &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{
+ node.getInputs().at(ir::operation::LocalResponseNormalization::Input::INPUT)};
+
+ auto radius = node.param().radius;
+ auto alpha = node.param().alpha;
+ auto beta = node.param().beta;
+ auto bias = node.param().bias;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ const auto norm_info = ::arm_compute::NormalizationLayerInfo(
+ ::arm_compute::NormType::CROSS_MAP, radius * 2 + 1, alpha, beta, bias, false);
+
+ auto fn = acl_common::generateLayer<arm_compute::NENormalizationLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), norm_info);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::LSTM &node)
+{
+ _return_fn = acl_common::kernelGenLSTM<acl_common::AclFunction, ::arm_compute::ITensor,
+ ::arm_compute::NELSTMLayer>(node, _ctx, _tensor_reg);
+}
+
+void KernelGenerator::visit(const ir::operation::Pack &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ auto axis{node.param().axis};
+
+ const auto output_rank = _ctx.at(output_index).shape().rank();
+
+ std::vector<ir::OperandIndex> input_indexes;
+ for (const auto &input_index : node.getInputs())
+ input_indexes.emplace_back(input_index);
+
+ auto output = _tensor_reg->getAclTensor(output_index)->handle();
+ std::vector<arm_compute::ITensor *> inputs;
+ for (const auto &input_index : input_indexes)
+ inputs.emplace_back(_tensor_reg->getAclTensor(input_index)->handle());
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = _tensor_reg->getAclTensor(output_index)->layout();
+
+ if (axis < 0)
+ axis += output_rank;
+ axis = acl_common::ToARMComputeAxis(output_rank, axis, frontend_layout, backend_layout).value();
+
+ // Disable applied dim_correction
+ for (const auto &input_index : input_indexes)
+ {
+ const auto &input_tensor = _tensor_reg->getAclTensor(input_index);
+ if (input_tensor->num_dimensions() != input_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and input tensor is applied dim_correction
+ acl_common::disableDimCorrection(input_tensor);
+ }
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::NEStackLayer>(inputs, axis, output);
+
+ // Revert disabling applied dim_correction
+ for (const auto &input_index : input_indexes)
+ {
+ const auto &input_tensor = _tensor_reg->getAclTensor(input_index);
+ if (input_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(input_tensor);
+ }
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Pad &node)
+{
+ const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)};
+ const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)};
+ const auto output_index{node.getOutputs().at(0)};
+ assert(_ctx.at(pad_index).data());
+
+ auto rank = _ctx.at(input_index).shape().rank();
+ auto pad_base = _ctx.at(pad_index).data()->base();
+
+ auto input = _tensor_reg->getAclTensor(input_index)->handle();
+ auto output = _tensor_reg->getAclTensor(output_index)->handle();
+
+ ::arm_compute::PaddingList padding_list;
+ padding_list.resize(rank);
+ for (int32_t n = 0; n < rank; ++n)
+ {
+ const int32_t *from = reinterpret_cast<const int32_t *>(pad_base) + (n * 2);
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = _tensor_reg->getAclTensor(input_index)->layout();
+ const auto axis =
+ acl_common::ToARMComputeAxis(rank, n, frontend_layout, backend_layout).value();
+ padding_list[axis] = ::arm_compute::PaddingInfo{from[0], from[1]};
+ }
+
+ const auto input_type = _ctx.at(input_index).typeInfo();
+ UNUSED_RELEASE(input_type);
+ assert(input->info()->data_type() == acl_common::asDataType(input_type.type()));
+ assert(input->info()->quantization_info() ==
+ ::arm_compute::QuantizationInfo(input_type.scale(), input_type.offset()));
+ const auto pixel_value =
+ ::arm_compute::PixelValue(0, input->info()->data_type(), input->info()->quantization_info());
+
+ auto fn =
+ acl_common::generateLayer<arm_compute::NEPadLayer>(input, output, padding_list, pixel_value);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Pool2D &node)
+{
+ auto raw_fn = acl_common::kernelGenPool2D<::arm_compute::NEPoolingLayer>(
+ node, _ctx, _tensor_reg, _current_op_seq_layout,
+ acl_common::convertPoolType(node.param().op_type));
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ const auto activation = node.param().activation;
+ _return_fn = std::make_unique<exec::FunctionSequence>(
+ asAclFunction(std::move(raw_fn)),
+ ActivationBuilder::generate(activation, ofm_tensor->handle()));
+}
+
+void KernelGenerator::visit(const ir::operation::Permute &node)
+{
+ const auto ofm_idx{node.getOutputs().at(0)};
+ const auto ifm_idx{node.getInputs().at(0)};
+ const auto permute_type = node.getPermuteType();
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_idx);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_idx);
+ const auto rank = _ctx.at(ofm_idx).shape().rank();
+ assert(_ctx.at(ifm_idx).shape().rank() == _ctx.at(ofm_idx).shape().rank());
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+ arm_compute::PermutationVector pv;
+ if (permute_type == ir::operation::Permute::Type::NCHW_TO_NHWC && rank == 4)
+ {
+ // WHCN -> CWHN
+ pv = arm_compute::PermutationVector{2, 0, 1};
+
+ fn = acl_common::generateLayer<arm_compute::NEPermute>(ifm_tensor->handle(),
+ ofm_tensor->handle(), pv);
+ }
+ else if (permute_type == ir::operation::Permute::Type::NHWC_TO_NCHW && rank == 4)
+ {
+ // CWHN -> WHCN
+ pv = arm_compute::PermutationVector{1, 2, 0};
+
+ fn = acl_common::generateLayer<arm_compute::NEPermute>(ifm_tensor->handle(),
+ ofm_tensor->handle(), pv);
+ }
+ else
+ {
+ fn = acl_common::generateLayer<arm_compute::NECopy>(ifm_tensor->handle(), ofm_tensor->handle());
+ }
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::PReLU &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::PReLU::Input::INPUT)};
+ const auto alpha_index{node.getInputs().at(ir::operation::PReLU::Input::ALPHA)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto alpha_tensor = _tensor_reg->getAclTensor(alpha_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEPReluLayer>(
+ ifm_tensor->handle(), alpha_tensor->handle(), ofm_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Reduce &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Reduce::Input::INPUT)};
+ const auto axes_index{node.getInputs().at(ir::operation::Reduce::Input::AXES)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ // Convert to ACL axes taking into account negative values and possible duplicates.
+ const auto &axes = _ctx.at(axes_index);
+ const auto input_rank = _ctx.at(input_index).shape().rank();
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = input_tensor->layout();
+ const auto reduce_axes =
+ acl_common::asCoordinates(axes, input_rank, frontend_layout, backend_layout);
+ const auto reduce_type = node.param().reduce_type;
+ const auto keep_dims = node.param().keep_dims;
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+ if (reduce_type == ir::operation::Reduce::ReduceType::MEAN)
+ {
+ fn = acl_common::generateLayer<arm_compute::NEReduceMean>(input_tensor->handle(), reduce_axes,
+ keep_dims, output_tensor->handle());
+ }
+ else if (reduce_type == ir::operation::Reduce::ReduceType::SUM)
+ {
+ fn = acl_common::generateLayer<arm_compute::NEReduceSum>(input_tensor->handle(), reduce_axes,
+ keep_dims, output_tensor->handle());
+ }
+ else
+ {
+ fn = acl_common::generateLayer<arm_compute::NEReduceOperation>(
+ input_tensor->handle(), reduce_axes, keep_dims, output_tensor->handle(),
+ acl_common::convertReduceType(reduce_type));
+ }
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Reshape &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Reshape::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ // NOTE This operation must not be changed the layout from frontend to backend
+ // So, PermutationOperationPass makes layouts of frontend and backend the same.
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = output_tensor->layout();
+ assert((_ctx.at(input_index).shape().rank() < 4 && _ctx.at(output_index).shape().rank() < 4) ||
+ frontend_layout == backend_layout);
+ UNUSED_RELEASE(frontend_layout);
+ UNUSED_RELEASE(backend_layout);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEReshapeLayer>(input_tensor->handle(),
+ output_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ResizeBilinear &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ResizeBilinear::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEScale>(
+ ifm_tensor->handle(), ofm_tensor->handle(), ::arm_compute::InterpolationPolicy::BILINEAR,
+ ::arm_compute::BorderMode::REPLICATE, ::arm_compute::PixelValue(0.f),
+ ::arm_compute::SamplingPolicy::TOP_LEFT);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::RNN &node)
+{
+ const auto output_index{node.getOutputs().at(ir::operation::RNN::Output::OUTPUT)};
+ const auto hidden_state_out_index{
+ node.getOutputs().at(ir::operation::RNN::Output::HIDDEN_STATE_OUT)};
+
+ const auto input_index{node.getInputs().at(ir::operation::RNN::Input::INPUT)};
+ const auto weights_index{node.getInputs().at(ir::operation::RNN::Input::WEIGHTS)};
+ const auto recurrent_weights_index{
+ node.getInputs().at(ir::operation::RNN::Input::RECURRENT_WEIGHTS)};
+ const auto bias_index{node.getInputs().at(ir::operation::RNN::Input::BIAS)};
+ const auto hidden_state_in_index{node.getInputs().at(ir::operation::RNN::Input::HIDDEN_STATE_IN)};
+
+ const auto activation = node.param().activation;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto hidden_state_out_tensor = _tensor_reg->getAclTensor(hidden_state_out_index);
+
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+ auto weights_tensor = _tensor_reg->getAclTensor(weights_index);
+ auto recurrent_weights_tensor = _tensor_reg->getAclTensor(recurrent_weights_index);
+ auto bias_tensor = _tensor_reg->getAclTensor(bias_index);
+ auto hidden_state_in_tensor = _tensor_reg->getAclTensor(hidden_state_in_index);
+ auto act_info = ::onert::backend::acl_common::asActivationLayerInfo(activation);
+
+ auto copy_layer = acl_common::generateLayer<arm_compute::NECopy>(
+ hidden_state_in_tensor->handle(), hidden_state_out_tensor->handle());
+ _return_fn = asAclFunction(std::move(copy_layer));
+
+ auto fn = acl_common::generateLayer<arm_compute::NERNNLayer>(
+ _tensor_builder->acl_tensor_manager()->internal_buffer_manager(), input_tensor->handle(),
+ weights_tensor->handle(), recurrent_weights_tensor->handle(), bias_tensor->handle(),
+ hidden_state_out_tensor->handle(), output_tensor->handle(), act_info);
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Squeeze &node)
+{
+ // Squeeze is identical to reshape except that it has an optional dimensions input.
+ // In addition, optional dims_index is ignored since output tensor already has squeezed shape
+ // by freezer and toco
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Squeeze::Input::INPUT)};
+ const auto dims{node.param().dims};
+ const auto ndim{node.param().ndim};
+ (void)dims;
+ (void)ndim;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+ auto fn = acl_common::generateLayer<arm_compute::NEReshapeLayer>(input_tensor->handle(),
+ output_tensor->handle());
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Softmax &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Softmax::Input::INPUT)};
+ const auto beta = node.param().beta;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ // Disable applied dim_correction
+ if (input_tensor->num_dimensions() != input_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and input tensor is applied dim_correction
+ acl_common::disableDimCorrection(input_tensor);
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::NESoftmaxLayer>(
+ _tensor_builder->acl_tensor_manager()->internal_buffer_manager(), input_tensor->handle(),
+ output_tensor->handle(), beta);
+
+ // Revert disabling applied dim_correction
+ if (input_tensor->dimension(0) == 1)
+ {
+ acl_common::disableDimCorrection(input_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::SpaceToBatchND &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)};
+ const auto block_size_index{
+ node.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)};
+ const auto paddings_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto block_size_tensor = _tensor_reg->getAclTensor(block_size_index);
+ auto paddings_tensor = _tensor_reg->getAclTensor(paddings_index);
+
+ assert(_ctx.at(block_size_index).data());
+ assert(_ctx.at(paddings_index).data());
+
+ auto fn = acl_common::generateLayer<arm_compute::NESpaceToBatchLayer>(
+ ifm_tensor->handle(), block_size_tensor->handle(), paddings_tensor->handle(),
+ ofm_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::SpaceToDepth &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)};
+
+ auto block_size = node.param().block_size;
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NESpaceToDepthLayer>(
+ ifm_tensor->handle(), ofm_tensor->handle(), block_size);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Split &node)
+{
+ // TODO Support this op by SubTensor
+ const auto ifm_index{node.getInputs().at(ir::operation::Split::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::Split::Input::AXIS)};
+
+ assert(node.param().num_splits == static_cast<int>(node.getOutputs().size()));
+ if (!_ctx.at(axis_index).isConstant())
+ {
+ throw std::runtime_error("Non-constant axis_index NYI for acl_neon backend");
+ }
+
+ const auto ifm_rank = _ctx.at(ifm_index).shape().rank();
+ std::vector<ir::OperandIndex> output_indexes;
+ for (const auto &output : node.getOutputs())
+ output_indexes.emplace_back(output);
+
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ std::vector<arm_compute::ITensor *> output_tensors;
+ for (const auto &ofm_ind : output_indexes)
+ output_tensors.emplace_back(_tensor_reg->getAclTensor(ofm_ind)->handle());
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = ifm_tensor->layout();
+ auto axis = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis < 0)
+ axis += ifm_rank;
+ axis = acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value();
+
+ auto fn =
+ acl_common::generateLayer<arm_compute::NESplit>(ifm_tensor->handle(), output_tensors, axis);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::SquaredDifference &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::RHS)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto lhs_tensor = _tensor_reg->getAclTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getAclTensor(rhs_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEElementwiseSquaredDiff>(
+ lhs_tensor->handle(), rhs_tensor->handle(), ofm_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Slice &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Slice::Input::INPUT)};
+ const auto begins_index{node.getInputs().at(ir::operation::Slice::Input::BEGINS)};
+ const auto sizes_index{node.getInputs().at(ir::operation::Slice::Input::SIZES)};
+
+ auto outputData_tensor = _tensor_reg->getAclTensor(output_index);
+ auto inputData_tensor = _tensor_reg->getAclTensor(input_index);
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = inputData_tensor->layout();
+
+ // Set initializers for indices data such as order of inputData
+ int input_rank = _ctx.at(input_index).shape().rank();
+ std::vector<int32_t> starts;
+ std::vector<int32_t> ends;
+ starts.resize(input_rank, 0);
+ ends.resize(input_rank, 0);
+ {
+ auto beginData_base = _ctx.at(begins_index).data()->base();
+ auto sizeData_base = _ctx.at(sizes_index).data()->base();
+ const int beginData_size = _ctx.at(begins_index).shape().num_elements();
+ const int sizeData_size = _ctx.at(sizes_index).shape().num_elements();
+
+ using ir::DataType;
+
+ UNUSED_RELEASE(beginData_size);
+ UNUSED_RELEASE(sizeData_size);
+
+ assert(_ctx.at(begins_index).typeInfo().type() == DataType::INT32);
+ assert(_ctx.at(sizes_index).typeInfo().type() == DataType::INT32);
+ assert(beginData_size == input_rank);
+ assert(sizeData_size == input_rank);
+
+ assert(beginData_base != nullptr);
+ for (int n = 0; n < input_rank; ++n)
+ {
+ auto axis = ::onert::backend::acl_common::ToARMComputeAxis(input_rank, n, frontend_layout,
+ backend_layout)
+ .value();
+
+ int32_t begin_value = *(reinterpret_cast<const int32_t *>(beginData_base) + n);
+ starts[axis] = begin_value;
+
+ int32_t size_value = *(reinterpret_cast<const int32_t *>(sizeData_base) + n);
+ ends[axis] = begin_value + size_value;
+ }
+ }
+
+ ::arm_compute::Coordinates starts_set;
+ ::arm_compute::Coordinates ends_set;
+
+ for (size_t i = 0; i < starts.size(); ++i)
+ {
+ starts_set.set(i, starts[i]);
+ ends_set.set(i, ends[i]);
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::NESlice>(
+ inputData_tensor->handle(), outputData_tensor->handle(), starts_set, ends_set);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::StridedSlice &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)};
+ const auto starts_index{node.getInputs().at(ir::operation::StridedSlice::Input::STARTS)};
+ const auto ends_index{node.getInputs().at(ir::operation::StridedSlice::Input::ENDS)};
+ const auto strides_index{node.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)};
+
+ auto outputData_tensor = _tensor_reg->getAclTensor(output_index);
+ auto inputData_tensor = _tensor_reg->getAclTensor(input_index);
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = inputData_tensor->layout();
+
+ // Set initializers for indices data such as order of inputData
+ int input_rank = _ctx.at(input_index).shape().rank();
+ std::vector<int32_t> starts;
+ std::vector<int32_t> ends;
+ std::vector<int32_t> strides;
+ starts.resize(input_rank, 0);
+ ends.resize(input_rank, 0);
+ strides.resize(input_rank, 0);
+ {
+ auto startData_base = _ctx.at(starts_index).data()->base();
+ auto endData_base = _ctx.at(ends_index).data()->base();
+ auto stridesData_base = _ctx.at(strides_index).data()->base();
+ const int startData_size = _ctx.at(starts_index).shape().num_elements();
+ const int endData_size = _ctx.at(ends_index).shape().num_elements();
+ const int stridesData_size = _ctx.at(strides_index).shape().num_elements();
+
+ using ir::DataType;
+
+ UNUSED_RELEASE(startData_size);
+ UNUSED_RELEASE(endData_size);
+ UNUSED_RELEASE(stridesData_size);
+
+ assert(_ctx.at(starts_index).typeInfo().type() == DataType::INT32);
+ assert(_ctx.at(ends_index).typeInfo().type() == DataType::INT32);
+ assert(_ctx.at(strides_index).typeInfo().type() == DataType::INT32);
+ assert(startData_size == input_rank);
+ assert(endData_size == input_rank);
+ assert(stridesData_size == input_rank);
+
+ assert(startData_base != nullptr);
+ for (int n = 0; n < input_rank; ++n)
+ {
+ auto axis = ::onert::backend::acl_common::ToARMComputeAxis(input_rank, n, frontend_layout,
+ backend_layout)
+ .value();
+
+ int32_t start_value = *(reinterpret_cast<const int32_t *>(startData_base) + n);
+ starts[axis] = start_value;
+
+ int32_t end_value = *(reinterpret_cast<const int32_t *>(endData_base) + n);
+ ends[axis] = end_value;
+
+ int32_t strides_value = *(reinterpret_cast<const int32_t *>(stridesData_base) + n);
+ strides[axis] = strides_value;
+ }
+ }
+
+ // Set mask bits such as order of inputData
+ // FIXME Take the layouts into account.
+ const auto begin_mask = acl_common::ReorderBits<int32_t>(node.param().begin_mask, input_rank);
+ const auto end_mask = acl_common::ReorderBits<int32_t>(node.param().end_mask, input_rank);
+ const auto shrink_axis_mask =
+ acl_common::ReorderBits<int32_t>(node.param().shrink_axis_mask, input_rank);
+
+ ::arm_compute::Coordinates starts_set;
+ ::arm_compute::Coordinates ends_set;
+ ::arm_compute::BiStrides strides_set;
+
+ for (size_t i = 0; i < starts.size(); ++i)
+ {
+ starts_set.set(i, starts[i]);
+ ends_set.set(i, ends[i]);
+ strides_set.set(i, strides[i]);
+ }
+
+ // Disable applied dim_correction
+ if (inputData_tensor->num_dimensions() != inputData_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and input tensor is applied dim_correction
+ acl_common::disableDimCorrection(inputData_tensor);
+ }
+
+ auto fn = acl_common::generateLayer<arm_compute::NEStridedSlice>(
+ inputData_tensor->handle(), outputData_tensor->handle(), starts_set, ends_set, strides_set,
+ begin_mask, end_mask, shrink_axis_mask);
+
+ // Revert disabling applied dim_correction
+ if (inputData_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(inputData_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::TransposeConv &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ker_index{node.getInputs().at(ir::operation::TransposeConv::Input::KERNEL)};
+ const auto ifm_index{node.getInputs().at(ir::operation::TransposeConv::Input::INPUT)};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ker_shape = _ctx.at(ker_index).shape().asFeature(_current_op_seq_layout);
+
+ const auto stride = node.param().stride;
+
+ assert((node.param().padding.type == ir::PaddingType::SAME) ||
+ (node.param().padding.type == ir::PaddingType::VALID));
+ auto padding = ir::calculatePadding(node.param().padding, ofm_shape, ifm_shape, stride,
+ ker_shape.W, ker_shape.H);
+
+ uint32_t invalid_horizontal = 0;
+ uint32_t invalid_vertical = 0;
+ if (node.param().padding.type == ir::PaddingType::VALID)
+ {
+ invalid_horizontal =
+ ofm_shape.W - (1 + (ifm_shape.W - 1) * stride.horizontal) - (ker_shape.W - 1);
+ invalid_vertical = ofm_shape.H - (1 + (ifm_shape.H - 1) * stride.vertical) - (ker_shape.H - 1);
+ }
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getAclTensor(ifm_index);
+ auto ker_tensor = _tensor_reg->getAclTensor(ker_index);
+
+ const auto tconv_info = acl_common::asPadStrideInfo(padding, stride);
+
+ auto fn = acl_common::generateLayer<arm_compute::NETransposeConvLayer>(
+ ifm_tensor->handle(), ker_tensor->handle(), nullptr, ofm_tensor->handle(), tconv_info,
+ invalid_horizontal, invalid_vertical);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Transpose &node)
+{
+ const auto ofm_idx{node.getOutputs().at(0)};
+ const auto ifm_idx{node.getInputs().at(ir::operation::Transpose::Input::INPUT)};
+ const auto perm_idx{node.getInputs().at(ir::operation::Transpose::Input::PERMUTATION)};
+
+ auto ofm_tensor = _tensor_reg->getAclTensor(ofm_idx);
+ const auto ifm_tensor = _tensor_reg->getAclTensor(ifm_idx);
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = ifm_tensor->layout();
+ const auto rank = _ctx.at(ifm_idx).shape().rank();
+
+ const auto &perms = _ctx.at(perm_idx);
+ std::vector<int32_t> pv;
+ if (perms.shape() == ir::Shape{0})
+ {
+ pv.resize(rank);
+ std::iota(pv.begin(), pv.end(), 0);
+ std::reverse(pv.begin(), pv.end());
+ }
+ else
+ {
+ pv = _ctx.at(perm_idx).asVector<int32_t>();
+ }
+
+ std::unique_ptr<arm_compute::IFunction> fn;
+ if (rank == 1)
+ {
+ fn = acl_common::generateLayer<arm_compute::NECopy>(ifm_tensor->handle(), ofm_tensor->handle());
+ }
+ else if (rank == 2)
+ {
+ assert(pv.size() == 2 && pv.at(0) == 1 && pv.at(1) == 0);
+ fn = acl_common::generateLayer<arm_compute::NETranspose>(ifm_tensor->handle(),
+ ofm_tensor->handle());
+ }
+ else
+ {
+ auto backend_pv =
+ acl_common::getARMComputePermutationVector(rank, pv, frontend_layout, backend_layout);
+
+ fn = acl_common::generateLayer<arm_compute::NEPermute>(ifm_tensor->handle(),
+ ofm_tensor->handle(), backend_pv);
+ }
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Unpack &node)
+{
+ const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)};
+ auto axis{node.param().axis};
+
+ const auto input_rank = _ctx.at(input_index).shape().rank();
+
+ std::vector<ir::OperandIndex> output_indexes;
+ for (const auto &output_index : node.getOutputs())
+ output_indexes.emplace_back(output_index);
+
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+ std::vector<arm_compute::ITensor *> outputs;
+ for (const auto &output_index : output_indexes)
+ outputs.emplace_back(_tensor_reg->getAclTensor(output_index)->handle());
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = _tensor_reg->getAclTensor(input_index)->layout();
+ if (axis < 0)
+ axis += input_rank;
+ axis = acl_common::ToARMComputeAxis(input_rank, axis, frontend_layout, backend_layout).value();
+
+ // Disable applied dim_correction
+ if (input_tensor->num_dimensions() != input_tensor->info()->num_dimensions())
+ {
+ // This means that high dimension's value is 1 and input tensor is applied dim_correction
+ acl_common::disableDimCorrection(input_tensor);
+ }
+
+ auto fn =
+ acl_common::generateLayer<arm_compute::NEUnstack>(input_tensor->handle(), outputs, axis);
+
+ // Revert disabling applied dim_correction
+ if (input_tensor->dimension(0) == 1)
+ {
+ acl_common::enableDimCorrection(input_tensor);
+ }
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::ExpandDims &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ExpandDims::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input_tensor = _tensor_reg->getAclTensor(input_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEReshapeLayer>(input_tensor->handle(),
+ output_tensor->handle());
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::Comparison &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input0_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)};
+ const auto input1_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)};
+
+ const auto comparison_type = node.param().comparison_type;
+
+ auto output_tensor = _tensor_reg->getAclTensor(output_index);
+ auto input0_tensor = _tensor_reg->getAclTensor(input0_index);
+ auto input1_tensor = _tensor_reg->getAclTensor(input1_index);
+
+ auto fn = acl_common::generateLayer<arm_compute::NEElementwiseComparison>(
+ input0_tensor->handle(), input1_tensor->handle(), output_tensor->handle(),
+ (arm_compute::ComparisonOperation)comparison_type);
+
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+void KernelGenerator::visit(const ir::operation::OneHot &node)
+{
+ const auto out_idx{node.getOutputs().at(0)};
+ const auto indices_idx{node.getInputs().at(ir::operation::OneHot::Input::INDICES)};
+ const auto depth_idx{node.getInputs().at(ir::operation::OneHot::Input::DEPTH)};
+ const auto onvalue_idx{node.getInputs().at(ir::operation::OneHot::Input::ON_VALUE)};
+ const auto offvalue_idx{node.getInputs().at(ir::operation::OneHot::Input::OFF_VALUE)};
+
+ auto output_tensor = _tensor_reg->getAclTensor(out_idx);
+ auto indices_tensor = _tensor_reg->getAclTensor(indices_idx);
+ auto depth_tensor = _tensor_reg->getAclTensor(depth_idx);
+ auto onvalue_tensor = _tensor_reg->getAclTensor(onvalue_idx);
+ auto offvalue_tensor = _tensor_reg->getAclTensor(offvalue_idx);
+
+ const size_t output_rank = _ctx.at(out_idx).shape().rank();
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto backend_layout = output_tensor->layout();
+ int32_t axis = node.param().axis == -1 ? output_rank - 1 : node.param().axis;
+ axis = acl_common::ToARMComputeAxis(output_rank, axis, frontend_layout, backend_layout).value();
+
+ auto fn = acl_common::generateLayer<arm_compute::NEOneHot>(
+ indices_tensor->handle(), depth_tensor->handle(), onvalue_tensor->handle(),
+ offvalue_tensor->handle(), output_tensor->handle(), axis);
+ _return_fn = asAclFunction(std::move(fn));
+}
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_neon/KernelGenerator.h b/runtime/onert/backend/acl_neon/KernelGenerator.h
new file mode 100644
index 000000000..4d269cde5
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/KernelGenerator.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_KERNEL_GENERATOR_H__
+#define __ONERT_BACKEND_ACL_NEON_KERNEL_GENERATOR_H__
+
+#include <backend/IKernelGenerator.h>
+
+#include "ir/Operands.h"
+#include "TensorBuilder.h"
+#include "AclTensorRegistry.h"
+#include "TensorManager.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+class KernelGenerator : public IKernelGenerator
+{
+public:
+ KernelGenerator(const ir::Operands &operands_ctx, const ir::Operations &operations_ctx,
+ const std::shared_ptr<TensorBuilder> &tensor_builder,
+ const std::shared_ptr<acl_common::AclTensorRegistry<TensorManager>> &_tensor_reg);
+
+ void visit(const ir::OpSequence &) override;
+ void visit(const ir::operation::ArgMax &) override;
+ void visit(const ir::operation::BatchToSpaceND &) override;
+ void visit(const ir::operation::BinaryArithmetic &) override;
+ void visit(const ir::operation::Conv2D &) override;
+ void visit(const ir::operation::DepthToSpace &) override;
+ void visit(const ir::operation::DepthwiseConv2D &) override;
+ void visit(const ir::operation::Concat &) override;
+ void visit(const ir::operation::ElementwiseActivation &) override;
+ void visit(const ir::operation::ElementwiseBinary &) override;
+ void visit(const ir::operation::ElementwiseUnary &) override;
+ void visit(const ir::operation::EmbeddingLookup &) override;
+ void visit(const ir::operation::FullyConnected &) override;
+ void visit(const ir::operation::Gather &) override;
+ void visit(const ir::operation::HashtableLookup &) override;
+ void visit(const ir::operation::InstanceNorm &) override;
+ void visit(const ir::operation::L2Normalization &) override;
+ void visit(const ir::operation::LocalResponseNormalization &) override;
+ void visit(const ir::operation::LSTM &) override;
+ void visit(const ir::operation::Pack &) override;
+ void visit(const ir::operation::Pad &) override;
+ void visit(const ir::operation::Pool2D &) override;
+ void visit(const ir::operation::Permute &) override;
+ void visit(const ir::operation::PReLU &) override;
+ void visit(const ir::operation::Reduce &) override;
+ void visit(const ir::operation::Reshape &) override;
+ void visit(const ir::operation::ResizeBilinear &) override;
+ void visit(const ir::operation::RNN &) override;
+ void visit(const ir::operation::Squeeze &) override;
+ void visit(const ir::operation::Softmax &) override;
+ void visit(const ir::operation::SpaceToBatchND &) override;
+ void visit(const ir::operation::SpaceToDepth &) override;
+ void visit(const ir::operation::Split &) override;
+ void visit(const ir::operation::SquaredDifference &) override;
+ void visit(const ir::operation::Slice &) override;
+ void visit(const ir::operation::StridedSlice &) override;
+ void visit(const ir::operation::TransposeConv &) override;
+ void visit(const ir::operation::Transpose &) override;
+ void visit(const ir::operation::Unpack &) override;
+ void visit(const ir::operation::ExpandDims &) override;
+ void visit(const ir::operation::Comparison &) override;
+ void visit(const ir::operation::OneHot &) override;
+
+private:
+ const ir::Operands &_ctx;
+ const ir::Operations &_operations_ctx;
+ std::shared_ptr<TensorBuilder> _tensor_builder;
+ std::shared_ptr<acl_common::AclTensorRegistry<TensorManager>> _tensor_reg;
+ ir::Layout _current_op_seq_layout;
+};
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_KERNEL_GENERATOR_H__
diff --git a/runtime/onert/backend/acl_neon/Optimizer.cc b/runtime/onert/backend/acl_neon/Optimizer.cc
new file mode 100644
index 000000000..ac80901cc
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/Optimizer.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Optimizer.h"
+
+#include "ParentInfo.h"
+
+#include <cassert>
+#include <compiler/LoweredGraph.h>
+#include <util/logging.h>
+#include "AclSubTensorAnalyzer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+Optimizer::Optimizer(BackendContext *context)
+ : _context{context},
+ _tensor_builder{std::dynamic_pointer_cast<TensorBuilder>(context->tensor_builder)}
+{
+ assert(context);
+}
+
+void Optimizer::optimize()
+{
+ // Concat elimination (build subtensor info)
+ {
+ acl_common::AclSubTensorAnalyzer sa{*_context->graph()};
+ for (auto op_info : _context->operation_list())
+ {
+ auto &op = _context->graph()->operations().at(op_info.index);
+ sa.setLayout(op_info.layout);
+ op.accept(sa);
+ }
+
+ _tensor_builder->parent_map(sa.releaseParentMap());
+ }
+}
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_neon/Optimizer.h b/runtime/onert/backend/acl_neon/Optimizer.h
new file mode 100644
index 000000000..5fe0d519c
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/Optimizer.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_OPTIMIZER_H__
+#define __ONERT_BACKEND_ACL_NEON_OPTIMIZER_H__
+
+#include <backend/IOptimizer.h>
+#include <backend/BackendContext.h>
+#include "TensorBuilder.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+class Optimizer : public IOptimizer
+{
+public:
+ Optimizer(BackendContext *context);
+
+ void optimize() override;
+
+private:
+ BackendContext *_context;
+ std::shared_ptr<TensorBuilder> _tensor_builder;
+};
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_OPTIMIZER_H__
diff --git a/runtime/onert/backend/acl_neon/TensorBuilder.h b/runtime/onert/backend/acl_neon/TensorBuilder.h
new file mode 100644
index 000000000..070dc20ac
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/TensorBuilder.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_TENSOR_BUILDER_H__
+#define __ONERT_BACKEND_ACL_NEON_TENSOR_BUILDER_H__
+
+#include <AclTensorBuilder.h>
+
+#include "operand/NETensor.h"
+#include "operand/NESubTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+using TensorBuilder =
+ acl_common::AclTensorBuilder<operand::INETensor, operand::NETensor, operand::NESubTensor>;
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_TENSOR_BUILDER_H__
diff --git a/runtime/onert/backend/acl_neon/TensorManager.h b/runtime/onert/backend/acl_neon/TensorManager.h
new file mode 100644
index 000000000..3b7cfbcfd
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/TensorManager.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_TENSOR_MANAGER_H__
+#define __ONERT_BACKEND_ACL_NEON_TENSOR_MANAGER_H__
+
+#include <arm_compute/runtime/Allocator.h>
+#include <arm_compute/runtime/PoolManager.h>
+#include <arm_compute/runtime/OffsetLifetimeManager.h>
+#include <arm_compute/runtime/MemoryManagerOnDemand.h>
+#include <arm_compute/runtime/MemoryGroup.h>
+
+#include <AclMemoryManager.h>
+#include <AclLinearMemoryManager.h>
+#include <AclInternalBufferManager.h>
+#include <AclTensorManager.h>
+
+#include "operand/NETensor.h"
+#include "operand/NESubTensor.h"
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+
+using MemoryManager =
+ acl_common::AclMemoryManager<operand::INETensor, operand::NETensor, operand::NESubTensor>;
+
+using LinearMemoryManager = acl_common::AclLinearMemoryManager<
+ operand::INETensor, operand::NETensor, operand::NESubTensor,
+ ::arm_compute::MemoryManagerOnDemand, ::arm_compute::PoolManager,
+ ::arm_compute::OffsetLifetimeManager, ::arm_compute::Allocator, ::arm_compute::MemoryGroup>;
+
+using InternalBufferManager = acl_common::AclInternalBufferManager<
+ ::arm_compute::MemoryManagerOnDemand, ::arm_compute::PoolManager,
+ ::arm_compute::OffsetLifetimeManager, ::arm_compute::Allocator>;
+
+using TensorManager = acl_common::AclTensorManager<acl_neon::operand::INETensor, operand::NETensor,
+ operand::NESubTensor>;
+
+inline TensorManager *createTensorManager(bool is_linear_executor)
+{
+ if (is_linear_executor)
+ {
+ VERBOSE(acl_neon_createTensorManager) << "AclTensorManager as Linear" << std::endl;
+ return new TensorManager(new MemoryManager(), new LinearMemoryManager(),
+ new InternalBufferManager());
+ }
+ else
+ {
+ VERBOSE(acl_neon_createTensorManager) << "AclTensorManager" << std::endl;
+ return new TensorManager(new MemoryManager(), new MemoryManager(), new InternalBufferManager());
+ }
+}
+
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_TENSOR_MANAGER_H__
diff --git a/runtime/onert/backend/acl_neon/acl_neon.cc b/runtime/onert/backend/acl_neon/acl_neon.cc
new file mode 100644
index 000000000..f490d132d
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/acl_neon.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <util/logging.h>
+
+#include "Backend.h"
+
+extern "C" {
+onert::backend::Backend *onert_backend_create()
+{
+ VERBOSE(onert_backend_create) << "'acl_neon' loaded\n";
+ return new onert::backend::acl_neon::Backend;
+}
+
+void onert_backend_destroy(onert::backend::Backend *backend)
+{
+ VERBOSE(onert_backend_create) << "'acl_neon' unloaded\n";
+ delete backend;
+}
+}
diff --git a/runtime/onert/backend/acl_neon/operand/INETensor.cc b/runtime/onert/backend/acl_neon/operand/INETensor.cc
new file mode 100644
index 000000000..fddcff0f4
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/operand/INETensor.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "INETensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+namespace operand
+{
+
+void INETensor::access(const std::function<void(ITensor &tensor)> &fn)
+{
+ // This is an optional input
+ if (total_size() == 0)
+ return;
+
+ fn(*this);
+}
+
+} // namespace operand
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_neon/operand/INETensor.h b/runtime/onert/backend/acl_neon/operand/INETensor.h
new file mode 100644
index 000000000..db0ce6fdc
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/operand/INETensor.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_OPERAND_I_NE_TENSOR_H__
+#define __ONERT_BACKEND_ACL_NEON_OPERAND_I_NE_TENSOR_H__
+
+#include <arm_compute/core/ITensor.h>
+
+#include <IACLTensor.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+namespace operand
+{
+
+class INETensor : public acl_common::IACLTensor
+{
+public:
+ const arm_compute::ITensor *handle() const override = 0;
+ arm_compute::ITensor *handle() override = 0;
+ void access(const std::function<void(ITensor &tensor)> &fn) final;
+};
+
+} // namespace operand
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_OPERAND_I_NE_TENSOR_H__
diff --git a/runtime/onert/backend/acl_neon/operand/NESubTensor.cc b/runtime/onert/backend/acl_neon/operand/NESubTensor.cc
new file mode 100644
index 000000000..457addd55
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/operand/NESubTensor.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NESubTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+namespace operand
+{
+
+NESubTensor::NESubTensor(INETensor *parent, const arm_compute::TensorShape &tensor_shape,
+ const arm_compute::Coordinates &coords, size_t rank, bool extend_parent)
+ : _ne_sub_tensor(std::make_shared<arm_compute::SubTensor>(parent->handle(), tensor_shape,
+ coords, extend_parent)),
+ _rank{rank}
+{
+ // DO NOTHING
+}
+
+const arm_compute::SubTensor *NESubTensor::handle() const { return _ne_sub_tensor.get(); }
+
+arm_compute::SubTensor *NESubTensor::handle() { return _ne_sub_tensor.get(); }
+
+} // namespace operand
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_neon/operand/NESubTensor.h b/runtime/onert/backend/acl_neon/operand/NESubTensor.h
new file mode 100644
index 000000000..9944e4ba0
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/operand/NESubTensor.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_OPERAND_NE_SUB_TENSOR_H__
+#define __ONERT_BACKEND_ACL_NEON_OPERAND_NE_SUB_TENSOR_H__
+
+#include <arm_compute/runtime/SubTensor.h>
+#include "INETensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+namespace operand
+{
+
+class NESubTensor : public INETensor
+{
+public:
+ NESubTensor() = delete;
+
+public:
+ NESubTensor(INETensor *parent, const arm_compute::TensorShape &tensor_shape,
+ const arm_compute::Coordinates &coords, size_t rank, bool extend_parent = false);
+
+public:
+ size_t num_dimensions() const final { return _rank; }
+
+public:
+ const arm_compute::SubTensor *handle() const override;
+ arm_compute::SubTensor *handle() override;
+
+public:
+ // This method is used to prevent the use of memcpy for SubTensor
+ bool has_padding() const override { return true; }
+ bool is_subtensor() const final { return true; }
+
+private:
+ std::shared_ptr<arm_compute::SubTensor> _ne_sub_tensor;
+ size_t _rank;
+};
+
+} // namespace operand
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_OPERAND_NE_SUB_TENSOR_H__
diff --git a/runtime/onert/backend/acl_neon/operand/NETensor.cc b/runtime/onert/backend/acl_neon/operand/NETensor.cc
new file mode 100644
index 000000000..53dbb3021
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/operand/NETensor.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arm_compute/runtime/Memory.h>
+#include <arm_compute/runtime/MemoryRegion.h>
+#include "NETensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+namespace operand
+{
+
+NETensor::NETensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses)
+ : _ne_tensor(std::make_shared<arm_compute::Tensor>()), _rank{rank}, _num_uses{num_uses}
+{
+ allocator()->init(info);
+}
+
+const arm_compute::Tensor *NETensor::handle() const { return _ne_tensor.get(); }
+
+arm_compute::Tensor *NETensor::handle() { return _ne_tensor.get(); }
+
+arm_compute::TensorAllocator *NETensor::allocator() { return _ne_tensor->allocator(); }
+
+} // namespace operand
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/acl_neon/operand/NETensor.h b/runtime/onert/backend/acl_neon/operand/NETensor.h
new file mode 100644
index 000000000..0dd81afec
--- /dev/null
+++ b/runtime/onert/backend/acl_neon/operand/NETensor.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ACL_NEON_OPERAND_NE_TENSOR_H__
+#define __ONERT_BACKEND_ACL_NEON_OPERAND_NE_TENSOR_H__
+
+#include <arm_compute/core/TensorInfo.h>
+#include <arm_compute/runtime/Tensor.h>
+#include "arm_compute/runtime/TensorAllocator.h"
+#include "INETensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace acl_neon
+{
+namespace operand
+{
+
+class NETensor : public INETensor
+{
+public:
+ NETensor() = delete;
+
+public:
+ NETensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses);
+
+public:
+ size_t num_dimensions() const final { return _rank; }
+
+public:
+ const arm_compute::Tensor *handle() const override;
+ arm_compute::Tensor *handle() override;
+ size_t num_uses() const { return _num_uses; }
+
+public:
+ arm_compute::TensorAllocator *allocator();
+
+private:
+ std::shared_ptr<arm_compute::Tensor> _ne_tensor;
+ size_t _rank;
+ size_t _num_uses;
+};
+
+} // namespace operand
+} // namespace acl_neon
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ACL_NEON_OPERAND_NE_TENSOR_H__
diff --git a/runtime/onert/backend/cpu/Backend.h b/runtime/onert/backend/cpu/Backend.h
new file mode 100644
index 000000000..fc8574b26
--- /dev/null
+++ b/runtime/onert/backend/cpu/Backend.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_BACKEND_H__
+#define __ONERT_BACKEND_CPU_BACKEND_H__
+
+#include "BackendContext.h"
+#include "Config.h"
+#include "ConstantInitializer.h"
+#include "KernelGenerator.h"
+
+#include <backend/Backend.h>
+
+#include <memory>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+class Backend : public ::onert::backend::Backend
+{
+public:
+ Backend() : _config{std::make_shared<Config>()} {}
+
+ std::shared_ptr<IConfig> config() const override { return _config; }
+
+ std::unique_ptr<onert::backend::BackendContext>
+ newContext(const ir::Graph &graph, const std::shared_ptr<custom::IKernelBuilder> &kb,
+ bool) const override
+ {
+ const auto &operands = graph.operands();
+ const auto &operations = graph.operations();
+ auto context = std::make_unique<BackendContext>(this, &graph);
+ auto tr = std::make_shared<cpu_common::TensorRegistry>();
+ auto tb = std::make_shared<TensorBuilder>(tr);
+ context->tensor_registry = tr;
+ context->tensor_builder = tb;
+ context->constant_initializer = std::make_shared<ConstantInitializer>(operands, tr);
+ context->kernel_gen = std::make_shared<KernelGenerator>(operands, operations, tb, tr, kb,
+ context->external_context());
+ context->tensor_register = nullptr;
+ context->optimizer = nullptr;
+ return context;
+ }
+
+private:
+ std::shared_ptr<IConfig> _config;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_BACKEND_H__
diff --git a/runtime/onert/backend/cpu/BackendContext.h b/runtime/onert/backend/cpu/BackendContext.h
new file mode 100644
index 000000000..e90b21054
--- /dev/null
+++ b/runtime/onert/backend/cpu/BackendContext.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_BACKEND_CONTEXT_H__
+#define __ONERT_BACKEND_CPU_BACKEND_CONTEXT_H__
+
+#include <backend/BackendContext.h>
+#include "ExternalContext.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+class BackendContext : public onert::backend::BackendContext
+{
+public:
+ BackendContext(const Backend *backend, const ir::Graph *graph,
+ std::shared_ptr<ITensorRegistry> tensor_registry = nullptr,
+ std::shared_ptr<ITensorBuilder> tensor_builder = nullptr,
+ std::shared_ptr<IConstantInitializer> constant_initializer = nullptr,
+ std::shared_ptr<IKernelGenerator> kernel_gen = nullptr,
+ std::shared_ptr<ITensorRegister> tensor_register = nullptr,
+ std::shared_ptr<IOptimizer> optimizer = nullptr)
+ : onert::backend::BackendContext(backend, graph, tensor_registry, tensor_builder,
+ constant_initializer, kernel_gen, tensor_register,
+ optimizer),
+ _external_context(new ExternalContext)
+ {
+ }
+
+ std::shared_ptr<ExternalContext> external_context() { return _external_context; }
+
+private:
+ // NOTE ruy context has a thread pool, and when multiple ruy contexts are created,
+ // the thread pool is also created in duplicate
+ // TODO Create one ruy context for session
+ std::shared_ptr<ExternalContext> _external_context;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_BACKEND_CONTEXT_H__
diff --git a/runtime/onert/backend/cpu/CMakeLists.txt b/runtime/onert/backend/cpu/CMakeLists.txt
new file mode 100644
index 000000000..1e5443263
--- /dev/null
+++ b/runtime/onert/backend/cpu/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LIB_ONERT_BACKEND_CPU onert_backend_cpu)
+
+nnfw_find_package(Ruy REQUIRED)
+
+file(GLOB_RECURSE SOURCES "*.cc")
+
+add_library(${LIB_ONERT_BACKEND_CPU} SHARED ${SOURCES})
+
+target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE nnfw_lib_cker)
+target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE onert_core)
+target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE nnfw_common)
+target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE nnfw_coverage)
+target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE ruy)
+target_link_libraries(${LIB_ONERT_BACKEND_CPU} INTERFACE ruy_instrumentation)
+
+set_target_properties(${LIB_ONERT_BACKEND_CPU} PROPERTIES OUTPUT_NAME backend_cpu)
+
+if(CMAKE_BUILD_TYPE_LC STREQUAL "release")
+ add_custom_command(TARGET ${LIB_ONERT_BACKEND_CPU} POST_BUILD
+ COMMAND ${CMAKE_STRIP} "--strip-unneeded" $<TARGET_FILE_NAME:${LIB_ONERT_BACKEND_CPU}>)
+endif()
+
+install(TARGETS ${LIB_ONERT_BACKEND_CPU} DESTINATION lib)
diff --git a/runtime/onert/backend/cpu/Config.cc b/runtime/onert/backend/cpu/Config.cc
new file mode 100644
index 000000000..3ace47f5d
--- /dev/null
+++ b/runtime/onert/backend/cpu/Config.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Config.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+bool Config::initialize() { return true; }
+
+ir::Layout Config::supportLayout(const ir::Operation &, ir::Layout) { return ir::Layout::NHWC; }
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/Config.h b/runtime/onert/backend/cpu/Config.h
new file mode 100644
index 000000000..37e49581a
--- /dev/null
+++ b/runtime/onert/backend/cpu/Config.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_CONFIG_H__
+#define __ONERT_BACKEND_CPU_CONFIG_H__
+
+#include <backend/IConfig.h>
+#include <memory>
+#include <util/ITimer.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+class Config : public IConfig
+{
+public:
+ std::string id() override { return "cpu"; }
+ bool initialize() override;
+ ir::Layout supportLayout(const ir::Operation &node, ir::Layout frontend_layout) override;
+ bool supportPermutation() override { return true; }
+ bool supportDynamicTensor() override { return true; }
+ bool supportFP16() override { return false; }
+
+ std::unique_ptr<util::ITimer> timer() override { return std::make_unique<util::CPUTimer>(); }
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_CONFIG_H__
diff --git a/runtime/onert/backend/cpu/ConstantInitializer.cc b/runtime/onert/backend/cpu/ConstantInitializer.cc
new file mode 100644
index 000000000..6f6eb77bc
--- /dev/null
+++ b/runtime/onert/backend/cpu/ConstantInitializer.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConstantInitializer.h"
+#include "Tensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+ConstantInitializer::ConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg)
+ : IConstantInitializer{operands}, _tensor_reg{tensor_reg}
+{
+ // DO NOTHING
+}
+
+void ConstantInitializer::registerDefaultInitializer(const ir::OperandIndex &index,
+ const ir::Operand &obj)
+{
+ registerExternalInitializer(index, obj);
+}
+
+void ConstantInitializer::registerExternalInitializer(const ir::OperandIndex &index,
+ const ir::Operand &obj)
+{
+ // For only CONSTANTS
+ // TODO Add to check if tensor has been allocated
+ if (!obj.isConstant())
+ return;
+
+ _init_map[index] = [](const onert::ir::Operand &model_obj, onert::backend::ITensor &itensor) {
+ auto data = model_obj.shareData();
+ assert(data && data->base());
+ ExternalTensor &tensor = dynamic_cast<ExternalTensor &>(itensor);
+ tensor.setData(data);
+ };
+}
+
+void ConstantInitializer::visit(const ir::operation::Conv2D &node)
+{
+ const auto &kernel_index = node.getInputs().at(ir::operation::Conv2D::KERNEL);
+ const auto &kernel_obj = _operands.at(kernel_index);
+ registerExternalInitializer(kernel_index, kernel_obj);
+
+ const auto &bias_index = node.getInputs().at(ir::operation::Conv2D::BIAS);
+ const auto &bias_obj = _operands.at(bias_index);
+ registerExternalInitializer(bias_index, bias_obj);
+}
+
+void ConstantInitializer::visit(const ir::operation::DepthwiseConv2D &node)
+{
+ const auto &kernel_index = node.getInputs().at(ir::operation::DepthwiseConv2D::KERNEL);
+ const auto &kernel_obj = _operands.at(kernel_index);
+ registerExternalInitializer(kernel_index, kernel_obj);
+
+ const auto &bias_index = node.getInputs().at(ir::operation::DepthwiseConv2D::BIAS);
+ const auto &bias_obj = _operands.at(bias_index);
+ registerExternalInitializer(bias_index, bias_obj);
+}
+
+void ConstantInitializer::visit(const ir::operation::FullyConnected &node)
+{
+ const auto &weight_index = node.getInputs().at(ir::operation::FullyConnected::WEIGHT);
+ const auto &weight_obj = _operands.at(weight_index);
+ registerExternalInitializer(weight_index, weight_obj);
+
+ const auto &bias_index = node.getInputs().at(ir::operation::FullyConnected::BIAS);
+ if (!bias_index.undefined())
+ {
+ const auto &bias_obj = _operands.at(bias_index);
+ registerExternalInitializer(bias_index, bias_obj);
+ }
+}
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ConstantInitializer.h b/runtime/onert/backend/cpu/ConstantInitializer.h
new file mode 100644
index 000000000..c016c83bc
--- /dev/null
+++ b/runtime/onert/backend/cpu/ConstantInitializer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_CPU_CONSTANT_INITIALIZER_H__
+#define __ONERT_COMPILER_CPU_CONSTANT_INITIALIZER_H__
+
+#include "backend/cpu_common/TensorRegistry.h"
+
+#include <backend/IConstantInitializer.h>
+#include <ir/Operands.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+class ConstantInitializer : public IConstantInitializer
+{
+public:
+ ConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg);
+
+public:
+ void registerDefaultInitializer(const ir::OperandIndex &index, const ir::Operand &obj) override;
+
+ // TODO: For now the only cpu backend supports constant tensor to use data from external
+ // If the other backend supports (to do this,
+ // ExternalTensor should be abstract such as IExternal, maybe),
+ // this can be an interface of IConstantInitializer
+ void registerExternalInitializer(const ir::OperandIndex &, const ir::Operand &);
+
+public:
+ void visit(const ir::operation::Conv2D &) override;
+ void visit(const ir::operation::DepthwiseConv2D &) override;
+ void visit(const ir::operation::FullyConnected &) override;
+
+private:
+ std::shared_ptr<ITensorRegistry> tensor_registry() const override { return _tensor_reg; }
+
+private:
+ std::shared_ptr<ITensorRegistry> _tensor_reg;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_COMPILER_CPU_CONSTANT_INITIALIZER_H__
diff --git a/runtime/onert/backend/cpu/ExternalContext.h b/runtime/onert/backend/cpu/ExternalContext.h
new file mode 100644
index 000000000..32e249f5a
--- /dev/null
+++ b/runtime/onert/backend/cpu/ExternalContext.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_EXTERNAL_CONTEXT_H__
+#define __ONERT_BACKEND_CPU_EXTERNAL_CONTEXT_H__
+
+#include <backend/IExternalContext.h>
+#include <util/ConfigSource.h>
+#include <ruy/context.h>
+
+namespace
+{
+const int kDefaultNumThreadpoolThreads = 1;
+}
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+class ExternalContext : public IExternalContext
+{
+public:
+ ExternalContext() : _ruy_context(new ruy::Context)
+ {
+ setMaxNumThreads(onert::util::getConfigInt(onert::util::config::RUY_THREADS));
+ }
+
+ void setMaxNumThreads(int max_num_threads)
+ {
+ const int target_num_threads =
+ max_num_threads > -1 ? max_num_threads : kDefaultNumThreadpoolThreads;
+ _ruy_context->set_max_num_threads(target_num_threads);
+ }
+
+ ruy::Context *ruy_context() const { return _ruy_context.get(); }
+
+private:
+ const std::unique_ptr<ruy::Context> _ruy_context;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_EXTERNAL_CONTEXT_H__
diff --git a/runtime/onert/backend/cpu/KernelGenerator.cc b/runtime/onert/backend/cpu/KernelGenerator.cc
new file mode 100644
index 000000000..451815b65
--- /dev/null
+++ b/runtime/onert/backend/cpu/KernelGenerator.cc
@@ -0,0 +1,1499 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KernelGenerator.h"
+
+#include "ops/AddNLayer.h"
+#include "ops/ArgMinMaxLayer.h"
+#include "ops/BatchToSpaceNDLayer.h"
+#include "ops/BinaryArithmeticLayer.h"
+#include "ops/CompareLayer.h"
+#include "ops/ConcatLayer.h"
+#include "ops/ConvolutionLayer.h"
+#include "ops/DepthwiseConvolutionLayer.h"
+#include "ops/EinsumLayer.h"
+#include "ops/ElementwiseActivationLayer.h"
+#include "ops/ElementwiseBinaryLayer.h"
+#include "ops/ElementwiseUnaryLayer.h"
+#include "ops/ExpandDimsLayer.h"
+#include "ops/FillLayer.h"
+#include "ops/FullyConnectedLayer.h"
+#include "ops/GatherLayer.h"
+#include "ops/LSTMLayer.h"
+#include "ops/MeanLayer.h"
+#include "ops/OneHotLayer.h"
+#include "ops/OperationUtils.h"
+#include "ops/PackLayer.h"
+#include "ops/PadLayer.h"
+#include "ops/PoolLayer.h"
+#include "ops/PowLayer.h"
+#include "ops/RangeLayer.h"
+#include "ops/RankLayer.h"
+#include "ops/ReduceLayer.h"
+#include "ops/ReshapeLayer.h"
+#include "ops/ResizeBilinearLayer.h"
+#include "ops/ReverseLayer.h"
+#include "ops/SelectLayer.h"
+#include "ops/ShapeLayer.h"
+#include "ops/SliceLayer.h"
+#include "ops/SoftMaxLayer.h"
+#include "ops/StridedSliceLayer.h"
+#include "ops/SpaceToBatchNDLayer.h"
+#include "ops/SpaceToDepthLayer.h"
+#include "ops/SplitLayer.h"
+#include "ops/SplitVLayer.h"
+#include "ops/TileLayer.h"
+#include "ops/TransposeLayer.h"
+#include "ops/UnpackLayer.h"
+#include "ops/SquaredDiffLayer.h"
+#include "ops/L2NormLayer.h"
+#include "ops/MatrixBandPartLayer.h"
+#include "ops/BatchMatMulLayer.h"
+#include "ops/BroadcastToLayer.h"
+#include "ops/FusedBatchNormLayer.h"
+#include "ops/LogSoftMaxLayer.h"
+#include "ops/StatelessRandomUniformLayer.h"
+
+#include <backend/Backend.h>
+#include <backend/IConfig.h>
+#include <memory>
+#include <util/Utils.h>
+#include <util/logging.h>
+#include <exec/DynamicShapeInferer.h>
+
+#include <stdexcept>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+namespace
+{
+ops::ArithmeticType
+convertArithmeticType(ir::operation::BinaryArithmetic::ArithmeticType arithmetic_type_ir)
+{
+ switch (arithmetic_type_ir)
+ {
+ case ir::operation::BinaryArithmetic::ArithmeticType::ADD:
+ return ops::ArithmeticType::kAdd;
+ case ir::operation::BinaryArithmetic::ArithmeticType::SUB:
+ return ops::ArithmeticType::kSub;
+ case ir::operation::BinaryArithmetic::ArithmeticType::MUL:
+ return ops::ArithmeticType::kMul;
+ case ir::operation::BinaryArithmetic::ArithmeticType::DIV:
+ return ops::ArithmeticType::kDiv;
+ default:
+ throw std::runtime_error("cpu KernelGenerator : Not supported operation yet");
+ }
+}
+
+ops::ElementwiseActivationType
+convertElementwiseActivationType(ir::operation::ElementwiseActivation::Type type_ir)
+{
+ switch (type_ir)
+ {
+ case ir::operation::ElementwiseActivation::Type::LOGISTIC:
+ return ops::ElementwiseActivationType::kLogistic;
+ case ir::operation::ElementwiseActivation::Type::RELU:
+ return ops::ElementwiseActivationType::kReLU;
+ case ir::operation::ElementwiseActivation::Type::TANH:
+ return ops::ElementwiseActivationType::kTanh;
+ default:
+ throw std::runtime_error("cpu KernelGenerator : Not supported operation yet");
+ }
+}
+
+ops::ElementwiseBinaryType
+convertElementwiseBinaryType(ir::operation::ElementwiseBinary::ElementwiseBinaryType type_ir)
+{
+ switch (type_ir)
+ {
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR:
+ return ops::ElementwiseBinaryType::kLogicalOr;
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::MAX:
+ return ops::ElementwiseBinaryType::kMax;
+ case ir::operation::ElementwiseBinary::ElementwiseBinaryType::MIN:
+ return ops::ElementwiseBinaryType::kMin;
+ default:
+ throw std::runtime_error("cpu KernelGenerator : Not supported operation yet");
+ }
+}
+
+ops::ElementwiseUnaryType convertElementwiseUnaryType(ir::operation::ElementwiseUnary::Type type_ir)
+{
+ switch (type_ir)
+ {
+ case ir::operation::ElementwiseUnary::Type::ABS:
+ return ops::ElementwiseUnaryType::kAbs;
+ case ir::operation::ElementwiseUnary::Type::CAST:
+ return ops::ElementwiseUnaryType::kCast;
+ case ir::operation::ElementwiseUnary::Type::COS:
+ return ops::ElementwiseUnaryType::kCos;
+ case ir::operation::ElementwiseUnary::Type::DEQUANTIZE:
+ return ops::ElementwiseUnaryType::kDequantize;
+ case ir::operation::ElementwiseUnary::Type::ERF:
+ return ops::ElementwiseUnaryType::kErf;
+ case ir::operation::ElementwiseUnary::Type::EXP:
+ return ops::ElementwiseUnaryType::kExp;
+ case ir::operation::ElementwiseUnary::Type::FLOOR:
+ return ops::ElementwiseUnaryType::kFloor;
+ case ir::operation::ElementwiseUnary::Type::LOG:
+ return ops::ElementwiseUnaryType::kLog;
+ case ir::operation::ElementwiseUnary::Type::LOGICAL_NOT:
+ return ops::ElementwiseUnaryType::kLogicalNot;
+ case ir::operation::ElementwiseUnary::Type::NEG:
+ return ops::ElementwiseUnaryType::kNeg;
+ case ir::operation::ElementwiseUnary::Type::QUANTIZE:
+ return ops::ElementwiseUnaryType::kQuantize;
+ case ir::operation::ElementwiseUnary::Type::ROUND:
+ return ops::ElementwiseUnaryType::kRound;
+ case ir::operation::ElementwiseUnary::Type::RSQRT:
+ return ops::ElementwiseUnaryType::kRSqrt;
+ case ir::operation::ElementwiseUnary::Type::SIN:
+ return ops::ElementwiseUnaryType::kSin;
+ case ir::operation::ElementwiseUnary::Type::ZEROS_LIKE:
+ return ops::ElementwiseUnaryType::kZerosLike;
+ default:
+ throw std::runtime_error("cpu KernelGenerator : Not supported operation yet");
+ }
+}
+
+ops::PoolType convertPoolType(ir::operation::Pool2D::PoolType type_ir)
+{
+ switch (type_ir)
+ {
+ case ir::operation::Pool2D::PoolType::AVG:
+ return ops::PoolType::kAvg;
+ case ir::operation::Pool2D::PoolType::MAX:
+ return ops::PoolType::kMax;
+ default:
+ throw std::runtime_error("cpu KernelGenerator : Not supported operation yet");
+ }
+}
+
+ops::ReduceType convertReduceType(ir::operation::Reduce::ReduceType reduce_type_ir)
+{
+ switch (reduce_type_ir)
+ {
+ case ir::operation::Reduce::ReduceType::ALL:
+ return ops::ReduceType::kAll;
+ case ir::operation::Reduce::ReduceType::ANY:
+ return ops::ReduceType::kAny;
+ case ir::operation::Reduce::ReduceType::MAX:
+ return ops::ReduceType::kMax;
+ case ir::operation::Reduce::ReduceType::MIN:
+ return ops::ReduceType::kMin;
+ case ir::operation::Reduce::ReduceType::PROD:
+ return ops::ReduceType::kProd;
+ case ir::operation::Reduce::ReduceType::SUM:
+ return ops::ReduceType::kSum;
+ default:
+ throw std::runtime_error("cpu KernelGenerator : Not supported operation yet");
+ }
+}
+} // namespace
+
+KernelGenerator::KernelGenerator(
+ const ir::Operands &operands_ctx, const ir::Operations &operations_ctx,
+ const std::shared_ptr<TensorBuilder> &tensor_builder,
+ const std::shared_ptr<cpu_common::TensorRegistry> &tensor_reg,
+ const std::shared_ptr<backend::custom::IKernelBuilder> &kernel_builder,
+ const std::shared_ptr<ExternalContext> &external_context)
+ : _ctx(operands_ctx), _operations_ctx{operations_ctx}, _tensor_builder(tensor_builder),
+ _tensor_reg{tensor_reg}, _kernel_builder(kernel_builder),
+ _current_op_seq_layout(ir::Layout::UNKNOWN), _external_context(external_context)
+{
+ // DO NOTHING
+}
+
+void KernelGenerator::visit(const ir::operation::AddN &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+
+ std::vector<const IPortableTensor *> input_tensors;
+ for (auto &input_idx : node.getInputs())
+ input_tensors.emplace_back(_tensor_reg->getPortableTensor(input_idx));
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+
+ auto fn = std::make_unique<ops::AddNLayer>();
+
+ fn->configure(std::move(input_tensors), output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::OpSequence &op_seq)
+{
+ assert(!_return_fn_seq);
+ assert(_tensor_builder->dynamicTensorManager());
+ assert(_tensor_reg);
+
+ auto dyn_shape_inferer = std::make_shared<exec::DynamicShapeInferer>(_ctx, _tensor_reg);
+
+ _return_fn_seq = std::make_unique<exec::FunctionSequence>();
+
+ // Prepare to handle dynamic tensors later
+ auto dyn_ctx = std::make_shared<exec::FunctionSequence::DynamicTensorCtx>();
+ {
+ dyn_ctx->op_seq = &op_seq;
+ dyn_ctx->operations = &_operations_ctx;
+ dyn_ctx->dynamic_shape_inferer = std::move(dyn_shape_inferer);
+ dyn_ctx->dynamic_tensor_manager = _tensor_builder->dynamicTensorManager();
+
+ _return_fn_seq->dynamic_tensor_ctx(dyn_ctx);
+ }
+
+ _current_op_seq_layout = op_seq.getLayout();
+ for (const auto &operation_idx : op_seq.operations())
+ {
+ const auto &node = _operations_ctx.at(operation_idx);
+ node.accept(*this);
+ _return_fn_seq->append(releaseFunction());
+
+ for (const auto &ind : (node.getInputs() | ir::Remove::UNDEFINED) + node.getOutputs())
+ {
+ auto portable_tensor = _tensor_reg->getPortableTensor(ind);
+ if (portable_tensor)
+ {
+ assert(portable_tensor->layout() == ir::Layout::NHWC);
+ }
+
+ auto tensor = _tensor_reg->getNativeTensor(ind);
+ if (tensor)
+ {
+ tensor->increase_ref();
+ }
+ }
+ }
+}
+
+void KernelGenerator::visit(const ir::operation::Conv2D &node)
+{
+ using ir::operation::Conv2D;
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)};
+ const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)};
+
+ auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index);
+ auto ker_tensor = _tensor_reg->getPortableTensor(ker_index);
+ auto bias_tensor = _tensor_reg->getPortableTensor(bias_index);
+
+ const auto stride = node.param().stride;
+ const auto activation = node.param().activation;
+ const auto param_padding = node.param().padding;
+ const auto dilation = node.param().dilation;
+ auto fn = std::make_unique<ops::ConvolutionLayer>();
+
+ if (_ctx.at(ifm_index).info().isDynamic() || _ctx.at(ker_index).info().isDynamic())
+ {
+ fn->configure(ifm_tensor, ker_tensor, bias_tensor, param_padding.type, param_padding.param.left,
+ param_padding.param.right, param_padding.param.top, param_padding.param.bottom,
+ stride.horizontal, stride.vertical, dilation.width_factor, dilation.height_factor,
+ activation, ofm_tensor);
+
+ _return_fn = std::move(fn);
+ return;
+ }
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
+ const auto &ker_shape = _ctx.at(ker_index).shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+
+ const auto padding =
+ ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width, ker_height,
+ dilation.width_factor, dilation.height_factor);
+
+ fn->configure(ifm_tensor, ker_tensor, bias_tensor, param_padding.type, padding.left,
+ padding.right, padding.top, padding.bottom, stride.horizontal, stride.vertical,
+ dilation.width_factor, dilation.height_factor, activation, ofm_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::DepthwiseConv2D &node)
+{
+ using ir::operation::DepthwiseConv2D;
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(DepthwiseConv2D::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)};
+ const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)};
+
+ const auto stride = node.param().stride;
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ // Kernel format is [1, kernel_height, kernel_width, depth_out].
+ const auto &ker_shape = _ctx.at(ker_index).shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+ const auto dilation_width = node.param().dilation.width_factor;
+ const auto dilation_height = node.param().dilation.height_factor;
+ const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride,
+ ker_width, ker_height, dilation_width, dilation_height);
+ const auto multiplier = node.param().multiplier;
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index);
+ auto ker_tensor = _tensor_reg->getPortableTensor(ker_index);
+ auto bias_tensor = _tensor_reg->getPortableTensor(bias_index);
+
+ auto fn = std::make_unique<ops::DepthwiseConvolutionLayer>();
+
+ fn->configure(ifm_tensor, ker_tensor, bias_tensor, padding.left, padding.right, padding.top,
+ padding.bottom, stride.horizontal, stride.vertical, multiplier, dilation_width,
+ dilation_height, activation, ofm_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Concat &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ const auto rank = _ctx.at(ofm_index).shape().rank();
+ const auto axis = ops::getAxis(rank, node.param().axis, _current_op_seq_layout);
+
+ auto output_tensor = _tensor_reg->getPortableTensor(ofm_index);
+
+ std::vector<const IPortableTensor *> input_tensors;
+ for (auto &ifm_idx : node.getInputs())
+ input_tensors.emplace_back(_tensor_reg->getPortableTensor(ifm_idx));
+
+ auto fn = std::make_unique<ops::ConcatLayer>();
+
+ fn->configure(input_tensors, axis, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::BatchToSpaceND &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::BatchToSpaceND::INPUT)};
+ const auto block_size_index{node.getInputs().at(ir::operation::BatchToSpaceND::BLOCK_SIZE)};
+
+ auto output_alloc = _tensor_reg->getPortableTensor(output_index);
+ auto input_alloc = _tensor_reg->getPortableTensor(input_index);
+ auto block_size_alloc = _tensor_reg->getPortableTensor(block_size_index);
+
+ auto fn = std::make_unique<ops::BatchToSpaceNDLayer>();
+
+ IPortableTensor *crops_alloc = nullptr;
+ const auto NNApiInputs = 2;
+
+ if (node.getInputs().size() != NNApiInputs)
+ {
+ const auto crops_data_index{node.getInputs().at(ir::operation::BatchToSpaceND::CROPS_DATA)};
+ crops_alloc = _tensor_reg->getPortableTensor(crops_data_index);
+ }
+
+ fn->configure(input_alloc, output_alloc, block_size_alloc, crops_alloc);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Fill &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Fill::Input::INPUT)};
+ const auto value_index{node.getInputs().at(ir::operation::Fill::Input::VALUE)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto value_tensor = _tensor_reg->getPortableTensor(value_index);
+
+ auto fn = std::make_unique<ops::FillLayer>();
+
+ fn->configure(input_tensor, value_tensor, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::FullyConnected &node)
+{
+ using ir::operation::FullyConnected;
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)};
+ const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)};
+ const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)};
+ const auto activation = node.param().activation;
+ const auto weights_format = node.param().weights_format;
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto weight_tensor = _tensor_reg->getPortableTensor(weight_index);
+ auto bias_tensor = bias_index.undefined() ? nullptr : _tensor_reg->getPortableTensor(bias_index);
+
+ auto fn = std::make_unique<ops::FullyConnectedLayer>();
+
+ fn->configure(input_tensor, weight_tensor, bias_tensor, activation, weights_format, output_tensor,
+ _external_context);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Reshape &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Reshape::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ // optional 2nd input
+ IPortableTensor *shape_tensor = nullptr;
+
+ if (node.getInputs().size() == 2)
+ {
+ const auto shape_index{node.getInputs().at(ir::operation::Reshape::Input::SHAPE)};
+ shape_tensor = _tensor_reg->getPortableTensor(shape_index);
+ }
+
+ auto fn = std::make_unique<ops::ReshapeLayer>();
+
+ fn->configure(input_tensor, shape_tensor, output_tensor);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Squeeze &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Squeeze::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ // Squeeze can share same kernel with reshape
+ auto fn = std::make_unique<ops::ReshapeLayer>();
+
+ fn->configure(input_tensor, nullptr, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Softmax &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Softmax::Input::INPUT)};
+
+ const auto beta = node.param().beta;
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ auto fn = std::make_unique<ops::SoftMaxLayer>();
+
+ fn->configure(input_tensor, beta, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::BinaryArithmetic &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::BinaryArithmetic::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::BinaryArithmetic::Input::RHS)};
+
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ auto lhs_tensor = _tensor_reg->getPortableTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getPortableTensor(rhs_index);
+
+ auto fn = std::make_unique<ops::BinaryArithmeticLayer>();
+
+ fn->configure(lhs_tensor, rhs_tensor, ofm_tensor, activation,
+ convertArithmeticType(node.param().arithmetic_type));
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Comparison &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)};
+ const auto rhs_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)};
+
+ auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ auto lhs_tensor = _tensor_reg->getPortableTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getPortableTensor(rhs_index);
+
+ auto comparison_type = node.param().comparison_type;
+
+ auto fn = std::make_unique<ops::CompareLayer>();
+
+ fn->configure(lhs_tensor, rhs_tensor, comparison_type, ofm_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Gather &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)};
+ const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto indices_tensor = _tensor_reg->getPortableTensor(indices_index);
+
+ const auto backend_layout = output_tensor->layout();
+ UNUSED_RELEASE(backend_layout);
+
+ // NOTE The frontend layout and backend layout must be the same for this operation.
+ // If not the same, we have to add a stage(?) to perform permutation of output tensor. It
+ // is not not efficient even if it works well. If so, it would be better to set the
+ // layout of these backend tensors to the same layout.
+ // There is also one thing we have to think about. This operation depends on the layout of
+ // a model. For example, if a model in NHWC has this operation as output rank == 4, indices
+ // rank == 2 and axis == 2, this operation should work as the axis W and C, but the axis W
+ // and C are not sequential in NCHW. So the backend in NCHW cannot handle this case.
+ assert(backend_layout == input_tensor->layout());
+ assert(backend_layout == indices_tensor->layout());
+ const auto &input_shape = _ctx.at(input_index).shape();
+ UNUSED_RELEASE(input_shape);
+ assert(input_shape.rank() < 4 || _current_op_seq_layout == backend_layout);
+
+ const auto axis_raw = node.param().axis;
+ const auto axis_value = (axis_raw < 0 ? (input_shape.rank() + axis_raw) : axis_raw);
+
+ auto fn = std::make_unique<ops::GatherLayer>();
+
+ fn->configure(input_tensor, indices_tensor, output_tensor, axis_value);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::OneHot &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto indices_index{node.getInputs().at(ir::operation::OneHot::INDICES)};
+ const auto depth_index{node.getInputs().at(ir::operation::OneHot::Input::DEPTH)};
+ const auto onvalue_index{node.getInputs().at(ir::operation::OneHot::Input::ON_VALUE)};
+ const auto offvalue_index{node.getInputs().at(ir::operation::OneHot::Input::OFF_VALUE)};
+
+ const auto axis = node.param().axis;
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto indices_tensor = _tensor_reg->getPortableTensor(indices_index);
+ auto depth_tensor = _tensor_reg->getPortableTensor(depth_index);
+ auto onvalue_tensor = _tensor_reg->getPortableTensor(onvalue_index);
+ auto offvalue_tensor = _tensor_reg->getPortableTensor(offvalue_index);
+
+ assert(indices_tensor->data_type() == OperandType::INT32);
+ assert(axis <= static_cast<int>(indices_tensor->num_dimensions()));
+
+ auto fn = std::make_unique<ops::OneHotLayer>();
+
+ fn->configure(indices_tensor, depth_tensor, onvalue_tensor, offvalue_tensor, output_tensor, axis);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Einsum &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ std::vector<const IPortableTensor *> input_tensors;
+ for (auto &ifm_idx : node.getInputs())
+ input_tensors.emplace_back(_tensor_reg->getPortableTensor(ifm_idx));
+
+ const auto equation = node.param().equation;
+
+ auto fn = std::make_unique<ops::EinsumLayer>();
+
+ fn->configure(input_tensors, equation, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Custom &node)
+{
+ auto fill_op_info = [&](const ir::OperandIndexSequence &opSeq,
+ std::vector<custom::TypeInfo> &types,
+ std::vector<IPortableTensor *> &tensors) {
+ for (auto &idx : opSeq)
+ {
+ const auto &operand = _ctx.at(idx);
+ // TODO make sure using `_current_op_seq_layout` is correct for custom operations
+ types.emplace_back(custom::TypeInfo{operand.shape(), operand.typeInfo().type()});
+ auto in_tensor = _tensor_reg->getPortableTensor(idx);
+ tensors.emplace_back(in_tensor);
+ }
+ };
+
+ backend::custom::CustomKernelConfigParams params{};
+
+ fill_op_info(node.getInputs(), params.input_types, params.input_tensors);
+ fill_op_info(node.getOutputs(), params.output_types, params.output_tensors);
+
+ params.userdata = node.userdata().data;
+ params.userdata_size = node.userdata().size;
+
+ auto fn = _kernel_builder->buildKernel(node.id(), std::move(params));
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseActivation &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ElementwiseActivation::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ auto fn = std::make_unique<ops::ElementwiseActivationLayer>();
+
+ fn->configure(input_tensor, output_tensor, node.param().alpha, node.param().beta,
+ convertElementwiseActivationType(node.param().op_type));
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseBinary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::ElementwiseBinary::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::ElementwiseBinary::Input::RHS)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto lhs_tensor = _tensor_reg->getPortableTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getPortableTensor(rhs_index);
+
+ auto fn = std::make_unique<ops::ElementwiseBinaryLayer>();
+
+ fn->configure(lhs_tensor, rhs_tensor, output_tensor,
+ convertElementwiseBinaryType(node.param().op_type));
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::ElementwiseUnary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ElementwiseUnary::Input::INPUT)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ auto fn = std::make_unique<ops::ElementwiseUnaryLayer>();
+
+ fn->configure(input_tensor, output_tensor, convertElementwiseUnaryType(node.param().op_type));
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::ExpandDims &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ExpandDims::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::ExpandDims::Input::AXIS)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto axis_tensor = _tensor_reg->getPortableTensor(axis_index);
+
+ auto fn = std::make_unique<ops::ExpandDimsLayer>();
+
+ fn->configure(input_tensor, axis_tensor, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Pack &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ const auto rank = _ctx.at(ofm_index).shape().rank();
+ const auto axis = ops::getAxis(rank, node.param().axis, _current_op_seq_layout);
+
+ assert(-rank <= axis && axis < rank);
+
+ auto output_tensor = _tensor_reg->getPortableTensor(ofm_index);
+
+ std::vector<const IPortableTensor *> input_tensors;
+ for (auto &ifm_idx : node.getInputs())
+ input_tensors.emplace_back(_tensor_reg->getPortableTensor(ifm_idx));
+
+ auto fn = std::make_unique<ops::PackLayer>();
+
+ fn->configure(input_tensors, axis, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Unpack &node)
+{
+ const auto input_index{node.getInputs().at(0)};
+
+ const auto rank = _ctx.at(input_index).shape().rank();
+ const auto axis = ops::getAxis(rank, node.param().axis, _current_op_seq_layout);
+
+ assert(rank == 0 || (-rank <= axis && axis < rank));
+
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ std::vector<IPortableTensor *> output_tensors;
+ for (auto &output_idx : node.getOutputs())
+ output_tensors.emplace_back(_tensor_reg->getPortableTensor(output_idx));
+
+ auto fn = std::make_unique<ops::UnpackLayer>();
+
+ uint32_t axis_resolved = (axis < 0 ? axis + rank : axis);
+
+ fn->configure(input_tensor, axis_resolved, node.param().num, output_tensors);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Pad &node)
+{
+ const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)};
+ const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)};
+ const auto output_index{node.getOutputs().at(0)};
+ assert(_ctx.at(pad_index).data());
+
+ auto input = _tensor_reg->getPortableTensor(input_index);
+ auto output = _tensor_reg->getPortableTensor(output_index);
+ auto pad_rank = _ctx.at(pad_index).shape().dim(0);
+ auto pad_base = reinterpret_cast<const int32_t *>(_ctx.at(pad_index).data()->base());
+
+ auto fn = std::make_unique<ops::PadLayer>();
+
+ bool isPadV2 = node.getInputs().size() == 3 ? true : false;
+ const void *value = nullptr;
+
+ if (isPadV2)
+ {
+ const auto value_index{node.getInputs().at(ir::operation::Pad::Input::VALUE)};
+ value = reinterpret_cast<const void *>(_ctx.at(value_index).data()->base());
+ }
+
+ fn->configure(input, output, pad_base, pad_rank, value);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Transpose &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Transpose::Input::INPUT)};
+ const auto perm_index{node.getInputs().at(ir::operation::Transpose::Input::PERMUTATION)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto perm_tensor = _tensor_reg->getPortableTensor(perm_index);
+
+ auto fn = std::make_unique<ops::TransposeLayer>();
+
+ fn->configure(input_tensor, perm_tensor, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Reduce &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Reduce::Input::INPUT)};
+ const auto axes_index{node.getInputs().at(ir::operation::Reduce::Input::AXES)};
+
+ const auto keep_dims = node.param().keep_dims;
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto axes_tensor = _tensor_reg->getPortableTensor(axes_index);
+
+ if (node.param().reduce_type == ir::operation::Reduce::ReduceType::MEAN)
+ {
+ auto fn = std::make_unique<ops::MeanLayer>();
+
+ fn->configure(input_tensor, axes_tensor, output_tensor, keep_dims);
+
+ _return_fn = std::move(fn);
+ }
+ else
+ {
+ auto fn = std::make_unique<ops::ReduceLayer>();
+
+ const auto reduce_type = convertReduceType(node.param().reduce_type);
+ fn->configure(input_tensor, axes_tensor, output_tensor, reduce_type, keep_dims);
+
+ _return_fn = std::move(fn);
+ }
+}
+
+void KernelGenerator::visit(const ir::operation::Select &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto condition_index{node.getInputs().at(ir::operation::Select::Input::CONDITION)};
+ const auto true_index{node.getInputs().at(ir::operation::Select::Input::INPUT_TRUE)};
+ const auto false_index{node.getInputs().at(ir::operation::Select::Input::INPUT_FALSE)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto condition_tensor = _tensor_reg->getPortableTensor(condition_index);
+ auto true_tensor = _tensor_reg->getPortableTensor(true_index);
+ auto false_tensor = _tensor_reg->getPortableTensor(false_index);
+
+ auto fn = std::make_unique<ops::SelectLayer>();
+
+ fn->configure(condition_tensor, true_tensor, false_tensor, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Slice &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Slice::Input::INPUT)};
+ const auto begins_index{node.getInputs().at(ir::operation::Slice::Input::BEGINS)};
+ const auto sizes_index{node.getInputs().at(ir::operation::Slice::Input::SIZES)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto begins_tensor = _tensor_reg->getPortableTensor(begins_index);
+ auto sizes_tensor = _tensor_reg->getPortableTensor(sizes_index);
+
+ auto fn = std::make_unique<ops::SliceLayer>();
+
+ fn->configure(input_tensor, begins_tensor, sizes_tensor, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::StridedSlice &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)};
+ const auto starts_index{node.getInputs().at(ir::operation::StridedSlice::Input::STARTS)};
+ const auto ends_index{node.getInputs().at(ir::operation::StridedSlice::Input::ENDS)};
+ const auto strides_index{node.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto starts_tensor = _tensor_reg->getPortableTensor(starts_index);
+ auto ends_tensor = _tensor_reg->getPortableTensor(ends_index);
+ auto strides_tensor = _tensor_reg->getPortableTensor(strides_index);
+
+ auto begin_mask = node.param().begin_mask;
+ auto end_mask = node.param().end_mask;
+ auto shrink_axis_mask = node.param().shrink_axis_mask;
+
+ auto fn = std::make_unique<ops::StridedSliceLayer>();
+
+ fn->configure(input_tensor, starts_tensor, ends_tensor, strides_tensor, output_tensor, begin_mask,
+ end_mask, shrink_axis_mask);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Split &node)
+{
+ const auto num_splits = node.param().num_splits;
+ assert(num_splits == static_cast<int>(node.getOutputs().size()));
+
+ const auto input_idx{node.getInputs().at(ir::operation::Split::Input::INPUT)};
+ const auto axis_idx{node.getInputs().at(ir::operation::Split::Input::AXIS)};
+
+ auto in_tensor = _tensor_reg->getPortableTensor(input_idx);
+ auto axis_tensor = _tensor_reg->getPortableTensor(axis_idx);
+
+ std::vector<IPortableTensor *> out_tensors;
+ for (auto &output_idx : node.getOutputs())
+ out_tensors.emplace_back(_tensor_reg->getPortableTensor(output_idx));
+
+ auto fn = std::make_unique<ops::SplitLayer>();
+
+ fn->configure(in_tensor, axis_tensor, num_splits, out_tensors);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Shape &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::Shape::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index);
+
+ auto fn = std::make_unique<ops::ShapeLayer>();
+
+ fn->configure(ifm_tensor, ofm_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::ResizeBilinear &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ResizeBilinear::INPUT)};
+
+ auto align_corners = node.param().align_corners;
+ auto half_pixel_centers = node.param().half_pixel_centers;
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ auto fn = std::make_unique<ops::ResizeBilinearLayer>();
+
+ if (node.getInputs().size() == 1)
+ {
+ fn->configure(input_tensor, output_tensor, node.param().height_out, node.param().width_out,
+ align_corners, half_pixel_centers);
+ }
+ else
+ {
+ assert(node.getInputs().size() == 2);
+ const auto size_index{node.getInputs().at(ir::operation::ResizeBilinear::SIZE)};
+ auto size_tensor = _tensor_reg->getPortableTensor(size_index);
+ if (size_tensor->is_constant())
+ {
+ auto size_vec = _ctx.at(size_index).asVector<int32_t>();
+ const auto height_out = size_vec[0];
+ const auto width_out = size_vec[1];
+ fn->configure(input_tensor, output_tensor, height_out, width_out, align_corners,
+ half_pixel_centers);
+ }
+ else
+ {
+ fn->configure(input_tensor, output_tensor, size_tensor, align_corners, half_pixel_centers);
+ }
+ }
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Reverse &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Reverse::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::Reverse::AXIS)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto axis_tensor = _tensor_reg->getPortableTensor(axis_index);
+
+ auto fn = std::make_unique<ops::ReverseLayer>();
+
+ fn->configure(input_tensor, axis_tensor, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::ArgMax &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ArgMax::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::ArgMax::AXIS)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto axis_tensor = _tensor_reg->getPortableTensor(axis_index);
+
+ auto fn = std::make_unique<ops::ArgMinMaxLayer>();
+
+ fn->configure(input_tensor, output_tensor, axis_tensor, /* is_arg_max */ true);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Pool2D &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::Pool2D::Input::INPUT)};
+
+ const auto kh = node.param().kh;
+ const auto kw = node.param().kw;
+ const auto stride = node.param().stride;
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout);
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout);
+ const auto padding =
+ ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh);
+ const auto activation = node.param().activation;
+
+ auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index);
+
+ auto fn = std::make_unique<ops::PoolLayer>();
+
+ fn->configure(ifm_tensor, padding.left, padding.right, padding.top, padding.bottom,
+ stride.horizontal, stride.vertical, kw, kh, activation, ofm_tensor,
+ convertPoolType(node.param().op_type));
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Pow &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::Pow::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::Pow::RHS)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto lhs_tensor = _tensor_reg->getPortableTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getPortableTensor(rhs_index);
+
+ auto fn = std::make_unique<ops::PowLayer>();
+
+ fn->configure(lhs_tensor, rhs_tensor, ir::Activation::NONE, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::L2Normalization &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ auto output_alloc = _tensor_reg->getPortableTensor(output_index);
+ auto input_alloc = _tensor_reg->getPortableTensor(input_index);
+
+ auto fn = std::make_unique<ops::L2NormLayer>();
+
+ fn->configure(input_alloc, output_alloc);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Range &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto start_index{node.getInputs().at(ir::operation::Range::START)};
+ const auto limit_index{node.getInputs().at(ir::operation::Range::LIMIT)};
+ const auto delta_index{node.getInputs().at(ir::operation::Range::DELTA)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto start_tensor = _tensor_reg->getPortableTensor(start_index);
+ auto limit_tensor = _tensor_reg->getPortableTensor(limit_index);
+ auto delta_tensor = _tensor_reg->getPortableTensor(delta_index);
+
+ auto fn = std::make_unique<ops::RangeLayer>();
+
+ fn->configure(start_tensor, limit_tensor, delta_tensor, output_tensor);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Rank &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::Shape::Input::INPUT)};
+
+ auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index);
+
+ auto fn = std::make_unique<ops::RankLayer>();
+
+ fn->configure(ifm_tensor, ofm_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::SquaredDifference &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::RHS)};
+
+ auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ auto lhs_tensor = _tensor_reg->getPortableTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getPortableTensor(rhs_index);
+
+ auto fn = std::make_unique<ops::SqDiffLayer>();
+
+ fn->configure(lhs_tensor, rhs_tensor, ofm_tensor);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Tile &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Tile::INPUT)};
+ const auto multiples_index{node.getInputs().at(ir::operation::Tile::MULTIPLES)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto multiples_tensor = _tensor_reg->getPortableTensor(multiples_index);
+
+ auto fn = std::make_unique<ops::TileLayer>();
+
+ fn->configure(input_tensor, multiples_tensor, output_tensor);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::MatrixBandPart &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::MatrixBandPart::INPUT)};
+ const auto num_lower_index{node.getInputs().at(ir::operation::MatrixBandPart::NUM_LOWER_DIAG)};
+ const auto num_upper_index{node.getInputs().at(ir::operation::MatrixBandPart::NUM_UPPER_DIAG)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto num_lower_tensor = _tensor_reg->getPortableTensor(num_lower_index);
+ auto num_upper_tensor = _tensor_reg->getPortableTensor(num_upper_index);
+
+ auto fn = std::make_unique<ops::MatrixBandPartLayer>();
+
+ fn->configure(input_tensor, num_lower_tensor, num_upper_tensor, output_tensor);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::BatchMatMul &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::BatchMatMul::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::BatchMatMul::RHS)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto lhs_tensor = _tensor_reg->getPortableTensor(lhs_index);
+ auto rhs_tensor = _tensor_reg->getPortableTensor(rhs_index);
+
+ const auto adj_x = node.param().adj_x;
+ const auto adj_y = node.param().adj_y;
+
+ auto fn = std::make_unique<ops::BatchMatMulLayer>();
+
+ fn->configure(lhs_tensor, rhs_tensor, adj_x, adj_y, output_tensor);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::BroadcastTo &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::BroadcastTo::INPUT)};
+ const auto shape_index{node.getInputs().at(ir::operation::BroadcastTo::SHAPE)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto shape_tensor = _tensor_reg->getPortableTensor(shape_index);
+
+ auto fn = std::make_unique<ops::BroadcastToLayer>();
+
+ fn->configure(input_tensor, shape_tensor, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::FusedBatchNorm &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(ofm_index);
+ std::vector<const IPortableTensor *> input_tensors;
+ for (auto &ifm_idx : node.getInputs())
+ input_tensors.emplace_back(_tensor_reg->getPortableTensor(ifm_idx));
+
+ const auto epsilon = node.param().epsilon;
+ const auto is_training = node.param().is_training;
+ const auto data_format = node.param().data_format;
+
+ auto fn = std::make_unique<ops::FusedBatchNormLayer>();
+
+ fn->configure(input_tensors, epsilon, is_training, data_format, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::LogSoftmax &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::LogSoftmax::Input::INPUT)};
+
+ const auto beta = node.param().beta;
+ const auto axis = node.param().axis;
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ auto fn = std::make_unique<ops::LogSoftMaxLayer>();
+
+ fn->configure(input_tensor, beta, axis, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::SpaceToBatchND &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::SpaceToBatchND::INPUT)};
+ const auto block_shape_index{node.getInputs().at(ir::operation::SpaceToBatchND::BLOCK_SIZE)};
+ const auto padding_index{node.getInputs().at(ir::operation::SpaceToBatchND::PADDINGS)};
+
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto block_shape_tensor = _tensor_reg->getPortableTensor(block_shape_index);
+ auto padding_tensor = _tensor_reg->getPortableTensor(padding_index);
+
+ auto fn = std::make_unique<ops::SpaceToBatchNDLayer>();
+
+ fn->configure(input_tensor, block_shape_tensor, padding_tensor, output_tensor);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::SpaceToDepth &node)
+{
+ const auto input_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)};
+ const auto output_index{node.getOutputs().at(0)};
+ auto block_size = node.param().block_size;
+
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+
+ auto fn = std::make_unique<ops::SpaceToDepthLayer>();
+
+ fn->configure(input_tensor, block_size, output_tensor);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::StatelessRandomUniform &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto shape_index{node.getInputs().at(ir::operation::StatelessRandomUniform::SHAPE)};
+ const auto seed_index{node.getInputs().at(ir::operation::StatelessRandomUniform::SEED)};
+
+ auto output_alloc = _tensor_reg->getPortableTensor(output_index);
+ auto shape_alloc = _tensor_reg->getPortableTensor(shape_index);
+ auto seed_alloc = _tensor_reg->getPortableTensor(seed_index);
+
+ auto fn = std::make_unique<ops::StatelessRandomUniformLayer>();
+
+ fn->configure(shape_alloc, seed_alloc, output_alloc);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::SplitV &node)
+{
+ const auto num_splits = node.param().num_splits;
+ assert(num_splits == static_cast<int>(node.getOutputs().size()));
+
+ const auto input_idx{node.getInputs().at(ir::operation::SplitV::Input::INPUT)};
+ const auto size_splits{node.getInputs().at(ir::operation::SplitV::Input::SIZE_SPLITS)};
+ const auto split_dim{node.getInputs().at(ir::operation::SplitV::Input::SPLIT_DIM)};
+
+ auto in_tensor = _tensor_reg->getPortableTensor(input_idx);
+ auto in_size_splits = _tensor_reg->getPortableTensor(size_splits);
+ auto in_split_dim = _tensor_reg->getPortableTensor(split_dim);
+
+ std::vector<IPortableTensor *> out_tensors;
+ for (auto &output_idx : node.getOutputs())
+ out_tensors.emplace_back(_tensor_reg->getPortableTensor(output_idx));
+
+ auto fn = std::make_unique<ops::SplitVLayer>();
+
+ fn->configure(in_tensor, in_size_splits, in_split_dim, num_splits, out_tensors);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::LSTM &node)
+{
+ const auto scratch_buffer_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)};
+ const auto output_state_out_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)};
+ const auto cell_state_out_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)};
+ const auto output_index{node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)};
+
+ const auto input_index{node.getInputs().at(ir::operation::LSTM::Input::INPUT)};
+ const auto input_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)}; // optional
+ const auto input_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_FORGET_WEIGHTS)};
+ const auto input_to_cell_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_CELL_WEIGHTS)};
+ const auto input_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)};
+ const auto recurrent_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)}; // optional
+ const auto recurrent_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS)};
+ const auto recurrent_to_cell_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_CELL_WEIGHTS)};
+ const auto recurrent_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS)};
+ const auto cell_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_INPUT_WEIGHTS)}; // optional
+ const auto cell_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_FORGET_WEIGHTS)}; // optional
+ const auto cell_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_OUTPUT_WEIGHTS)}; // optional
+ const auto input_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_GATE_BIAS)};
+ const auto forget_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::FORGET_GATE_BIAS)};
+ const auto cell_gate_bias_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_BIAS)};
+ const auto output_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_GATE_BIAS)};
+ const auto projection_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_WEIGHTS)}; // optional
+ const auto projection_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_BIAS)}; // optional
+ const auto output_state_in_index{
+ node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_STATE_IN)};
+ const auto cell_state_in_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_STATE_IN)};
+ const auto time_major = node.param().time_major;
+
+ // NOTE The input_to_input_weights and the recurrent_to_input_weights do not exist in CIFG.
+ // has_input_to_input_weights && has_recurrent_to_input_weights: no CIFG
+ // !(has_input_to_input_weights && has_recurrent_to_input_weights): CIFG
+ // NOTE The cell_to_input_weights does not exist in non-peephole although regular LSTM(non-CIFG).
+ bool has_input_to_input_weights = _ctx.exist(input_to_input_weights_index) &&
+ (_ctx.at(input_to_input_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(input_to_input_weights_index).shape().dim(1) != 0);
+ bool has_recurrent_to_input_weights =
+ _ctx.exist(recurrent_to_input_weights_index) &&
+ (_ctx.at(recurrent_to_input_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(recurrent_to_input_weights_index).shape().dim(1) != 0);
+
+ // NOTE The cell_to_forget_weights and the cell_to_output_weights exist in peephole.
+ // But the cell_to_input_weights does not exist in regular CIFG although peephole.
+ // has_cell_to_forget_weights && has_cell_to_output_weights: peephole
+ // !(has_cell_to_forget_weights && has_cell_to_output_weights): no peephole
+ bool has_cell_to_forget_weights = _ctx.exist(cell_to_forget_weights_index) &&
+ _ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0;
+ bool has_cell_to_output_weights = _ctx.exist(cell_to_output_weights_index) &&
+ _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0;
+
+ bool has_input_gate_bias =
+ _ctx.exist(input_gate_bias_index) && _ctx.at(input_gate_bias_index).shape().dim(0);
+
+ bool has_projection_weights = _ctx.exist(projection_weights_index) &&
+ (_ctx.at(projection_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(projection_weights_index).shape().dim(1) != 0);
+ bool has_projection_bias =
+ _ctx.exist(projection_bias_index) && _ctx.at(projection_bias_index).shape().dim(0);
+
+ auto scratch_buffer_tensor = _ctx.exist(scratch_buffer_index)
+ ? _tensor_reg->getPortableTensor(scratch_buffer_index)
+ : nullptr; // optional
+ auto output_state_out_tensor = _ctx.exist(output_state_out_index)
+ ? _tensor_reg->getPortableTensor(output_state_out_index)
+ : nullptr; // optional
+ auto cell_state_out_tensor = _ctx.exist(cell_state_out_index)
+ ? _tensor_reg->getPortableTensor(cell_state_out_index)
+ : nullptr; // optional
+ auto output_tensor = _tensor_reg->getPortableTensor(output_index);
+
+ auto input_tensor = _tensor_reg->getPortableTensor(input_index);
+
+ auto input_to_input_weights_tensor =
+ has_input_to_input_weights ? _tensor_reg->getPortableTensor(input_to_input_weights_index)
+ : nullptr; // optional
+ auto input_to_forget_weights_tensor =
+ _tensor_reg->getPortableTensor(input_to_forget_weights_index);
+ auto input_to_cell_weights_tensor = _tensor_reg->getPortableTensor(input_to_cell_weights_index);
+ auto input_to_output_weights_tensor =
+ _tensor_reg->getPortableTensor(input_to_output_weights_index);
+ auto recurrent_to_input_weights_tensor =
+ has_recurrent_to_input_weights
+ ? _tensor_reg->getPortableTensor(recurrent_to_input_weights_index)
+ : nullptr; // optional
+ auto recurrent_to_forget_weights_tensor =
+ _tensor_reg->getPortableTensor(recurrent_to_forget_weights_index);
+ auto recurrent_to_cell_weights_tensor =
+ _tensor_reg->getPortableTensor(recurrent_to_cell_weights_index);
+ auto recurrent_to_output_weights_tensor =
+ _tensor_reg->getPortableTensor(recurrent_to_output_weights_index);
+
+ auto cell_to_input_weights_tensor = _tensor_reg->getPortableTensor(cell_to_input_weights_index);
+ auto cell_to_forget_weights_tensor =
+ has_cell_to_forget_weights ? _tensor_reg->getPortableTensor(cell_to_forget_weights_index)
+ : nullptr; // optional
+ auto cell_to_output_weights_tensor =
+ has_cell_to_output_weights ? _tensor_reg->getPortableTensor(cell_to_output_weights_index)
+ : nullptr; // optional
+
+ auto input_gate_bias_tensor =
+ has_input_gate_bias ? _tensor_reg->getPortableTensor(input_gate_bias_index) : nullptr;
+ auto forget_gate_bias_tensor = _tensor_reg->getPortableTensor(forget_gate_bias_index);
+ auto cell_gate_bias_tensor = _tensor_reg->getPortableTensor(cell_gate_bias_index);
+ auto output_gate_bias_tensor = _tensor_reg->getPortableTensor(output_gate_bias_index);
+ auto output_state_in_tensor = _tensor_reg->getPortableTensor(output_state_in_index);
+ auto cell_state_in_tensor = _tensor_reg->getPortableTensor(cell_state_in_index);
+
+ auto projection_weights_tensor = has_projection_weights
+ ? _tensor_reg->getPortableTensor(projection_weights_index)
+ : nullptr; // optional
+ auto projection_bias_tensor = has_projection_bias
+ ? _tensor_reg->getPortableTensor(projection_bias_index)
+ : nullptr; // optional
+
+ IPortableTensor *input_layer_norm_weights_tensor = nullptr;
+ IPortableTensor *forget_layer_norm_weights_tensor = nullptr;
+ IPortableTensor *cell_layer_norm_weights_tensor = nullptr;
+ IPortableTensor *output_layer_norm_weights_tensor = nullptr;
+ if (node.getInputs().size() == 24)
+ {
+ const auto input_layer_norm_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_LAYER_NORMALIZATION_WEIGHTS)};
+ const auto forget_layer_norm_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::FORGET_LAYER_NORMALIZATION_WEIGHTS)};
+ const auto cell_layer_norm_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_LAYER_NORMALIZATION_WEIGHTS)};
+ const auto output_layer_norm_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_LAYER_NORMALIZATION_WEIGHTS)};
+
+ input_layer_norm_weights_tensor =
+ _tensor_reg->getPortableTensor(input_layer_norm_weights_index);
+ forget_layer_norm_weights_tensor =
+ _tensor_reg->getPortableTensor(forget_layer_norm_weights_index);
+ cell_layer_norm_weights_tensor = _tensor_reg->getPortableTensor(cell_layer_norm_weights_index);
+ output_layer_norm_weights_tensor =
+ _tensor_reg->getPortableTensor(output_layer_norm_weights_index);
+ }
+
+ auto fn = std::make_unique<ops::LSTMLayer>();
+
+ fn->configure(
+ input_tensor, input_to_input_weights_tensor, input_to_forget_weights_tensor,
+ input_to_cell_weights_tensor, input_to_output_weights_tensor,
+ recurrent_to_input_weights_tensor, recurrent_to_forget_weights_tensor,
+ recurrent_to_cell_weights_tensor, recurrent_to_output_weights_tensor,
+ cell_to_input_weights_tensor, cell_to_forget_weights_tensor, cell_to_output_weights_tensor,
+ input_layer_norm_weights_tensor, forget_layer_norm_weights_tensor,
+ cell_layer_norm_weights_tensor, output_layer_norm_weights_tensor,
+ /*aux_input=*/nullptr,
+ /*aux_input_to_input_weights=*/nullptr,
+ /*aux_input_to_forget_weights=*/nullptr,
+ /*aux_input_to_cell_weights=*/nullptr,
+ /*aux_input_to_output_weights=*/nullptr, input_gate_bias_tensor, forget_gate_bias_tensor,
+ cell_gate_bias_tensor, output_gate_bias_tensor, projection_weights_tensor,
+ projection_bias_tensor, output_state_in_tensor, cell_state_in_tensor, node.param(),
+ /*forward_sequence=*/true, time_major,
+ /*output_offset=*/0, scratch_buffer_tensor, output_state_out_tensor, cell_state_out_tensor,
+ output_tensor,
+ !_ctx.at(output_state_in_index).info().isVariable() /* means empty buffer on frontend now */,
+ !_ctx.at(cell_state_in_index).info().isVariable());
+
+ _return_fn = std::move(fn);
+}
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/KernelGenerator.h b/runtime/onert/backend/cpu/KernelGenerator.h
new file mode 100644
index 000000000..5df77607f
--- /dev/null
+++ b/runtime/onert/backend/cpu/KernelGenerator.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_KERNEL_GENERATOR_H__
+#define __ONERT_BACKEND_CPU_KERNEL_GENERATOR_H__
+
+#include "ExternalContext.h"
+#include "TensorBuilder.h"
+#include "backend/cpu_common/TensorRegistry.h"
+#include "Tensor.h"
+
+#include <backend/CustomKernelBuilder.h>
+#include <backend/IKernelGenerator.h>
+#include <ir/Operands.h>
+#include <ir/Operations.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+class KernelGenerator : public IKernelGenerator
+{
+public:
+ KernelGenerator(const ir::Operands &operands_ctx, const ir::Operations &operations_ctx,
+ const std::shared_ptr<TensorBuilder> &tensor_builder,
+ const std::shared_ptr<cpu_common::TensorRegistry> &tensor_reg,
+ const std::shared_ptr<custom::IKernelBuilder> &kernel_builder,
+ const std::shared_ptr<ExternalContext> &external_context);
+
+ using IKernelGenerator::visit;
+
+ void visit(const ir::operation::AddN &) override;
+ void visit(const ir::OpSequence &) override;
+ void visit(const ir::operation::Conv2D &) override;
+ void visit(const ir::operation::DepthwiseConv2D &) override;
+ void visit(const ir::operation::Concat &) override;
+ void visit(const ir::operation::Fill &) override;
+ void visit(const ir::operation::FullyConnected &) override;
+ void visit(const ir::operation::Reshape &) override;
+ void visit(const ir::operation::Squeeze &) override;
+ void visit(const ir::operation::Softmax &) override;
+ void visit(const ir::operation::Comparison &) override;
+ void visit(const ir::operation::BinaryArithmetic &) override;
+ void visit(const ir::operation::Einsum &) override;
+ void visit(const ir::operation::Gather &) override;
+ void visit(const ir::operation::Custom &node) override;
+ void visit(const ir::operation::ElementwiseActivation &) override;
+ void visit(const ir::operation::ElementwiseBinary &) override;
+ void visit(const ir::operation::ElementwiseUnary &) override;
+ void visit(const ir::operation::ExpandDims &) override;
+ void visit(const ir::operation::LSTM &) override;
+ void visit(const ir::operation::Pad &) override;
+ void visit(const ir::operation::Pack &) override;
+ void visit(const ir::operation::Unpack &) override;
+ void visit(const ir::operation::OneHot &) override;
+ void visit(const ir::operation::Transpose &) override;
+ void visit(const ir::operation::Reduce &) override;
+ void visit(const ir::operation::Select &) override;
+ void visit(const ir::operation::Slice &) override;
+ void visit(const ir::operation::StridedSlice &) override;
+ void visit(const ir::operation::Split &) override;
+ void visit(const ir::operation::Shape &) override;
+ void visit(const ir::operation::ResizeBilinear &node) override;
+ void visit(const ir::operation::Reverse &) override;
+ void visit(const ir::operation::ArgMax &) override;
+ void visit(const ir::operation::Pool2D &) override;
+ void visit(const ir::operation::Pow &) override;
+ void visit(const ir::operation::SquaredDifference &) override;
+ void visit(const ir::operation::Tile &) override;
+ void visit(const ir::operation::L2Normalization &) override;
+ void visit(const ir::operation::Range &) override;
+ void visit(const ir::operation::Rank &) override;
+ void visit(const ir::operation::MatrixBandPart &) override;
+ void visit(const ir::operation::BatchMatMul &) override;
+ void visit(const ir::operation::BatchToSpaceND &) override;
+ void visit(const ir::operation::BroadcastTo &) override;
+ void visit(const ir::operation::FusedBatchNorm &) override;
+ void visit(const ir::operation::LogSoftmax &) override;
+ void visit(const ir::operation::SpaceToBatchND &) override;
+ void visit(const ir::operation::SpaceToDepth &) override;
+ void visit(const ir::operation::StatelessRandomUniform &) override;
+ void visit(const ir::operation::SplitV &) override;
+
+private:
+ const ir::Operands &_ctx;
+ const ir::Operations &_operations_ctx;
+ std::shared_ptr<TensorBuilder> _tensor_builder;
+ std::shared_ptr<cpu_common::TensorRegistry> _tensor_reg;
+ std::shared_ptr<backend::custom::IKernelBuilder> _kernel_builder;
+ ir::Layout _current_op_seq_layout;
+ const std::shared_ptr<ExternalContext> _external_context;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_KERNEL_GENERATOR_H__
diff --git a/runtime/onert/backend/cpu/StaticTensorManager.cc b/runtime/onert/backend/cpu/StaticTensorManager.cc
new file mode 100644
index 000000000..3edac897c
--- /dev/null
+++ b/runtime/onert/backend/cpu/StaticTensorManager.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "StaticTensorManager.h"
+#include "Tensor.h"
+
+#include <util/logging.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+StaticTensorManager::StaticTensorManager(const std::shared_ptr<cpu_common::TensorRegistry> &reg,
+ cpu_common::DynamicTensorManager *dynamic_tensor_manager)
+ : _nonconst_mgr{new cpu_common::MemoryManager()}, _tensors{reg},
+ _dynamic_tensor_manager{dynamic_tensor_manager}
+{
+ // DO NOTHING
+}
+
+void StaticTensorManager::allocateNonconsts(void)
+{
+ _nonconst_mgr->allocate();
+
+ for (auto &pair : _tensors->native_tensors())
+ {
+ const auto &ind = pair.first;
+ auto tensor = pair.second.get();
+ if (!_as_constants[ind] && !tensor->is_dynamic())
+ {
+ auto *buffer = _nonconst_mgr->getBuffer(ind);
+ tensor->setBuffer(buffer);
+
+ VERBOSE(CPU_StaticTensorManager) << "TENSOR(#" << ind.value()
+ << "): " << static_cast<void *>(buffer) << std::endl;
+ }
+ }
+}
+
+void StaticTensorManager::deallocateNonconsts(void) { _nonconst_mgr->deallocate(); }
+
+void StaticTensorManager::buildTensor(const ir::OperandIndex &ind,
+ const ir::OperandInfo &tensor_info, ir::Layout backend_layout,
+ bool as_const)
+{
+ assert(!_tensors->getITensor(ind));
+ if (as_const)
+ {
+ auto tensor = std::make_unique<ExternalTensor>(tensor_info, backend_layout);
+ _tensors->setNativeTensor(ind, std::move(tensor));
+ }
+ else
+ {
+ auto tensor = std::make_unique<Tensor>(tensor_info, backend_layout,
+ _dynamic_tensor_manager->dynamic_mem_mgr().get());
+ _tensors->setNativeTensor(ind, std::move(tensor));
+ }
+ _as_constants[ind] = as_const;
+}
+
+void StaticTensorManager::claimPlan(const ir::OperandIndex &ind, uint32_t size)
+{
+ assert(_tensors->getITensor(ind));
+
+ // This method is called only when a tensor has proper shape
+ assert(!_tensors->getITensor(ind)->is_dynamic());
+
+ if (!_as_constants[ind])
+ _nonconst_mgr->claimPlan(ind, size);
+}
+
+void StaticTensorManager::releasePlan(const ir::OperandIndex &ind)
+{
+ assert(_tensors->getITensor(ind));
+
+ // This method is called only when a tensor has proper shape
+ assert(!_tensors->getITensor(ind)->is_dynamic());
+
+ if (!_as_constants[ind])
+ _nonconst_mgr->releasePlan(ind);
+}
+
+void StaticTensorManager::iterate(const std::function<void(const ir::OperandIndex &)> &fn)
+{
+ for (const auto &it : _tensors->native_tensors())
+ fn(it.first);
+}
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/StaticTensorManager.h b/runtime/onert/backend/cpu/StaticTensorManager.h
new file mode 100644
index 000000000..2af61e4e7
--- /dev/null
+++ b/runtime/onert/backend/cpu/StaticTensorManager.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_STATICTENSOR_MANAGER_H__
+#define __ONERT_BACKEND_CPU_STATICTENSOR_MANAGER_H__
+
+#include "backend/IStaticTensorManager.h"
+#include "backend/cpu_common/DynamicTensorManager.h"
+#include "backend/cpu_common/MemoryManager.h"
+#include "backend/cpu_common/TensorRegistry.h"
+#include "backend/ITensorManager.h"
+#include "ir/OperandIndexMap.h"
+#include "ir/OperandInfo.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+class StaticTensorManager : public backend::IStaticTensorManager
+{
+public:
+ StaticTensorManager(const std::shared_ptr<cpu_common::TensorRegistry> &reg,
+ cpu_common::DynamicTensorManager *dynamic_tensor_manager);
+ virtual ~StaticTensorManager() = default;
+
+ void allocateNonconsts(void);
+ void deallocateNonconsts(void);
+
+ void buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &tensor_info,
+ ir::Layout backend_layout, bool as_const);
+
+ void claimPlan(const ir::OperandIndex &ind, uint32_t size);
+ void releasePlan(const ir::OperandIndex &ind);
+
+ void iterate(const std::function<void(const ir::OperandIndex &)> &fn);
+
+private:
+ std::unique_ptr<cpu_common::MemoryManager> _nonconst_mgr;
+ const std::shared_ptr<cpu_common::TensorRegistry> _tensors;
+ ir::OperandIndexMap<bool> _as_constants;
+ cpu_common::DynamicTensorManager *_dynamic_tensor_manager;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_STATICTENSOR_MANAGER_H__
diff --git a/runtime/onert/backend/cpu/Tensor.cc b/runtime/onert/backend/cpu/Tensor.cc
new file mode 100644
index 000000000..dac8f898b
--- /dev/null
+++ b/runtime/onert/backend/cpu/Tensor.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Tensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+// `dynamic_cast` not working across library boundaries on NDK
+// With this as a key function, `dynamic_cast` works across dl
+ExternalTensor::~ExternalTensor() {}
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/Tensor.h b/runtime/onert/backend/cpu/Tensor.h
new file mode 100644
index 000000000..2ad2ad0fb
--- /dev/null
+++ b/runtime/onert/backend/cpu/Tensor.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_TENSOR_H__
+#define __ONERT_BACKEND_CPU_TENSOR_H__
+
+#include <backend/cpu_common/Tensor.h>
+#include <ir/Data.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+using Tensor = cpu_common::Tensor;
+
+/**
+ * @brief Class that uses data from external memory that is not managed by a backend
+ * instead of allocating and copying the data. ExternalTensor's data pointer points to
+ * an address of memory such as where memory is already allocated, or mmapped area.
+ * This is meaning that ExternalTensor can take all of types' ir::Data.
+ * To support this, assume below things no padding, always NHWC layout,
+ * constant tensor and not dynamic.
+ */
+class ExternalTensor : public Tensor
+{
+public:
+ ExternalTensor() = delete;
+ virtual ~ExternalTensor();
+
+public:
+ ExternalTensor(const ir::OperandInfo &info, const ir::Layout layout)
+ : Tensor(info, layout, nullptr)
+ {
+ assert(_layout == ir::Layout::NHWC);
+ assert(_info.isConstant());
+ assert(_info.isDynamic() == false);
+ }
+
+public:
+ /**
+ * @brief set Data to be shared from external so that this ExternalTensor will not be
+ * allocated on CPU backend
+ * @param[in] data data of Operand to be set
+ */
+ void setData(const std::shared_ptr<ir::Data> data)
+ {
+ assert(data != nullptr);
+ _data = data;
+ // Note. Some op such as cker::Conv could take buffer as nullptr.
+ // That's why _buffer also would be used
+ _buffer = const_cast<uint8_t *>(_data->base());
+ }
+
+public:
+ uint8_t *buffer() const override { return _buffer; }
+
+ bool is_constant() const override { return true; }
+ bool is_dynamic() const override { return false; }
+ void set_dynamic() override
+ {
+ throw std::runtime_error("This tensor does not support changing dynamic");
+ }
+
+ void setShape(const ir::Shape &) override
+ {
+ throw std::runtime_error("This tensor does not support changing shape");
+ }
+
+ void increase_ref() override { ++_num_references; }
+
+ void decrease_ref() override
+ {
+ assert(_data != nullptr);
+ assert(_num_references > 0);
+ --_num_references;
+ if (_num_references == 0)
+ {
+ _data.reset();
+ _buffer = nullptr;
+ }
+ }
+
+ /**
+ * @brief Reset reference count to zero and release data
+ */
+ void reset_ref() override
+ {
+ assert(_data != nullptr);
+ assert(_num_references > 0);
+ _num_references = 0;
+
+ _data.reset();
+ _buffer = nullptr;
+ }
+
+ int32_t num_references() override { return _num_references; }
+
+private:
+ std::shared_ptr<const ir::Data> _data;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_TENSOR_H__
diff --git a/runtime/onert/backend/cpu/TensorBuilder.cc b/runtime/onert/backend/cpu/TensorBuilder.cc
new file mode 100644
index 000000000..e6bc55b0b
--- /dev/null
+++ b/runtime/onert/backend/cpu/TensorBuilder.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TensorBuilder.h"
+
+#include <util/logging.h>
+
+#include <cassert>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+TensorBuilder::TensorBuilder(const std::shared_ptr<cpu_common::TensorRegistry> &tensor_reg)
+ : _tensor_reg{tensor_reg},
+ _dynamic_tensor_mgr{new cpu_common::DynamicTensorManager(_tensor_reg)},
+ _static_tensor_mgr{new StaticTensorManager(_tensor_reg, _dynamic_tensor_mgr.get())}
+{
+ /* empty */
+}
+
+void TensorBuilder::registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
+ ir::Layout layout)
+{
+ _tensor_info_map.emplace(ind, info);
+
+ // CPU backend supports only one layout as NHWC
+ assert(layout == ir::Layout::NHWC);
+ if (info.isDynamic())
+ {
+ _dynamic_tensor_mgr->buildTensor(ind, info, layout);
+ }
+ else
+ {
+ _static_tensor_mgr->buildTensor(ind, info, layout, info.isConstant());
+ }
+}
+
+void TensorBuilder::notifyFirstUse(const ir::OperandIndex &ind)
+{
+ assert(_tensor_info_map.find(ind) != _tensor_info_map.end());
+ const auto tensor_info = _tensor_info_map.at(ind);
+
+ if (!_tensor_reg->getNativeTensor(ind)->is_dynamic())
+ {
+ const auto size = tensor_info.total_size();
+ _static_tensor_mgr->claimPlan(ind, size);
+ }
+}
+
+void TensorBuilder::notifyLastUse(const ir::OperandIndex &ind)
+{
+ if (!_tensor_reg->getNativeTensor(ind)->is_dynamic())
+ {
+ _static_tensor_mgr->releasePlan(ind);
+ }
+}
+
+bool TensorBuilder::isRegistered(const ir::OperandIndex &ind) const
+{
+ return _tensor_info_map.find(ind) != _tensor_info_map.end();
+}
+
+void TensorBuilder::prepare(void) { _static_tensor_mgr->allocateNonconsts(); }
+
+void TensorBuilder::allocate()
+{
+ // NOTE For now nothing to do. Allocation is done in prepare stage, which is not appropriate
+ // This is because CPU kernels require `ITensor`s to be allocated before Kernel Generation.
+}
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/TensorBuilder.h b/runtime/onert/backend/cpu/TensorBuilder.h
new file mode 100644
index 000000000..448abc229
--- /dev/null
+++ b/runtime/onert/backend/cpu/TensorBuilder.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_TENSOR_BUILDER_H__
+#define __ONERT_BACKEND_CPU_TENSOR_BUILDER_H__
+
+#include <backend/cpu_common/DynamicTensorManager.h>
+#include <backend/cpu_common/TensorRegistry.h>
+
+#include <backend/ITensorBuilder.h>
+#include <ir/OperandIndexMap.h>
+
+#include "StaticTensorManager.h"
+#include "Tensor.h"
+
+#include <unordered_map>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+
+class TensorBuilder : public ITensorBuilder
+{
+public:
+ TensorBuilder(const std::shared_ptr<cpu_common::TensorRegistry> &tensor_reg);
+
+ /**
+ * @brief Register tensor information to allocate on CPU backend
+ * @param[in] ind Operand index
+ * @param[in] info Operand information
+ * @param[in] layout Operand data layout
+ */
+ void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
+ ir::Layout backend_layout) override;
+
+ void notifyFirstUse(const ir::OperandIndex &) override;
+ void notifyLastUse(const ir::OperandIndex &) override;
+
+ bool isRegistered(const ir::OperandIndex &) const override;
+
+ void prepare(void) override;
+ void allocate() override;
+ void postFunctionPrepare() override { /* DO NOTHING */}
+
+ IDynamicTensorManager *dynamicTensorManager(void) override { return _dynamic_tensor_mgr.get(); }
+
+private:
+ const std::shared_ptr<cpu_common::TensorRegistry> _tensor_reg;
+ std::unique_ptr<cpu_common::DynamicTensorManager> _dynamic_tensor_mgr;
+ std::unique_ptr<StaticTensorManager> _static_tensor_mgr;
+ ir::OperandIndexMap<ir::OperandInfo> _tensor_info_map;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_TENSOR_BUILDER_H__
diff --git a/runtime/onert/backend/cpu/cpu.cc b/runtime/onert/backend/cpu/cpu.cc
new file mode 100644
index 000000000..5385bb2a3
--- /dev/null
+++ b/runtime/onert/backend/cpu/cpu.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Backend.h"
+
+#include <util/logging.h>
+
+extern "C" {
+onert::backend::Backend *onert_backend_create()
+{
+ VERBOSE(onert_backend_create) << "'cpu' loaded\n";
+ return new onert::backend::cpu::Backend;
+}
+
+void onert_backend_destroy(onert::backend::Backend *backend)
+{
+ VERBOSE(onert_backend_create) << "'cpu' unloaded\n";
+ delete backend;
+}
+}
diff --git a/runtime/onert/backend/cpu/ops/AddNLayer.cc b/runtime/onert/backend/cpu/ops/AddNLayer.cc
new file mode 100644
index 000000000..5c0395dcc
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/AddNLayer.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AddNLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/AddN.h>
+#include <assert.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+void AddNLayer::configure(std::vector<const IPortableTensor *> &&inputs, IPortableTensor *output)
+{
+ _inputs = std::move(inputs);
+ _output = output;
+}
+
+void AddNLayer::run()
+{
+ size_t input_size = _inputs.size();
+ if (_output->data_type() == ir::DataType::INT32)
+ {
+ std::vector<const int32_t *> input_buffers(input_size);
+ for (size_t i = 0; i < input_size; i++)
+ {
+ input_buffers[i] = reinterpret_cast<int32_t *>(_inputs[i]->buffer());
+ }
+ AddN(getTensorShape(_inputs[0]), input_size, input_buffers.data(),
+ reinterpret_cast<int32_t *>(_output->buffer()));
+ }
+ else if (_output->data_type() == ir::DataType::FLOAT32)
+ {
+ std::vector<const float *> input_buffers(input_size);
+ for (size_t i = 0; i < input_size; i++)
+ {
+ input_buffers[i] = reinterpret_cast<float *>(_inputs[i]->buffer());
+ }
+ AddN(getTensorShape(_inputs[0]), input_size, input_buffers.data(),
+ reinterpret_cast<float *>(_output->buffer()));
+ }
+ else
+ {
+ throw std::runtime_error("AddN: unsupported data type");
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/AddNLayer.h b/runtime/onert/backend/cpu/ops/AddNLayer.h
new file mode 100644
index 000000000..b7639d149
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/AddNLayer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_ADDNLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_ADDNLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class AddNLayer : public ::onert::exec::IFunction
+{
+public:
+ AddNLayer() : _inputs(), _output(nullptr) {}
+
+public:
+ void configure(std::vector<const IPortableTensor *> &&inputs, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ std::vector<const IPortableTensor *> _inputs;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_ADDNLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ArgMinMaxLayer.cc b/runtime/onert/backend/cpu/ops/ArgMinMaxLayer.cc
new file mode 100644
index 000000000..2fd284c91
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ArgMinMaxLayer.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ArgMinMaxLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/ArgMinMax.h>
+#include <assert.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+namespace
+{
+template <typename T> std::function<bool(T, T)> GetComparefunction(bool is_arg_max)
+{
+ if (is_arg_max)
+ {
+ return std::greater<T>();
+ }
+ else
+ {
+ return std::less<T>();
+ }
+}
+}
+
+void ArgMinMaxLayer::configure(const IPortableTensor *input, IPortableTensor *output,
+ const IPortableTensor *axis, bool is_arg_max)
+{
+ _input = input;
+ _output = output;
+ _axis = axis;
+ _is_arg_max = is_arg_max;
+}
+
+void ArgMinMaxLayer::run()
+{
+ if (_axis->total_size() != sizeof(int32_t))
+ {
+ throw std::runtime_error("ArgMinMax: wrong shape of axis");
+ }
+ auto axis = *reinterpret_cast<const int32_t *>(_axis->buffer());
+ if (axis < 0)
+ {
+ axis += _input->num_dimensions();
+ }
+#define TF_LITE_ARG_MIN_MAX(input_type, axis_type, output_type) \
+ ArgMinMax(getTensorShape(_input), reinterpret_cast<const input_type *>(_input->buffer()), \
+ getTensorShape(_output), reinterpret_cast<output_type *>(_output->buffer()), axis, \
+ GetComparefunction<input_type>(_is_arg_max));
+ if (_output->data_type() == ir::DataType::INT32)
+ {
+ switch (_input->data_type())
+ {
+ case ir::DataType::FLOAT32:
+ TF_LITE_ARG_MIN_MAX(float, int32_t, int32_t);
+ break;
+ case ir::DataType::QUANT_UINT8_ASYMM:
+ case ir::DataType::UINT8:
+ TF_LITE_ARG_MIN_MAX(uint8_t, int32_t, int32_t);
+ break;
+ case ir::DataType::INT32:
+ TF_LITE_ARG_MIN_MAX(int32_t, int32_t, int32_t);
+ break;
+ default:
+ throw std::runtime_error("ArgMinMax: unsupported data type");
+ }
+ }
+ else if (_output->data_type() == ir::DataType::INT64)
+ {
+ switch (_input->data_type())
+ {
+ case ir::DataType::FLOAT32:
+ TF_LITE_ARG_MIN_MAX(float, int32_t, int64_t);
+ break;
+ case ir::DataType::QUANT_UINT8_ASYMM:
+ case ir::DataType::UINT8:
+ TF_LITE_ARG_MIN_MAX(uint8_t, int32_t, int64_t);
+ break;
+ case ir::DataType::INT32:
+ TF_LITE_ARG_MIN_MAX(int32_t, int32_t, int64_t);
+ break;
+ default:
+ throw std::runtime_error("ArgMinMax: unsupported data type");
+ }
+ }
+ else
+ {
+ throw std::runtime_error("ArgMinMax: unsupported data type");
+ }
+
+#undef TF_LITE_ARG_MIN_MAX
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ArgMinMaxLayer.h b/runtime/onert/backend/cpu/ops/ArgMinMaxLayer.h
new file mode 100644
index 000000000..4c864cb98
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ArgMinMaxLayer.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_ARGMINMAXLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_ARGMINMAXLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class ArgMinMaxLayer : public ::onert::exec::IFunction
+{
+public:
+ ArgMinMaxLayer() : _input(nullptr), _output(nullptr), _axis(nullptr), _is_arg_max(true) {}
+
+public:
+ void configure(const IPortableTensor *indices, IPortableTensor *output,
+ const IPortableTensor *axis, bool is_arg_max);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+ const IPortableTensor *_axis;
+ bool _is_arg_max;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_ARGMINMAXLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/BatchMatMulLayer.cc b/runtime/onert/backend/cpu/ops/BatchMatMulLayer.cc
new file mode 100644
index 000000000..7ef023788
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/BatchMatMulLayer.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BatchMatMulLayer.h"
+
+#include <cker/operation/BatchMatMul.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+BatchMatMulLayer::BatchMatMulLayer()
+ : _lhs(nullptr), _rhs(nullptr), _output(nullptr), _adj_x(false), _adj_y(false),
+ _kernel(new nnfw::cker::BatchMatMul())
+{
+ // DO NOTHING
+}
+
+BatchMatMulLayer::~BatchMatMulLayer() = default;
+
+void BatchMatMulLayer::batchMatMulFloat32()
+{
+ nnfw::cker::BatchMatMul &batchmatmul_kernel = *_kernel;
+ nnfw::cker::Shape lhs_shape = getTensorShape(_lhs);
+ nnfw::cker::Shape rhs_shape = getTensorShape(_rhs);
+ nnfw::cker::Shape output_shape = getTensorShape(_output);
+
+ // TODO implement for constant input
+
+ batchmatmul_kernel.prepare(lhs_shape, rhs_shape, _adj_x, _adj_y);
+ batchmatmul_kernel(lhs_shape, reinterpret_cast<const float *>(_lhs->buffer()), rhs_shape,
+ reinterpret_cast<const float *>(_rhs->buffer()), _adj_x, _adj_y, output_shape,
+ reinterpret_cast<float *>(_output->buffer()));
+}
+
+void BatchMatMulLayer::configure(const IPortableTensor *lhs, const IPortableTensor *rhs, bool adj_x,
+ bool adj_y, IPortableTensor *output)
+{
+ assert(lhs != nullptr);
+ assert(rhs != nullptr);
+ assert(output != nullptr);
+
+ _lhs = lhs;
+ _rhs = rhs;
+ _adj_x = adj_x;
+ _adj_y = adj_y;
+ _output = output;
+}
+
+void BatchMatMulLayer::run()
+{
+ if (_lhs->data_type() == OperandType::FLOAT32)
+ {
+ batchMatMulFloat32();
+ }
+ else
+ {
+ throw std::runtime_error{"BatchMatMul: unsupported data type"};
+ }
+}
+
+#undef AVGPOOLING_PARAMETERS
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/BatchMatMulLayer.h b/runtime/onert/backend/cpu/ops/BatchMatMulLayer.h
new file mode 100644
index 000000000..6770e218b
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/BatchMatMulLayer.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_BATCH_MATMUL_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_BATCH_MATMUL_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace nnfw
+{
+namespace cker
+{
+class BatchMatMul;
+}
+} // namespace nnfw
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class BatchMatMulLayer : public ::onert::exec::IFunction
+{
+public:
+ BatchMatMulLayer();
+ ~BatchMatMulLayer();
+
+public:
+ void batchMatMulFloat32();
+
+ void configure(const IPortableTensor *lhs, const IPortableTensor *rhs, bool adj_x, bool adj_y,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_lhs;
+ const IPortableTensor *_rhs;
+ IPortableTensor *_output;
+
+ bool _adj_x;
+ bool _adj_y;
+
+ std::unique_ptr<nnfw::cker::BatchMatMul> _kernel;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_BATCH_MATMUL_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/BatchToSpaceNDLayer.cc b/runtime/onert/backend/cpu/ops/BatchToSpaceNDLayer.cc
new file mode 100644
index 000000000..f2f10eb9d
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/BatchToSpaceNDLayer.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BatchToSpaceNDLayer.h"
+
+#include <cker/operation/BatchToSpaceND.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+BatchToSpaceNDLayer::BatchToSpaceNDLayer()
+ : _input(nullptr), _output(nullptr), _block_shape(nullptr), _crops(nullptr)
+{
+ // DO NOTHING
+}
+
+template <typename T> void BatchToSpaceNDLayer::batchToSpaceNDGeneric()
+{
+ const int32_t NNapiCrops[]{0, 0, 0, 0};
+ const int32_t *_crops_buffer;
+
+ if (_crops == nullptr)
+ {
+ _crops_buffer = NNapiCrops;
+ }
+ else
+ {
+ _crops_buffer = reinterpret_cast<const int32_t *>(_crops->buffer());
+ }
+ nnfw::cker::BatchToSpaceND<T>(
+ getTensorShape(_input), reinterpret_cast<const T *>(_input->buffer()),
+ reinterpret_cast<const int32_t *>(_block_shape->buffer()), _crops_buffer,
+ getTensorShape(_output), reinterpret_cast<T *>(_output->buffer()));
+}
+
+void BatchToSpaceNDLayer::configure(const IPortableTensor *input, IPortableTensor *output,
+ IPortableTensor *block_shape, IPortableTensor *crops)
+{
+ _output = output;
+ _input = input;
+ _block_shape = block_shape;
+ _crops = crops;
+}
+
+void BatchToSpaceNDLayer::run()
+{
+ if (_output->data_type() == OperandType::FLOAT32)
+ {
+ batchToSpaceNDGeneric<float>();
+ }
+ else if (_output->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ batchToSpaceNDGeneric<uint8_t>();
+ }
+ else
+ {
+ throw std::runtime_error{"NYI"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/BatchToSpaceNDLayer.h b/runtime/onert/backend/cpu/ops/BatchToSpaceNDLayer.h
new file mode 100644
index 000000000..6e25b241b
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/BatchToSpaceNDLayer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_BATCHTOSPACEND_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_BATCHTOSPACEND_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class BatchToSpaceNDLayer : public ::onert::exec::IFunction
+{
+public:
+ BatchToSpaceNDLayer();
+
+public:
+ template <typename T> void batchToSpaceNDGeneric();
+
+ void configure(const IPortableTensor *input, IPortableTensor *output,
+ IPortableTensor *block_shape, IPortableTensor *crops);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+ IPortableTensor *_block_shape;
+ IPortableTensor *_crops;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_BATCHTOSPACEND_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.cc b/runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.cc
new file mode 100644
index 000000000..ff1126932
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.cc
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BinaryArithmeticLayer.h"
+
+#include <cker/operation/BinaryArithmeticOps.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+namespace
+{
+
+template <nnfw::cker::BinaryArithmeticOpType arithmetic_type, typename T> struct Eval
+{
+ nnfw::cker::Shape _lhs_shape;
+ nnfw::cker::Shape _rhs_shape;
+ nnfw::cker::Shape _output_shape;
+ nnfw::cker::BinaryArithmeticOpParam _op_params;
+ bool _need_broadcast;
+
+ Eval(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output,
+ nnfw::cker::BinaryArithmeticOpParam op_params)
+ : _op_params(std::move(op_params)), _need_broadcast(false)
+ {
+ if (!output->is_dynamic())
+ updateCache(lhs, rhs, output);
+ }
+
+ void updateCache(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output)
+ {
+ _lhs_shape.ReplaceWith(getTensorShape(lhs));
+ _rhs_shape.ReplaceWith(getTensorShape(rhs));
+ _output_shape.ReplaceWith(getTensorShape(output));
+ _need_broadcast = nnfw::cker::ProcessBroadcastShapes(_lhs_shape, _rhs_shape, &_op_params);
+ }
+
+ void operator()(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output)
+ {
+ // Assume dynamic tensors never become static and static ones never change shape since
+ // configure()
+ if (output->is_dynamic())
+ updateCache(lhs, rhs, output);
+ else
+ assert(_lhs_shape == getTensorShape(lhs) && _rhs_shape == getTensorShape(rhs) &&
+ _output_shape == getTensorShape(output));
+ auto lhs_buffer = reinterpret_cast<const T *>(lhs->buffer());
+ auto rhs_buffer = reinterpret_cast<const T *>(rhs->buffer());
+ auto output_buffer = reinterpret_cast<T *>(output->buffer());
+ if (_need_broadcast)
+ {
+ nnfw::cker::BroadcastBinaryArithmeticOp<arithmetic_type>(
+ _op_params, _lhs_shape, lhs_buffer, _rhs_shape, rhs_buffer, _output_shape, output_buffer);
+ }
+ else
+ {
+ nnfw::cker::BinaryArithmeticOp<arithmetic_type>(
+ _op_params, _lhs_shape, lhs_buffer, _rhs_shape, rhs_buffer, _output_shape, output_buffer);
+ }
+ }
+};
+
+template <nnfw::cker::BinaryArithmeticOpType arithmetic_type>
+std::function<void(const IPortableTensor *, const IPortableTensor *, IPortableTensor *)>
+generateKernelGeneric(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ IPortableTensor *output, const ir::Activation activation,
+ nnfw::cker::BinaryArithmeticOpParam &op_params)
+{
+ switch (lhs->data_type())
+ {
+ case OperandType::FLOAT32:
+ {
+ float output_activation_min = 0, output_activation_max = 0;
+ CalculateActivationRange(activation, &output_activation_min, &output_activation_max);
+ op_params.float_activation_max = output_activation_max;
+ op_params.float_activation_min = output_activation_min;
+ return Eval<arithmetic_type, float>(lhs, rhs, output, op_params);
+ break;
+ }
+ case OperandType::INT32:
+ {
+ int32_t output_activation_min = 0, output_activation_max = 0;
+ CalculateActivationRange(activation, &output_activation_min, &output_activation_max);
+ op_params.quantized_activation_max = output_activation_max;
+ op_params.quantized_activation_min = output_activation_min;
+ return Eval<arithmetic_type, int32_t>(lhs, rhs, output, op_params);
+ break;
+ }
+ default:
+ throw std::runtime_error{"BinaryArithmetic(generic): Unsupported data type"};
+ }
+}
+
+void setAddOrSubQuant8Params(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ IPortableTensor *output, ir::Activation activation,
+ nnfw::cker::BinaryArithmeticOpParam *params)
+{
+ int32_t output_activation_min, output_activation_max;
+ CalculateActivationRangeUint8(activation, output, &output_activation_min, &output_activation_max);
+ nnfw::cker::BinaryArithmeticOpParam &op_params = *params;
+ op_params.quantized_activation_max = output_activation_max;
+ op_params.quantized_activation_min = output_activation_min;
+ // Parameters for scaled quantized computation
+ op_params.left_shift = 20;
+ // Zero-points of input and output tensors
+ op_params.input1_offset = -lhs->data_offset();
+ op_params.input2_offset = -rhs->data_offset();
+ op_params.output_offset = output->data_offset();
+ assert((op_params.input1_offset <= 0) && (op_params.input1_offset >= -255));
+ assert((op_params.input2_offset <= 0) && (op_params.input2_offset >= -255));
+ assert((op_params.output_offset >= 0) && (op_params.output_offset <= 255));
+
+ // Compute normalized scale for _lhs and _rhs values,
+ // and represent in 32-bit fixed point
+ const double norm_max_scale = 2 * std::max(lhs->data_scale(), rhs->data_scale());
+ const double real_lhs_scale = lhs->data_scale() / norm_max_scale;
+ const double real_rhs_scale = rhs->data_scale() / norm_max_scale;
+ // output scale is used to normalize final result, so we invert the scale here
+ const double real_output_scale =
+ norm_max_scale / (output->data_scale() * (1 << op_params.left_shift));
+
+ // Represent the scales as fixed int32_t multipliers, and int32_t shifts
+ QuantizeMultiplier(real_lhs_scale, &op_params.input1_multiplier, &op_params.input1_shift);
+ QuantizeMultiplier(real_rhs_scale, &op_params.input2_multiplier, &op_params.input2_shift);
+ QuantizeMultiplier(real_output_scale, &op_params.output_multiplier, &op_params.output_shift);
+}
+
+void setMulQuant8Params(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ IPortableTensor *output, ir::Activation activation,
+ nnfw::cker::BinaryArithmeticOpParam *params)
+{
+ int32_t output_activation_min, output_activation_max;
+ CalculateActivationRangeUint8(activation, output, &output_activation_min, &output_activation_max);
+ nnfw::cker::BinaryArithmeticOpParam &op_params = *params;
+
+ op_params.quantized_activation_max = output_activation_max;
+ op_params.quantized_activation_min = output_activation_min;
+ op_params.input1_offset = -lhs->data_offset();
+ op_params.input2_offset = -rhs->data_offset();
+ op_params.output_offset = output->data_offset();
+
+ double real_multiplier = lhs->data_scale() * rhs->data_scale() / output->data_scale();
+ QuantizeMultiplier(real_multiplier, &op_params.output_multiplier, &op_params.output_shift);
+}
+
+} // namespace
+
+void BinaryArithmeticLayer::configure(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ IPortableTensor *output, const ir::Activation activation,
+ const ArithmeticType arithmetic_type)
+{
+ assert(lhs != nullptr);
+ assert(rhs != nullptr);
+ assert(output != nullptr);
+
+ _lhs = lhs;
+ _rhs = rhs;
+ _output = output;
+
+ nnfw::cker::BinaryArithmeticOpParam op_params;
+ switch (arithmetic_type)
+ {
+ case ArithmeticType::kAdd:
+ if (_lhs->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ setAddOrSubQuant8Params(_lhs, _rhs, _output, activation, &op_params);
+ _kernel =
+ Eval<nnfw::cker::BinaryArithmeticOpType::ADD, uint8_t>(_lhs, _rhs, _output, op_params);
+ }
+ else
+ {
+ _kernel = generateKernelGeneric<nnfw::cker::BinaryArithmeticOpType::ADD>(
+ _lhs, _rhs, _output, activation, op_params);
+ }
+ break;
+ case ArithmeticType::kSub:
+ if (_lhs->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ setAddOrSubQuant8Params(_lhs, _rhs, _output, activation, &op_params);
+ op_params.input2_multiplier *= -1;
+ _kernel =
+ Eval<nnfw::cker::BinaryArithmeticOpType::SUB, uint8_t>(_lhs, _rhs, _output, op_params);
+ }
+ else
+ {
+ _kernel = generateKernelGeneric<nnfw::cker::BinaryArithmeticOpType::SUB>(
+ _lhs, _rhs, _output, activation, op_params);
+ }
+ break;
+ case ArithmeticType::kMul:
+ if (_lhs->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ nnfw::cker::BinaryArithmeticOpParam op_params;
+ setMulQuant8Params(_lhs, _rhs, _output, activation, &op_params);
+ _kernel =
+ Eval<nnfw::cker::BinaryArithmeticOpType::MUL, uint8_t>(_lhs, _rhs, _output, op_params);
+ }
+ else
+ {
+ _kernel = generateKernelGeneric<nnfw::cker::BinaryArithmeticOpType::MUL>(
+ _lhs, _rhs, _output, activation, op_params);
+ }
+ break;
+ case ArithmeticType::kDiv:
+ if (_lhs->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ throw std::runtime_error{
+ "BinaryArithmetic(Div): Div operation does not support quantization"};
+ }
+ else if (_lhs->data_type() == OperandType::INT32)
+ {
+ throw std::runtime_error{"BinaryArithmetic(Div): Unsupported data type"};
+ }
+ else
+ {
+ _kernel = generateKernelGeneric<nnfw::cker::BinaryArithmeticOpType::DIV>(
+ _lhs, _rhs, _output, activation, op_params);
+ }
+ break;
+ default:
+ throw std::runtime_error{"BinaryArithmetic: Unsupported BinaryArithmetic type"};
+ }
+}
+
+void BinaryArithmeticLayer::run() { _kernel(_lhs, _rhs, _output); }
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.h b/runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.h
new file mode 100644
index 000000000..d6b33ad07
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/BinaryArithmeticLayer.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_BINARYARITHMETICLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_BINARYARITHMETICLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+enum class ArithmeticType
+{
+ kAdd,
+ kSub,
+ kMul,
+ kDiv,
+};
+
+class BinaryArithmeticLayer : public ::onert::exec::IFunction
+{
+public:
+ BinaryArithmeticLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr)
+ {
+ // DO NOTHING
+ }
+
+public:
+ void configure(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output,
+ const ir::Activation activation, const ArithmeticType arithmetic_type);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_lhs;
+ const IPortableTensor *_rhs;
+ IPortableTensor *_output;
+
+ std::function<void(const IPortableTensor *, const IPortableTensor *, IPortableTensor *)> _kernel;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_BINARYARITHMETICLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/BroadcastToLayer.cc b/runtime/onert/backend/cpu/ops/BroadcastToLayer.cc
new file mode 100644
index 000000000..d9c1bbfc5
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/BroadcastToLayer.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BroadcastToLayer.h"
+
+#include <cker/operation/BroadcastTo.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+BroadcastToLayer::BroadcastToLayer() : _input(nullptr), _shape(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void BroadcastToLayer::configure(const IPortableTensor *input, const IPortableTensor *shape,
+ IPortableTensor *output)
+{
+ _input = input;
+ _shape = shape;
+ _output = output;
+}
+
+void BroadcastToLayer::run()
+{
+ // NOTE : It was implemented follows tf.broadcast_to operation works and
+ // Api Document(https://www.tensorflow.org/api_docs/python/tf/broadcast_to)
+
+ switch (_output->data_type())
+ {
+ // ToDo : It need to support INT8 and UINT8 also when will be applied quantization.
+ case OperandType::FLOAT32:
+ nnfw::cker::BroadcastTo<float>(
+ getTensorShape(_input), reinterpret_cast<float *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+ break;
+ case OperandType::INT32:
+ nnfw::cker::BroadcastTo<int32_t>(
+ getTensorShape(_input), reinterpret_cast<int32_t *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<int32_t *>(_output->buffer()));
+ break;
+ case OperandType::UINT32:
+ nnfw::cker::BroadcastTo<uint32_t>(
+ getTensorShape(_input), reinterpret_cast<uint32_t *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<uint32_t *>(_output->buffer()));
+ break;
+ default:
+ throw std::runtime_error{"BroadcastToLayer: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/BroadcastToLayer.h b/runtime/onert/backend/cpu/ops/BroadcastToLayer.h
new file mode 100644
index 000000000..8e8433fc9
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/BroadcastToLayer.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_BROADCASTLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_BROADCASTLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class BroadcastToLayer : public ::onert::exec::IFunction
+{
+public:
+ BroadcastToLayer();
+
+public:
+ void configure(const IPortableTensor *input, const IPortableTensor *shape,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_shape;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_BROADCASTLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/CompareLayer.cc b/runtime/onert/backend/cpu/ops/CompareLayer.cc
new file mode 100644
index 000000000..adf902aaf
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/CompareLayer.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "CompareLayer.h"
+
+#include "OperationUtils.h"
+
+#include <assert.h>
+#include <cker/operation/Comparison.h>
+using namespace nnfw::cker;
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+namespace
+{
+
+using OpType = onert::ir::operation::Comparison::ComparisonType;
+using namespace onert::backend::cpu;
+
+// Assumes these enum values to be in the order like this
+static_assert(static_cast<int>(OpType::Equal) == 0, "An OpType value has changed!");
+static_assert(static_cast<int>(OpType::NotEqual) == 1, "An OpType value has changed!");
+static_assert(static_cast<int>(OpType::Greater) == 2, "An OpType value has changed!");
+static_assert(static_cast<int>(OpType::GreaterEqual) == 3, "An OpType value has changed!");
+static_assert(static_cast<int>(OpType::Less) == 4, "An OpType value has changed!");
+static_assert(static_cast<int>(OpType::LessEqual) == 5, "An OpType value has changed!");
+
+template <typename T>
+void compareQuant8(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output,
+ OpType op_type)
+{
+ nnfw::cker::ComparisonParams params;
+ params.left_shift = 8;
+ params.input1_offset = -lhs->data_offset();
+ params.input2_offset = -rhs->data_offset();
+ const double norm_max_scale =
+ 2 * std::max(std::abs(lhs->data_scale()), std::abs(rhs->data_scale()));
+ const double adjusted_lhs_scale = lhs->data_scale() / norm_max_scale;
+ const double adjusted_rhs_scale = rhs->data_scale() / norm_max_scale;
+ QuantizeMultiplierSmallerThanOneExp(adjusted_lhs_scale, &params.input1_multiplier,
+ &params.input1_shift);
+ QuantizeMultiplierSmallerThanOneExp(adjusted_rhs_scale, &params.input2_multiplier,
+ &params.input2_shift);
+ params.is_broadcast = !HaveSameShapes(lhs, rhs);
+
+ using CompareFunction =
+ void (*)(ComparisonParams & params, const Shape &input1_shape, const T *input1_data,
+ const Shape &input2_shape, const T *input2_data, const Shape &output_shape,
+ bool *output_data);
+
+ static const CompareFunction broadcast_fns[] = {
+ Broadcast4DSlowEqualWithScaling, Broadcast4DSlowNotEqualWithScaling,
+ Broadcast4DSlowGreaterWithScaling, Broadcast4DSlowGreaterEqualWithScaling,
+ Broadcast4DSlowLessWithScaling, Broadcast4DSlowLessEqualWithScaling,
+ };
+ static const CompareFunction non_broadcast_fns[] = {
+ EqualWithScaling, NotEqualWithScaling, GreaterWithScaling,
+ GreaterEqualWithScaling, LessWithScaling, LessEqualWithScaling,
+ };
+
+ static_assert(sizeof(broadcast_fns) == sizeof(non_broadcast_fns),
+ "Sizes of broadcast_fns and non_broadcast_fns must match!");
+
+ auto index = static_cast<int>(op_type);
+ if (index < 0 || index >= static_cast<int>(sizeof(broadcast_fns) / sizeof(broadcast_fns[0])))
+ throw std::runtime_error{"Invalid OpType for CompareLayer"};
+
+ CompareFunction fn = (params.is_broadcast ? broadcast_fns[index] : non_broadcast_fns[index]);
+
+ fn(params, getExtendedTensorShape(lhs), reinterpret_cast<const T *>(lhs->buffer()),
+ getExtendedTensorShape(rhs), reinterpret_cast<const T *>(rhs->buffer()),
+ getExtendedTensorShape(output), reinterpret_cast<bool *>(output->buffer()));
+}
+
+template <typename T>
+void compareScalar(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output,
+ OpType op_type)
+{
+ bool requires_broadcast = !HaveSameShapes(lhs, rhs);
+
+ using CompareFunction =
+ void (*)(const Shape &input1_shape, const T *input1_data, const Shape &input2_shape,
+ const T *input2_data, const Shape &output_shape, bool *output_data);
+
+ static const CompareFunction broadcast_fns[] = {
+ Broadcast4DSlowEqual, Broadcast4DSlowNotEqual, Broadcast4DSlowGreater,
+ Broadcast4DSlowGreaterEqual, Broadcast4DSlowLess, Broadcast4DSlowLessEqual,
+ };
+ static const CompareFunction non_broadcast_fns[] = {
+ EqualNoScaling, NotEqualNoScaling, GreaterNoScaling,
+ GreaterEqualNoScaling, LessNoScaling, LessEqualNoScaling,
+ };
+
+ static_assert(sizeof(broadcast_fns) == sizeof(non_broadcast_fns),
+ "Sizes of broadcast_fns and non_broadcast_fns must match!");
+
+ auto index = static_cast<int>(op_type);
+ if (index < 0 || index >= static_cast<int>(sizeof(broadcast_fns) / sizeof(broadcast_fns[0])))
+ throw std::runtime_error{"Invalid OpType for CompareLayer"};
+
+ CompareFunction fn = (requires_broadcast ? broadcast_fns[index] : non_broadcast_fns[index]);
+
+ fn(getExtendedTensorShape(lhs), reinterpret_cast<const T *>(lhs->buffer()),
+ getExtendedTensorShape(rhs), reinterpret_cast<const T *>(rhs->buffer()),
+ getExtendedTensorShape(output), reinterpret_cast<bool *>(output->buffer()));
+}
+
+} // namespace
+
+CompareLayer::CompareLayer()
+ : _lhs(nullptr), _rhs(nullptr), _output(nullptr),
+ _op_type(ir::operation::Comparison::ComparisonType::Equal)
+{
+ // DO NOTHING
+}
+
+void CompareLayer::configure(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ const OpType op_type, IPortableTensor *output)
+{
+ _lhs = lhs;
+ _rhs = rhs;
+ _op_type = op_type;
+ _output = output;
+}
+
+void CompareLayer::run()
+{
+ if (_lhs->data_type() == OperandType::FLOAT32)
+ {
+ compareScalar<float>(_lhs, _rhs, _output, _op_type);
+ }
+ else if (_lhs->data_type() == OperandType::INT32)
+ {
+ compareScalar<int32_t>(_lhs, _rhs, _output, _op_type);
+ }
+ else if (_lhs->data_type() == OperandType::INT64)
+ {
+ compareScalar<int64_t>(_lhs, _rhs, _output, _op_type);
+ }
+ else if (_lhs->data_type() == OperandType::BOOL8)
+ {
+ compareScalar<uint8_t>(_lhs, _rhs, _output, _op_type);
+ }
+ else if (_lhs->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ compareQuant8<uint8_t>(_lhs, _rhs, _output, _op_type);
+ }
+ else
+ {
+ throw std::runtime_error{"Compare: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/CompareLayer.h b/runtime/onert/backend/cpu/ops/CompareLayer.h
new file mode 100644
index 000000000..add360ef8
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/CompareLayer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_COMPARELAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_COMPARELAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+#include <ir/operation/Comparison.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class CompareLayer : public ::onert::exec::IFunction
+{
+public:
+ CompareLayer();
+
+public:
+ void configure(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ const ir::operation::Comparison::ComparisonType op_type, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_lhs;
+ const IPortableTensor *_rhs;
+ IPortableTensor *_output;
+ ir::operation::Comparison::ComparisonType _op_type;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_COMPARELAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ConcatLayer.cc b/runtime/onert/backend/cpu/ops/ConcatLayer.cc
new file mode 100644
index 000000000..d26ed7378
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ConcatLayer.cc
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConcatLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Concatenation.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+ConcatLayer::ConcatLayer() : _inputs(), _output(nullptr), _axis(0)
+{
+ // DO NOTHING
+}
+
+template <typename T> void ConcatLayer::concatenationGeneral()
+{
+ uint32_t num_inputs = _inputs.size();
+
+ nnfw::cker::ConcatenationParams op_params;
+ op_params.axis = _axis;
+ op_params.inputs_count = num_inputs;
+
+ std::vector<nnfw::cker::Shape *> inputDimsPtr;
+ std::vector<nnfw::cker::Shape> inputDims;
+ inputDimsPtr.reserve(num_inputs);
+ inputDims.reserve(num_inputs);
+
+ for (uint32_t i = 0; i < num_inputs; i++)
+ {
+ inputDims.push_back(getTensorShape(_inputs[i]));
+ inputDimsPtr.push_back(&inputDims[i]);
+ }
+
+ std::vector<const T *> inputDataPtrs;
+
+ for (const auto input : _inputs)
+ {
+ inputDataPtrs.emplace_back(reinterpret_cast<const T *>(input->buffer()));
+ }
+
+ nnfw::cker::Concatenation<T>(op_params, inputDimsPtr.data(), inputDataPtrs.data(),
+ getTensorShape(_output), reinterpret_cast<T *>(_output->buffer()));
+}
+void ConcatLayer::concatenationQuant8()
+{
+ uint32_t num_inputs = _inputs.size();
+
+ std::vector<int32_t> input_zeropoints(num_inputs);
+ std::vector<float> input_scales(num_inputs);
+ for (uint32_t i = 0; i < num_inputs; i++)
+ {
+ input_zeropoints[i] = _inputs[i]->data_offset();
+ input_scales[i] = _inputs[i]->data_scale();
+ }
+
+ nnfw::cker::ConcatenationParams op_params;
+ op_params.axis = _axis;
+ op_params.inputs_count = num_inputs;
+ op_params.input_zeropoint = input_zeropoints.data();
+ op_params.input_scale = input_scales.data();
+ op_params.output_zeropoint = _output->data_offset();
+ op_params.output_scale = _output->data_scale();
+
+ std::vector<nnfw::cker::Shape *> inputDimsPtr;
+ std::vector<nnfw::cker::Shape> inputDims;
+ inputDimsPtr.reserve(num_inputs);
+ inputDims.reserve(num_inputs);
+ for (uint32_t i = 0; i < num_inputs; i++)
+ {
+ inputDims.push_back(getTensorShape(_inputs[i]));
+ inputDimsPtr.push_back(&inputDims[i]);
+ }
+
+ std::vector<const uint8_t *> inputDataPtrs;
+ for (const auto input : _inputs)
+ {
+ inputDataPtrs.emplace_back(reinterpret_cast<const uint8_t *>(input->buffer()));
+ }
+
+ nnfw::cker::ConcatenationWithScaling(op_params, inputDimsPtr.data(), inputDataPtrs.data(),
+ getTensorShape(_output),
+ reinterpret_cast<uint8_t *>(_output->buffer()));
+}
+
+void ConcatLayer::configure(const std::vector<const IPortableTensor *> &inputs, int32_t axis,
+ IPortableTensor *output)
+{
+ assert(inputs.size() > 0);
+ assert(output != nullptr);
+
+ _inputs = inputs;
+ _axis = axis;
+ _output = output;
+}
+
+void ConcatLayer::run()
+{
+ if (_output->data_type() == OperandType::FLOAT32)
+ {
+ concatenationGeneral<float>();
+ }
+ else if (_output->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ concatenationQuant8();
+ }
+ else if (_output->data_type() == OperandType::INT32)
+ {
+ concatenationGeneral<int32_t>();
+ }
+ else if (_output->data_type() == OperandType::INT64)
+ {
+ concatenationGeneral<int64_t>();
+ }
+ else
+ throw std::runtime_error("Concat: unsupported data type");
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ConcatLayer.h b/runtime/onert/backend/cpu/ops/ConcatLayer.h
new file mode 100644
index 000000000..0787199d6
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ConcatLayer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_CONCATLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_CONCATLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class ConcatLayer : public ::onert::exec::IFunction
+{
+public:
+ ConcatLayer();
+
+public:
+ template <typename T> void concatenationGeneral();
+
+ void concatenationQuant8();
+
+ void configure(const std::vector<const IPortableTensor *> &inputs, int32_t axis,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ std::vector<const IPortableTensor *> _inputs;
+ IPortableTensor *_output;
+ int32_t _axis;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_CONCATLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ConvolutionLayer.cc b/runtime/onert/backend/cpu/ops/ConvolutionLayer.cc
new file mode 100644
index 000000000..799e9e2d0
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ConvolutionLayer.cc
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConvolutionLayer.h"
+
+#include "../Tensor.h"
+#include "ir/Padding.h"
+#include <cker/operation/Conv.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+ConvolutionLayer::ConvolutionLayer()
+ : _input(nullptr), _kernel(nullptr), _bias(nullptr), _output(nullptr),
+ _paddingType(ir::PaddingType::EXPLICIT), _paddingLeft(0), _paddingTop(0), _paddingRight(0),
+ _paddingBottom(0), _strideWidth(0), _strideHeight(0), _dilationWidthFactor(1),
+ _dilationHeightFactor(1), _activation(ir::Activation::NONE),
+ _conv_kernel(new nnfw::cker::Conv()), _prepare(false)
+{
+ // DO NOTHING
+}
+
+ConvolutionLayer::~ConvolutionLayer() = default;
+
+void ConvolutionLayer::convFloat32()
+{
+ float output_activation_min = 0, output_activation_max = 0;
+ CalculateActivationRange(_activation, &output_activation_min, &output_activation_max);
+
+ nnfw::cker::ConvParams op_params;
+ op_params.padding_type = getPaddingType(_paddingType);
+ op_params.padding_values.width = _paddingLeft;
+ op_params.padding_values.height = _paddingTop;
+ op_params.stride_width = _strideWidth;
+ op_params.stride_height = _strideHeight;
+ op_params.dilation_width_factor = _dilationWidthFactor;
+ op_params.dilation_height_factor = _dilationHeightFactor;
+ op_params.float_activation_min = output_activation_min;
+ op_params.float_activation_max = output_activation_max;
+
+ nnfw::cker::Conv &kernel = *_conv_kernel;
+ kernel(op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_kernel), reinterpret_cast<const float *>(_kernel->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const float *>(_bias->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+}
+
+void ConvolutionLayer::convQuant8()
+{
+ int32_t output_activation_min = 0;
+ int32_t output_activation_max = 0;
+ CalculateActivationRangeUint8(_activation, _output, &output_activation_min,
+ &output_activation_max);
+
+ double real_multiplier = 0.0;
+ int32_t output_multiplier = 0;
+ int32_t output_shift = 0;
+ GetQuantizedConvolutionMultiplier(_input, _kernel, _bias, _output, &real_multiplier);
+ QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift);
+
+ nnfw::cker::ConvParams op_params;
+ op_params.stride_width = _strideWidth;
+ op_params.stride_height = _strideHeight;
+ op_params.dilation_width_factor = _dilationWidthFactor;
+ op_params.dilation_height_factor = _dilationHeightFactor;
+ op_params.padding_type = getPaddingType(_paddingType);
+ op_params.padding_values.width = _paddingLeft;
+ op_params.padding_values.height = _paddingTop;
+ op_params.input_offset = -_input->data_offset();
+ op_params.weights_offset = -_kernel->data_offset();
+ op_params.output_offset = _output->data_offset();
+ op_params.output_multiplier = output_multiplier;
+ op_params.output_shift = output_shift;
+ op_params.quantized_activation_min = output_activation_min;
+ op_params.quantized_activation_max = output_activation_max;
+ op_params.is_replaced_weights = true;
+
+ nnfw::cker::Conv &kernel = *_conv_kernel;
+ kernel(op_params, getTensorShape(_input), reinterpret_cast<const uint8_t *>(_input->buffer()),
+ getTensorShape(_kernel), reinterpret_cast<const uint8_t *>(_kernel->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const int32_t *>(_bias->buffer()),
+ getTensorShape(_output), reinterpret_cast<uint8_t *>(_output->buffer()));
+}
+
+void ConvolutionLayer::configure(const IPortableTensor *input, const IPortableTensor *kernel,
+ const IPortableTensor *bias, const ir::PaddingType paddingType,
+ const uint32_t paddingLeft, const uint32_t paddingRight,
+ const uint32_t paddingTop, const uint32_t paddingBottom,
+ const uint32_t strideWidth, const uint32_t strideHeight,
+ const uint32_t dilationWidthFactor,
+ const uint32_t dilationHeightFactor,
+ const ir::Activation activation, IPortableTensor *output)
+{
+ _input = input;
+ _kernel = kernel;
+ _bias = bias;
+ _paddingType = paddingType;
+ _paddingLeft = paddingLeft;
+ _paddingRight = paddingRight;
+ _paddingTop = paddingTop;
+ _paddingBottom = paddingBottom;
+ _strideWidth = strideWidth;
+ _strideHeight = strideHeight;
+ _dilationWidthFactor = dilationWidthFactor;
+ _dilationHeightFactor = dilationHeightFactor;
+ _activation = activation;
+ _output = output;
+}
+
+void ConvolutionLayer::run()
+{
+ prepare();
+
+ if (_input->is_dynamic() || _kernel->is_dynamic())
+ {
+ const auto ifm_shape = _input->getShape().asFeature(_input->layout());
+ const auto ofm_shape = _output->getShape().asFeature(_input->layout());
+ // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
+ const auto ker_shape = _kernel->getShape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+
+ ir::Stride stride;
+ stride.vertical = _strideWidth;
+ stride.horizontal = _strideWidth;
+
+ ir::Padding param_padding;
+ param_padding.type = _paddingType;
+ param_padding.param.left = _paddingLeft;
+ param_padding.param.right = _paddingRight;
+ param_padding.param.top = _paddingTop;
+ param_padding.param.bottom = _paddingBottom;
+
+ const auto padding =
+ ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width, ker_height,
+ _dilationWidthFactor, _dilationHeightFactor);
+
+ _paddingLeft = padding.left;
+ _paddingRight = padding.right;
+ _paddingTop = padding.top;
+ _paddingBottom = padding.bottom;
+ }
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ convFloat32();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ convQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"Conv: unsupported data type"};
+ }
+}
+
+void ConvolutionLayer::prepare()
+{
+ if (_prepare)
+ return;
+
+ nnfw::cker::Conv &kernel = *_conv_kernel;
+ if (_input->data_type() == OperandType::FLOAT32 && _kernel->is_constant())
+ {
+ bool is_transposed = false;
+ kernel.prepare(getTensorShape(_kernel), reinterpret_cast<const float *>(_kernel->buffer()),
+ getPaddingType(_paddingType), is_transposed, _dilationWidthFactor,
+ _dilationHeightFactor);
+
+ // Decrease reference of _kernel(weights) only when _kernel is constant
+ if (is_transposed)
+ {
+ auto kernel_tensor = dynamic_cast<const Tensor *>(_kernel);
+ if (kernel_tensor)
+ // TODO Remove const_cast
+ const_cast<Tensor *>(kernel_tensor)->decrease_ref();
+ }
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM && _kernel->is_constant() &&
+ !_input->is_dynamic() && !_output->is_dynamic())
+ {
+ kernel.prepareQuant(getTensorShape(_input), getTensorShape(_kernel), getTensorShape(_output),
+ _strideWidth, _strideHeight, _dilationWidthFactor, _dilationHeightFactor);
+ }
+ _prepare = true;
+}
+
+#undef ANDROID_NN_CONV_PARAMETERS
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ConvolutionLayer.h b/runtime/onert/backend/cpu/ops/ConvolutionLayer.h
new file mode 100644
index 000000000..398892e65
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ConvolutionLayer.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_CONVOLUTIONLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_CONVOLUTIONLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+#include <functional>
+#include <memory>
+
+namespace nnfw
+{
+namespace cker
+{
+class Conv;
+}
+} // namespace nnfw
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class ConvolutionLayer : public ::onert::exec::IFunction
+{
+public:
+ ConvolutionLayer();
+ ~ConvolutionLayer();
+
+public:
+ void convFloat32();
+
+ void convQuant8();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *kernel,
+ const IPortableTensor *bias, ir::PaddingType _paddingType,
+ const uint32_t paddingLeft, const uint32_t paddingRight, const uint32_t paddingTop,
+ const uint32_t paddingBottom, const uint32_t strideWidth,
+ const uint32_t strideHeight, const uint32_t dilationWidthFactor,
+ const uint32_t dilationHeightFactor, const ir::Activation activation,
+ IPortableTensor *output);
+
+ void run() override;
+
+ void prepare() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_kernel;
+ const IPortableTensor *_bias;
+ IPortableTensor *_output;
+
+ ir::PaddingType _paddingType;
+ uint32_t _paddingLeft;
+ uint32_t _paddingTop;
+ uint32_t _paddingRight;
+ uint32_t _paddingBottom;
+
+ uint32_t _strideWidth;
+ uint32_t _strideHeight;
+ uint32_t _dilationWidthFactor;
+ uint32_t _dilationHeightFactor;
+
+ ir::Activation _activation;
+
+ std::unique_ptr<nnfw::cker::Conv> _conv_kernel;
+
+ bool _prepare;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_CONVOLUTIONLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc
new file mode 100644
index 000000000..f1dc1103a
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DepthwiseConvolutionLayer.h"
+
+#include <cker/operation/DepthwiseConv.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+void DepthwiseConvolutionLayer::convFloat32()
+{
+ float output_activation_min = 0, output_activation_max = 0;
+ CalculateActivationRange(_activation, &output_activation_min, &output_activation_max);
+
+ nnfw::cker::DepthwiseConvParams op_params;
+ op_params.stride_width = _strideWidth;
+ op_params.stride_height = _strideHeight;
+ op_params.dilation_width_factor = _dilationWidth;
+ op_params.dilation_height_factor = _dilationHeight;
+ op_params.padding_values.width = _paddingLeft;
+ op_params.padding_values.height = _paddingTop;
+ op_params.depth_multiplier = _multiplier;
+ op_params.float_activation_min = output_activation_min;
+ op_params.float_activation_max = output_activation_max;
+
+ nnfw::cker::DepthwiseConv(
+ op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_kernel), reinterpret_cast<const float *>(_kernel->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const float *>(_bias->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+}
+
+void DepthwiseConvolutionLayer::convQuant8()
+{
+ int32_t output_activation_min = 0;
+ int32_t output_activation_max = 0;
+ CalculateActivationRangeUint8(_activation, _output, &output_activation_min,
+ &output_activation_max);
+
+ double real_multiplier = 0.0;
+ int32_t output_multiplier = 0;
+ int32_t output_shift = 0;
+ GetQuantizedConvolutionMultiplier(_input, _kernel, _bias, _output, &real_multiplier);
+ QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift);
+
+ nnfw::cker::DepthwiseConvParams op_params;
+ op_params.stride_width = _strideWidth;
+ op_params.stride_height = _strideHeight;
+ op_params.dilation_width_factor = _dilationWidth;
+ op_params.dilation_height_factor = _dilationHeight;
+ op_params.padding_values.width = _paddingLeft;
+ op_params.padding_values.height = _paddingTop;
+ op_params.depth_multiplier = _multiplier;
+ op_params.input_offset = -_input->data_offset();
+ op_params.weights_offset = -_kernel->data_offset();
+ op_params.output_offset = _output->data_offset();
+ op_params.output_multiplier = output_multiplier;
+ op_params.output_shift = output_shift;
+ op_params.quantized_activation_min = output_activation_min;
+ op_params.quantized_activation_max = output_activation_max;
+
+ nnfw::cker::DepthwiseConv(
+ op_params, getTensorShape(_input), reinterpret_cast<const uint8_t *>(_input->buffer()),
+ getTensorShape(_kernel), reinterpret_cast<const uint8_t *>(_kernel->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const int32_t *>(_bias->buffer()),
+ getTensorShape(_output), reinterpret_cast<uint8_t *>(_output->buffer()));
+}
+
+void DepthwiseConvolutionLayer::configure(
+ const IPortableTensor *input, const IPortableTensor *kernel, const IPortableTensor *bias,
+ const uint32_t paddingLeft, const uint32_t paddingRight, const uint32_t paddingTop,
+ const uint32_t paddingBottom, const uint32_t strideWidth, const uint32_t strideHeight,
+ const uint32_t multiplier, const uint32_t dilationWidth, const uint32_t dilationHeight,
+ const ir::Activation activation, IPortableTensor *output)
+{
+ _input = input;
+ _kernel = kernel;
+ _bias = bias;
+ _paddingLeft = paddingLeft;
+ _paddingRight = paddingRight;
+ _paddingTop = paddingTop;
+ _paddingBottom = paddingBottom;
+ _strideWidth = strideWidth;
+ _strideHeight = strideHeight;
+ _multiplier = multiplier;
+ _dilationWidth = dilationWidth;
+ _dilationHeight = dilationHeight;
+ _activation = activation;
+ _output = output;
+}
+
+void DepthwiseConvolutionLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ convFloat32();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ convQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"DepthwiseConv: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h
new file mode 100644
index 000000000..fb032ecbf
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_KERNEL_CPU_DEPTHWISECONVOLUTIONLAYER_H__
+#define __ONERT_KERNEL_CPU_DEPTHWISECONVOLUTIONLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class DepthwiseConvolutionLayer : public ::onert::exec::IFunction
+{
+public:
+ DepthwiseConvolutionLayer() = default;
+
+public:
+ void convFloat32();
+
+ void convQuant8();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *kernel,
+ const IPortableTensor *bias, const uint32_t paddingLeft,
+ const uint32_t paddingRight, const uint32_t paddingTop,
+ const uint32_t paddingBottom, const uint32_t strideW, const uint32_t strideH,
+ const uint32_t multiplier, const uint32_t dilationWidth,
+ const uint32_t dilationHeight, const ir::Activation activation,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input{nullptr};
+ const IPortableTensor *_kernel{nullptr};
+ const IPortableTensor *_bias{nullptr};
+ IPortableTensor *_output{nullptr};
+
+ uint32_t _paddingLeft{0};
+ uint32_t _paddingTop{0};
+ uint32_t _paddingRight{0};
+ uint32_t _paddingBottom{0};
+
+ uint32_t _strideWidth{0};
+ uint32_t _strideHeight{0};
+
+ uint32_t _multiplier{0};
+
+ uint32_t _dilationWidth{1};
+ uint32_t _dilationHeight{1};
+
+ ir::Activation _activation{ir::Activation::NONE};
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_KERNEL_CPU_DEPTHWISECONVOLUTIONLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/EinsumLayer.cc b/runtime/onert/backend/cpu/ops/EinsumLayer.cc
new file mode 100644
index 000000000..8c16740a3
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/EinsumLayer.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EinsumLayer.h"
+
+#include <cker/operation/Einsum.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+EinsumLayer::EinsumLayer()
+ : _inputs(), _output(nullptr), _equation(), _einsum_kernel(new nnfw::cker::Einsum())
+{
+ // DO NOTHING
+}
+
+EinsumLayer::~EinsumLayer() = default;
+
+void EinsumLayer::einsumFloat32()
+{
+ uint32_t num_inputs = _inputs.size();
+ nnfw::cker::Einsum &kernel = *_einsum_kernel;
+
+ kernel.prepare(_equation);
+
+ std::vector<nnfw::cker::Shape> inputShapes;
+ std::vector<const float *> inputFloatPtrs;
+
+ for (uint32_t i = 0; i < num_inputs; i++)
+ {
+ inputShapes.emplace_back(getTensorShape(_inputs[i]));
+ inputFloatPtrs.emplace_back(reinterpret_cast<const float *>(_inputs[i]->buffer()));
+ }
+
+ kernel(_equation, inputShapes, inputFloatPtrs, getTensorShape(_output),
+ reinterpret_cast<float *>(_output->buffer()));
+}
+
+void EinsumLayer::run()
+{
+ if (_output->data_type() == OperandType::FLOAT32)
+ {
+ einsumFloat32();
+ }
+ else
+ {
+ throw std::runtime_error{"Einsum: unsupported data type"};
+ }
+}
+
+void EinsumLayer::configure(const std::vector<const IPortableTensor *> &inputs,
+ std::string equation, IPortableTensor *output)
+{
+ assert(inputs.size() > 0);
+ assert(output != nullptr);
+
+ _inputs = inputs;
+ _equation = equation;
+ _output = output;
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/EinsumLayer.h b/runtime/onert/backend/cpu/ops/EinsumLayer.h
new file mode 100644
index 000000000..a93f87e77
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/EinsumLayer.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_EINSUM_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_EINSUM_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+#include <functional>
+#include <memory>
+
+namespace nnfw
+{
+namespace cker
+{
+class Einsum;
+}
+} // namespace nnfw
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class EinsumLayer : public ::onert::exec::IFunction
+{
+public:
+ EinsumLayer();
+ ~EinsumLayer();
+
+public:
+ void einsumFloat32();
+
+ void configure(const std::vector<const IPortableTensor *> &inputs, std::string equation,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ std::vector<const IPortableTensor *> _inputs;
+ IPortableTensor *_output;
+
+ std::string _equation;
+
+ std::unique_ptr<nnfw::cker::Einsum> _einsum_kernel;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_EINSUM_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ElementwiseActivationLayer.cc b/runtime/onert/backend/cpu/ops/ElementwiseActivationLayer.cc
new file mode 100644
index 000000000..c1d63172b
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ElementwiseActivationLayer.cc
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ElementwiseActivationLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Logistic.h>
+#include <cker/operation/ReLU.h>
+#include <cker/operation/ReLU6.h>
+#include <cker/operation/Tanh.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+ElementwiseActivationLayer::ElementwiseActivationLayer()
+ : _input(nullptr), _output(nullptr), _kernel()
+{
+ // DO NOTHING
+}
+
+void ElementwiseActivationLayer::PopulateLookupTable(const ElementwiseActivationType op_type)
+{
+ const auto input_scale = static_cast<double>(_input->data_scale());
+ const auto input_zero_point = static_cast<int32_t>(_input->data_offset());
+ const auto output_scale = static_cast<double>(_output->data_scale());
+ const auto output_zero_point = static_cast<int32_t>(_output->data_offset());
+ const float inverse_scale = 1 / output_scale;
+ int32_t maxval = std::numeric_limits<uint8_t>::max();
+ int32_t minval = std::numeric_limits<uint8_t>::min();
+ for (int32_t val = minval; val <= maxval; ++val)
+ {
+ const float dequantized = input_scale * (val - input_zero_point);
+ float transformed = 0.f;
+ if (op_type == ElementwiseActivationType::kTanh)
+ {
+ transformed = std::tanh(dequantized);
+ }
+ else if (op_type == ElementwiseActivationType::kLogistic)
+ {
+ transformed = 1.0f / (1.0f + std::exp(-dequantized));
+ }
+ else
+ {
+ throw std::runtime_error("ElementwiseActivationLayer : unsupported activation type");
+ }
+ const float rescaled = std::round(transformed * inverse_scale);
+ const int32_t quantized = static_cast<int32_t>(rescaled + output_zero_point);
+ _table[val] = static_cast<uint8_t>(std::max(std::min(maxval, quantized), minval));
+ }
+}
+
+void ElementwiseActivationLayer::EvalUsingLookupTable(const IPortableTensor *input,
+ IPortableTensor *output)
+{
+ const int size = MatchingFlatSize(getTensorShape(input), getTensorShape(output));
+ const uint8_t *input_data = reinterpret_cast<const uint8_t *>(input->buffer());
+ uint8_t *output_data = reinterpret_cast<uint8_t *>(output->buffer());
+
+ for (int i = 0; i < size; ++i)
+ {
+ output_data[i] = _table[input_data[i]];
+ }
+}
+
+void ElementwiseActivationLayer::configure(const IPortableTensor *input, IPortableTensor *output,
+ float alpha, float beta,
+ ElementwiseActivationType op_type)
+{
+ _input = input;
+ _output = output;
+
+ switch (op_type)
+ {
+ case ElementwiseActivationType::kLogistic:
+ if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ PopulateLookupTable(op_type);
+ _kernel = std::bind(&ElementwiseActivationLayer::EvalUsingLookupTable, this,
+ std::placeholders::_1, std::placeholders::_2);
+ }
+ else if (_input->data_type() == OperandType::FLOAT32)
+ {
+ _kernel = [](const IPortableTensor *input, IPortableTensor *output) {
+ nnfw::cker::Logistic(getTensorShape(input),
+ reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+ };
+ }
+ else
+ {
+ throw std::runtime_error{"ElementwiseActivationLayer(Logistic): unsupported data type"};
+ }
+ break;
+ case ElementwiseActivationType::kReLU:
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ if (alpha == std::numeric_limits<float>::infinity() && beta == 0.f)
+ {
+ _kernel = [](const IPortableTensor *input, IPortableTensor *output) {
+ nnfw::cker::ReLU(getTensorShape(input),
+ reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+ };
+ }
+ else if (alpha == 6.f && beta == 0.f)
+ {
+ _kernel = [](const IPortableTensor *input, IPortableTensor *output) {
+ nnfw::cker::ReLU6(getTensorShape(input),
+ reinterpret_cast<const float *>(input->buffer()),
+ reinterpret_cast<float *>(output->buffer()));
+ };
+ }
+ else
+ {
+ throw std::runtime_error(
+ "ElementwiseActivationLayer : This layer suppports only ReLU(0-inf) and ReLU6(0-6)");
+ }
+ }
+ else
+ {
+ throw std::runtime_error{"ElementwiseActivationLayer(ReLU): unsupported data type"};
+ }
+ break;
+ case ElementwiseActivationType::kTanh:
+ if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ PopulateLookupTable(op_type);
+ _kernel = std::bind(&ElementwiseActivationLayer::EvalUsingLookupTable, this,
+ std::placeholders::_1, std::placeholders::_2);
+ }
+ else if (_input->data_type() == OperandType::FLOAT32)
+ {
+ _kernel = [](const IPortableTensor *input, IPortableTensor *output) {
+ nnfw::cker::Tanh(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+ };
+ }
+ else
+ {
+ throw std::runtime_error{"ElementwiseActivationLayer(Logistic): unsupported data type"};
+ }
+ break;
+ default:
+ throw std::runtime_error("ElementwiseActivationLayer: unsupported op type");
+ }
+}
+
+void ElementwiseActivationLayer::run() { _kernel(_input, _output); }
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ElementwiseActivationLayer.h b/runtime/onert/backend/cpu/ops/ElementwiseActivationLayer.h
new file mode 100644
index 000000000..3ef580041
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ElementwiseActivationLayer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_ElementwiseActivationLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_ElementwiseActivationLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+enum class ElementwiseActivationType
+{
+ kLogistic,
+ kReLU,
+ kTanh
+};
+
+class ElementwiseActivationLayer : public ::onert::exec::IFunction
+{
+public:
+ ElementwiseActivationLayer();
+
+public:
+ void configure(const IPortableTensor *input, IPortableTensor *output, float alpha, float beta,
+ const ElementwiseActivationType op_type);
+
+ void run() override;
+
+ void PopulateLookupTable(const ElementwiseActivationType op_type);
+
+ void EvalUsingLookupTable(const IPortableTensor *input, IPortableTensor *output);
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+ uint8_t _table[256];
+ std::function<void(const IPortableTensor *input, IPortableTensor *output)> _kernel;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_ElementwiseActivationLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ElementwiseBinaryLayer.cc b/runtime/onert/backend/cpu/ops/ElementwiseBinaryLayer.cc
new file mode 100644
index 000000000..ea3c1e7cd
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ElementwiseBinaryLayer.cc
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ElementwiseBinaryLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/LogicalOr.h>
+#include <cker/operation/MaxMin.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+namespace
+{
+template <typename T>
+void logicalOrGeneric(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ IPortableTensor *output)
+{
+ if (!HaveSameShapes(lhs, rhs))
+ {
+ nnfw::cker::LogicalOrBroadcast<T>(
+ getTensorShape(lhs), reinterpret_cast<const T *>(lhs->buffer()), getTensorShape(rhs),
+ reinterpret_cast<const T *>(rhs->buffer()), getTensorShape(output),
+ reinterpret_cast<T *>(output->buffer()));
+ }
+ else
+ {
+ nnfw::cker::LogicalOrElementwise<T>(
+ getTensorShape(lhs), reinterpret_cast<const T *>(lhs->buffer()),
+ reinterpret_cast<const T *>(rhs->buffer()), reinterpret_cast<T *>(output->buffer()));
+ }
+}
+
+template <typename T>
+void maximumGeneric(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output)
+{
+ nnfw::cker::Max<T>(getTensorShape(lhs), reinterpret_cast<const T *>(lhs->buffer()),
+ getTensorShape(rhs), reinterpret_cast<const T *>(rhs->buffer()),
+ getTensorShape(output), reinterpret_cast<T *>(output->buffer()));
+}
+
+template <typename T>
+void minimumGeneric(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output)
+{
+ nnfw::cker::Min<T>(getTensorShape(lhs), reinterpret_cast<const T *>(lhs->buffer()),
+ getTensorShape(rhs), reinterpret_cast<const T *>(rhs->buffer()),
+ getTensorShape(output), reinterpret_cast<T *>(output->buffer()));
+}
+
+bool haveSameQauntInfo(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ const IPortableTensor *output)
+{
+ return (lhs->data_scale() == rhs->data_scale() && lhs->data_scale() == output->data_scale()) &&
+ (lhs->data_offset() == rhs->data_offset() && lhs->data_offset() == output->data_offset());
+}
+} // namespace
+
+void ElementwiseBinaryLayer::configure(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ IPortableTensor *output, const ElementwiseBinaryType op_type)
+{
+ assert(lhs != nullptr);
+ assert(rhs != nullptr);
+ assert(output != nullptr);
+
+ _lhs = lhs;
+ _rhs = rhs;
+ _output = output;
+
+ switch (op_type)
+ {
+ case ElementwiseBinaryType::kLogicalOr:
+ if ((_lhs->data_type() == OperandType::BOOL8) && (_rhs->data_type() == OperandType::BOOL8))
+ {
+ _kernel = logicalOrGeneric<bool>;
+ }
+ else
+ {
+ throw std::runtime_error{"LogicalOr: Unsupported data type"};
+ }
+ break;
+ case ElementwiseBinaryType::kMax:
+ if (_lhs->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ if (!haveSameQauntInfo(_lhs, _rhs, _output))
+ {
+ throw std::runtime_error("Max NYI for quantized");
+ }
+ _kernel = maximumGeneric<uint8_t>;
+ }
+ else if (_lhs->data_type() == OperandType::FLOAT32)
+ {
+ _kernel = maximumGeneric<float>;
+ }
+ else
+ {
+ throw std::runtime_error{"Max: unsupported data type"};
+ }
+ break;
+ case ElementwiseBinaryType::kMin:
+ if (_lhs->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ if (!haveSameQauntInfo(_lhs, _rhs, _output))
+ {
+ throw std::runtime_error("Min NYI for quantized");
+ }
+ _kernel = minimumGeneric<uint8_t>;
+ }
+ else if (_lhs->data_type() == OperandType::INT32)
+ {
+ _kernel = minimumGeneric<int32_t>;
+ }
+ else if (_lhs->data_type() == OperandType::FLOAT32)
+ {
+ _kernel = minimumGeneric<float>;
+ }
+ else
+ {
+ throw std::runtime_error{"Min: unsupported data type"};
+ }
+ break;
+ default:
+ throw std::runtime_error{"ElementwiseBinary: Unsupported ElementwiseBinary type"};
+ }
+}
+
+void ElementwiseBinaryLayer::run() { _kernel(_lhs, _rhs, _output); }
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ElementwiseBinaryLayer.h b/runtime/onert/backend/cpu/ops/ElementwiseBinaryLayer.h
new file mode 100644
index 000000000..052747a4c
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ElementwiseBinaryLayer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_ELEMENTWISEBINARYLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_ELEMENTWISEBINARYLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+enum class ElementwiseBinaryType
+{
+ kLogicalAnd,
+ kLogicalOr,
+ kMax,
+ kMin,
+};
+
+class ElementwiseBinaryLayer : public ::onert::exec::IFunction
+{
+public:
+ ElementwiseBinaryLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr)
+ {
+ // DO NOTHING
+ }
+
+public:
+ void configure(const IPortableTensor *lhs, const IPortableTensor *rhs, IPortableTensor *output,
+ const ElementwiseBinaryType op_type);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_lhs;
+ const IPortableTensor *_rhs;
+ IPortableTensor *_output;
+ std::function<void(const IPortableTensor *, const IPortableTensor *, IPortableTensor *)> _kernel;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_ELEMENTWISEBINARYLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ElementwiseUnaryLayer.cc b/runtime/onert/backend/cpu/ops/ElementwiseUnaryLayer.cc
new file mode 100644
index 000000000..066455e72
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ElementwiseUnaryLayer.cc
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ElementwiseUnaryLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Dequantize.h>
+#include <cker/operation/Elementwise.h>
+#include <cker/operation/Erf.h>
+#include <cker/operation/Exp.h>
+#include <cker/operation/LogicalNot.h>
+#include <cker/operation/Quantize.h>
+#include <cker/operation/Round.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+namespace
+{
+void absFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Abs(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+template <typename FromT>
+void castPtr(const FromT *in, DataPtr out, int num_elements, ir::DataType data_type_out)
+{
+ switch (data_type_out)
+ {
+ case ir::DataType::FLOAT32:
+ std::transform(in, in + num_elements, out.f, [](FromT a) { return static_cast<float>(a); });
+ return;
+ case ir::DataType::INT32:
+ std::transform(in, in + num_elements, out.i32,
+ [](FromT a) { return static_cast<int32_t>(a); });
+ return;
+ case ir::DataType::UINT32:
+ std::transform(in, in + num_elements, out.u32,
+ [](FromT a) { return static_cast<uint32_t>(a); });
+ return;
+ case ir::DataType::UINT8:
+ std::transform(in, in + num_elements, out.u8,
+ [](FromT a) { return static_cast<uint8_t>(a); });
+ return;
+ case ir::DataType::BOOL8:
+ std::transform(in, in + num_elements, out.b, [](FromT a) { return static_cast<bool>(a); });
+ return;
+ case ir::DataType::INT64:
+ std::transform(in, in + num_elements, out.i64,
+ [](FromT a) { return static_cast<int64_t>(a); });
+ return;
+ default:
+ throw std::runtime_error("Cast: Not supported output type" +
+ std::to_string((int)data_type_out));
+ }
+}
+
+void cast(const IPortableTensor *input, IPortableTensor *output)
+{
+ auto input_buf = input->buffer();
+ auto output_buf = output->buffer();
+ const auto in = *reinterpret_cast<const DataPtr *>(&input_buf);
+ auto out = *reinterpret_cast<DataPtr *>(&output_buf);
+
+ auto input_shape = getTensorShape(input);
+ auto output_shape = getTensorShape(output);
+ const auto num_elements = MatchingFlatSize(input_shape, output_shape);
+
+ switch (input->data_type())
+ {
+ case ir::DataType::FLOAT32:
+ castPtr(in.f, out, num_elements, output->data_type());
+ return;
+ case ir::DataType::INT32:
+ castPtr(in.i32, out, num_elements, output->data_type());
+ return;
+ case ir::DataType::UINT32:
+ castPtr(in.u32, out, num_elements, output->data_type());
+ return;
+ case ir::DataType::UINT8:
+ castPtr(in.u8, out, num_elements, output->data_type());
+ return;
+ case ir::DataType::BOOL8:
+ castPtr(in.b, out, num_elements, output->data_type());
+ return;
+ case ir::DataType::INT64:
+ castPtr(in.i64, out, num_elements, output->data_type());
+ return;
+ default:
+ throw std::runtime_error("Cast: unsupported data type" +
+ std::to_string((int)input->data_type()));
+ }
+}
+
+void cosFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Cos(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+void dequantizeInt8(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Dequantize(getTensorShape(input), reinterpret_cast<const int8_t *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()),
+ input->data_scale(), input->data_offset());
+}
+
+void dequantizeUint8(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Dequantize(getTensorShape(input), reinterpret_cast<const uint8_t *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()),
+ input->data_scale(), input->data_offset());
+}
+
+void expFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Exp(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+void erfFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Erf(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+void floorFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Floor(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+void logFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Log(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+void logicalNot(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::LogicalNot(getTensorShape(input), reinterpret_cast<const bool *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<bool *>(output->buffer()));
+}
+
+template <typename T> void neg(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Neg<T>(getTensorShape(input), reinterpret_cast<const T *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<T *>(output->buffer()));
+}
+
+template <typename InputT, typename OutputT>
+void affineQuantize(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Quantize(getTensorShape(input), reinterpret_cast<const InputT *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<OutputT *>(output->buffer()),
+ output->data_scale(), output->data_offset());
+}
+
+void roundFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Round(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+void rsqrtFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Rsqrt(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+void sinFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ nnfw::cker::Sin(getTensorShape(input), reinterpret_cast<const float *>(input->buffer()),
+ getTensorShape(output), reinterpret_cast<float *>(output->buffer()));
+}
+
+template <typename T> void zerosLikeFloat32(const IPortableTensor *input, IPortableTensor *output)
+{
+ if (!HaveSameShapes(input, output))
+ throw std::runtime_error{"ZerosLike: input and output shape don't match."};
+
+ auto element_size = getTensorShape(input).FlatSize();
+
+ memset(reinterpret_cast<T *>(output->buffer()), 0, element_size * sizeof(T));
+}
+} // namespace
+
+void ElementwiseUnaryLayer::configure(const IPortableTensor *input, IPortableTensor *output,
+ const ElementwiseUnaryType op_type)
+{
+ assert(input != nullptr);
+ assert(output != nullptr);
+
+ _input = input;
+ _output = output;
+
+ switch (op_type)
+ {
+ case ElementwiseUnaryType::kAbs:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = absFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"Abs: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kCast:
+ _kernel = cast;
+ break;
+ case ElementwiseUnaryType::kCos:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = cosFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"Cos: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kDequantize:
+ if ((input->data_type() == OperandType::QUANT_UINT8_ASYMM))
+ {
+ _kernel = dequantizeUint8;
+ }
+ else if ((input->data_type() == OperandType::QUANT_INT8_ASYMM) ||
+ (input->data_type() == OperandType::QUANT_INT8_SYMM))
+ {
+ _kernel = dequantizeInt8;
+ }
+ else
+ {
+ throw std::runtime_error{"Dequantize: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kExp:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = expFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"Exp: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kErf:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = erfFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"Exp: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kFloor:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = floorFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"Floor: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kLog:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = logFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"Log: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kLogicalNot:
+ if ((input->data_type() == OperandType::BOOL8))
+ {
+ _kernel = logicalNot;
+ }
+ else
+ {
+ throw std::runtime_error{"LogicalNot: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kNeg:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = neg<float>;
+ }
+ else if ((input->data_type() == OperandType::INT64))
+ {
+ _kernel = neg<int64_t>;
+ }
+ else if ((input->data_type() == OperandType::INT32))
+ {
+ _kernel = neg<int32_t>;
+ }
+ else
+ {
+ throw std::runtime_error{"Neg: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kQuantize:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = affineQuantize<float, uint8_t>;
+ }
+ else
+ {
+ throw std::runtime_error{"Quantize: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kRound:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = roundFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"Round: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kRSqrt:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = rsqrtFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"RSqrt: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kSin:
+ if ((input->data_type() == OperandType::FLOAT32))
+ {
+ _kernel = sinFloat32;
+ }
+ else
+ {
+ throw std::runtime_error{"Sin: Unsupported data type"};
+ }
+ break;
+ case ElementwiseUnaryType::kZerosLike:
+ if (input->data_type() == OperandType::FLOAT32)
+ {
+ _kernel = zerosLikeFloat32<float>;
+ }
+ else if (input->data_type() == OperandType::INT32)
+ {
+ _kernel = zerosLikeFloat32<int32_t>;
+ }
+ else
+ {
+ throw std::runtime_error{"ZerosLike: Unsupported data type"};
+ }
+ break;
+ default:
+ throw std::runtime_error{"ElementwiseBinary: Unsupported ElementwiseBinary type"};
+ }
+}
+
+void ElementwiseUnaryLayer::run() { _kernel(_input, _output); }
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ElementwiseUnaryLayer.h b/runtime/onert/backend/cpu/ops/ElementwiseUnaryLayer.h
new file mode 100644
index 000000000..c1765b5b7
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ElementwiseUnaryLayer.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_ELEMENTWISEUNARYLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_ELEMENTWISEUNARYLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+enum class ElementwiseUnaryType
+{
+ kAbs,
+ kCast,
+ kCos,
+ kDequantize,
+ kErf,
+ kExp,
+ kFloor,
+ kLog,
+ kLogicalNot,
+ kNeg,
+ kQuantize,
+ kRound,
+ kRSqrt,
+ kSin,
+ kZerosLike
+};
+
+class ElementwiseUnaryLayer : public ::onert::exec::IFunction
+{
+public:
+ ElementwiseUnaryLayer() : _input(nullptr), _output(nullptr), _kernel()
+ {
+ // DO NOTHING
+ }
+
+public:
+ void configure(const IPortableTensor *input, IPortableTensor *output,
+ const ElementwiseUnaryType op_type);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+ std::function<void(const IPortableTensor *, IPortableTensor *)> _kernel;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_ELEMENTWISEUNARYLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ExpandDimsLayer.cc b/runtime/onert/backend/cpu/ops/ExpandDimsLayer.cc
new file mode 100644
index 000000000..b545e6743
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ExpandDimsLayer.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExpandDimsLayer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+ExpandDimsLayer::ExpandDimsLayer() : _input(nullptr), _axis(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void ExpandDimsLayer::configure(const IPortableTensor *input, const IPortableTensor *axis,
+ IPortableTensor *output)
+{
+ _input = input;
+ _axis = axis;
+ _output = output;
+}
+
+void ExpandDimsLayer::run()
+{
+ // TODO use _axis to calculate shape of output when _axis is not constant
+ size_t count = _input->total_size();
+ memcpy(_output->buffer(), _input->buffer(), count);
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ExpandDimsLayer.h b/runtime/onert/backend/cpu/ops/ExpandDimsLayer.h
new file mode 100644
index 000000000..b5d4938b5
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ExpandDimsLayer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ExpandDi__ONERT_BACKEND_CPU_OPS_EXPANDDIMS_LAYER_H__ms
+#define ExpandDi__ONERT_BACKEND_CPU_OPS_EXPANDDIMS_LAYER_H__ms
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class ExpandDimsLayer : public ::onert::exec::IFunction
+{
+public:
+ ExpandDimsLayer();
+
+public:
+ void configure(const IPortableTensor *input, const IPortableTensor *axis,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_axis;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // ExpandDi__ONERT_BACKEND_CPU_OPS_EXPANDDIMS_LAYER_H__ms
diff --git a/runtime/onert/backend/cpu/ops/FillLayer.cc b/runtime/onert/backend/cpu/ops/FillLayer.cc
new file mode 100644
index 000000000..df3f8b7cd
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/FillLayer.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FillLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Fill.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+FillLayer::FillLayer() : _input(nullptr), _value(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void FillLayer::configure(const IPortableTensor *input, const IPortableTensor *value,
+ IPortableTensor *output)
+{
+ _input = input;
+ _value = value;
+ _output = output;
+}
+
+void FillLayer::run()
+{
+ switch (_output->data_type())
+ {
+ case OperandType::FLOAT32:
+ nnfw::cker::Fill<float *>(getTensorShape(_input), reinterpret_cast<int *>(_input->buffer()),
+ reinterpret_cast<float *>(_value->buffer()),
+ getTensorShape(_output),
+ reinterpret_cast<float *>(_output->buffer()));
+ break;
+ case OperandType::INT32:
+ nnfw::cker::Fill<int32_t *>(getTensorShape(_input), reinterpret_cast<int *>(_input->buffer()),
+ reinterpret_cast<int32_t *>(_value->buffer()),
+ getTensorShape(_output),
+ reinterpret_cast<int32_t *>(_output->buffer()));
+ break;
+ case OperandType::INT64:
+ nnfw::cker::Fill<int64_t *>(getTensorShape(_input), reinterpret_cast<int *>(_input->buffer()),
+ reinterpret_cast<int64_t *>(_value->buffer()),
+ getTensorShape(_output),
+ reinterpret_cast<int64_t *>(_output->buffer()));
+ break;
+ case OperandType::UINT32:
+ nnfw::cker::Fill<uint32_t *>(
+ getTensorShape(_input), reinterpret_cast<int *>(_input->buffer()),
+ reinterpret_cast<uint32_t *>(_value->buffer()), getTensorShape(_output),
+ reinterpret_cast<uint32_t *>(_output->buffer()));
+ break;
+ default:
+ throw std::runtime_error{"Fill: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/FillLayer.h b/runtime/onert/backend/cpu/ops/FillLayer.h
new file mode 100644
index 000000000..1f17d6b68
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/FillLayer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_FILLLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_FILLLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class FillLayer : public ::onert::exec::IFunction
+{
+public:
+ FillLayer();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *value,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_value;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_FILLLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/FullyConnectedLayer.cc b/runtime/onert/backend/cpu/ops/FullyConnectedLayer.cc
new file mode 100644
index 000000000..47ac1d873
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/FullyConnectedLayer.cc
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FullyConnectedLayer.h"
+
+#include "../Tensor.h"
+#include <cker/operation/FullyConnected.h>
+#include <cker/TensorUtils.h>
+#include <misc/polymorphic_downcast.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+FullyConnectedLayer::FullyConnectedLayer()
+ : _input(nullptr), _weights(nullptr), _bias(nullptr), _output(nullptr),
+ _activation(ir::Activation::NONE), _temp_arena(new nnfw::cker::FCTempArena()),
+ _external_context(nullptr), _is_hybrid(false), _is_shuffled16x1float32(false)
+{
+ // DO NOTHING
+}
+
+FullyConnectedLayer::~FullyConnectedLayer() = default;
+
+void FullyConnectedLayer::fullyConnectedFloat32()
+{
+ nnfw::cker::FullyConnectedParams op_params;
+ op_params.activation = convertActivationType(_activation);
+
+ nnfw::cker::FullyConnected(
+ op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_weights), reinterpret_cast<const float *>(_weights->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const float *>(_bias ? _bias->buffer() : nullptr),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+}
+
+// executionMutex is used to protect concurrent access of non-threadsafe resources
+// like gemmlowp::GemmContext.
+void FullyConnectedLayer::fullyConnectedQuant8()
+{
+ double real_multiplier = 0.0;
+ int32_t output_multiplier = 0;
+ int32_t output_shift = 0;
+ int32_t output_activation_min = 0;
+ int32_t output_activation_max = 0;
+ GetQuantizedConvolutionMultiplier(_input, _weights, _bias, _output, &real_multiplier);
+ QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift);
+ CalculateActivationRangeUint8(_activation, _output, &output_activation_min,
+ &output_activation_max);
+
+ nnfw::cker::FullyConnectedParams op_params;
+ op_params.input_offset = -_input->data_offset();
+ op_params.weights_offset = -_weights->data_offset();
+ op_params.output_offset = _output->data_offset();
+ op_params.output_multiplier = output_multiplier;
+ op_params.output_shift = output_shift;
+ op_params.quantized_activation_min = output_activation_min;
+ op_params.quantized_activation_max = output_activation_max;
+
+ nnfw::cker::FullyConnected(
+ op_params, getTensorShape(_input), reinterpret_cast<const uint8_t *>(_input->buffer()),
+ getTensorShape(_weights), reinterpret_cast<const uint8_t *>(_weights->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const int32_t *>(_bias ? _bias->buffer() : nullptr),
+ getTensorShape(_output), reinterpret_cast<uint8_t *>(_output->buffer()));
+}
+
+void FullyConnectedLayer::fullyConnectedHybrid()
+{
+ nnfw::cker::FCTempArena &temp_arena = *_temp_arena;
+ if (!temp_arena.prepared)
+ {
+ temp_arena.prepare(getTensorShape(_input), getTensorShape(_weights));
+ }
+
+ nnfw::cker::FullyConnectedParams op_params;
+ op_params.activation = convertActivationType(_activation);
+ op_params.weights_scale = _weights->data_scale();
+
+#ifndef USE_RUY_GEMV
+ nnfw::cker::FullyConnectedHybrid(
+ op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_weights), reinterpret_cast<const int8_t *>(_weights->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const float *>(_bias ? _bias->buffer() : nullptr),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()), temp_arena,
+ _external_context->ruy_context());
+#else
+ nnfw::cker::FullyConnectedHybrid(
+ op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_weights),
+ (_cached_weights) ? reinterpret_cast<const int8_t *>(_cached_weights)
+ : reinterpret_cast<const int8_t *>(_weights->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const float *>(_bias ? _bias->buffer() : nullptr),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()), temp_arena,
+ _external_context->ruy_context());
+
+ if (_cached_weights == nullptr || _is_weights_freed)
+ return;
+
+ // '_cached_weights is not nullptr and _is_weights_freed is false' means
+ // this weight shape is satisfied with the ruy kernel's prepack cache's condition.
+ // After entering here, it will not enter again except below the case - input is zero-vector
+
+ // if input's elements are filled with zero, it by-passes(does not enter ruy-kernel path)
+ // so that handle this case
+ const int input_size = getTensorShape(_input).FlatSize();
+ if (nnfw::cker::IsZeroVector(reinterpret_cast<float *>(_input->buffer()), input_size))
+ return;
+
+ auto weight_tensor = nnfw::misc::polymorphic_downcast<const Tensor *>(_weights);
+
+ // This weight tensor could be other ops' const tensor.
+ // Therefore, below reference should be checked like following
+ auto tensor = const_cast<Tensor *>(weight_tensor);
+ if (tensor->buffer() == nullptr) // ref is already 0?
+ {
+ _is_weights_freed = true;
+ return;
+ }
+
+ tensor->decrease_ref();
+ if (tensor->buffer() == nullptr) // ref == 0?
+ {
+ _is_weights_freed = true;
+ }
+#endif
+}
+
+void FullyConnectedLayer::fullyConnectedSparseWeight()
+{
+ nnfw::cker::FullyConnectedParams op_params;
+ op_params.activation = convertActivationType(_activation);
+
+ const uint16_t *w1_segments = _weights->sparsity()->w1_segments();
+ const uint16_t *w1_indices = _weights->sparsity()->w1_indices();
+
+ auto block_size = _weights->sparsity()->block_size();
+ if (block_size.size() == 0)
+ {
+ nnfw::cker::FullyConnectedSparseWeightRandom(
+ op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_weights), reinterpret_cast<const float *>(_weights->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const float *>(_bias ? _bias->buffer() : nullptr),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()), w1_segments,
+ w1_indices);
+ }
+ else if (block_size.size() == 2 && block_size[0] == 16 && block_size[1] == 1)
+ {
+ nnfw::cker::FullyConnectedSparseWeight16x1(
+ op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_weights), reinterpret_cast<const float *>(_weights->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const float *>(_bias ? _bias->buffer() : nullptr),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()), w1_segments,
+ w1_indices);
+ }
+ else
+ throw std::runtime_error{"FullyConnected: unsupported sparsity"};
+}
+
+void FullyConnectedLayer::fullyConnected16x1Float32()
+{
+#if defined(__aarch64__) && defined(USE_NEON)
+ float output_activation_min = 0, output_activation_max = 0;
+ CalculateActivationRange(_activation, &output_activation_min, &output_activation_max);
+
+ nnfw::cker::FullyConnectedParams op_params;
+ op_params.activation = convertActivationType(_activation);
+
+ nnfw::cker::FullyConnected16x1Float32(
+ op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_weights), reinterpret_cast<const float *>(_weights->buffer()),
+ getTensorShape(_bias), reinterpret_cast<const float *>(_bias ? _bias->buffer() : nullptr),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+#else
+ throw std::runtime_error{"FullyConnected: Shuffled16x1Float32 weights_format is not supported."};
+#endif
+}
+
+void FullyConnectedLayer::configure(const IPortableTensor *input, const IPortableTensor *weights,
+ const IPortableTensor *bias, ir::Activation activation,
+ ir::FullyConnectedWeightsFormat weights_format,
+ IPortableTensor *output,
+ const std::shared_ptr<ExternalContext> &external_context)
+{
+ _input = input;
+ _weights = weights;
+ _bias = bias;
+ _activation = activation;
+ _output = output;
+ _is_hybrid = input->data_type() == OperandType::FLOAT32 &&
+ weights->data_type() == OperandType::QUANT_INT8_SYMM;
+ _is_shuffled16x1float32 = weights_format == ir::FullyConnectedWeightsFormat::Shuffled16x1Float32;
+#if !defined(__aarch64__) || !defined(USE_NEON)
+ if (_is_shuffled16x1float32)
+ {
+ throw std::runtime_error{
+ "FullyConnected: Shuffled16x1Float32 weights_format is not supported."};
+ }
+#endif
+ _external_context = external_context;
+}
+
+void FullyConnectedLayer::run()
+{
+ if (_is_hybrid)
+ {
+ fullyConnectedHybrid();
+ }
+ else if (_weights->sparsity())
+ {
+ fullyConnectedSparseWeight();
+ }
+ else if (_input->data_type() == OperandType::FLOAT32)
+ {
+ _is_shuffled16x1float32 ? fullyConnected16x1Float32() : fullyConnectedFloat32();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ fullyConnectedQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"FullyConnected: unsupported data type"};
+ }
+}
+
+void FullyConnectedLayer::prepare()
+{
+ if (_bias && _bias->is_constant())
+ {
+ const int bias_size = getTensorShape(_bias).FlatSize();
+ if (nnfw::cker::IsZeroVector(reinterpret_cast<float *>(_bias->buffer()), bias_size))
+ {
+ _bias = nullptr;
+ }
+ }
+
+#if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && defined(USE_RUY_GEMV)
+ // TODO This is workaround
+ // The only fc hybrid will use ruy kernel
+ if (_input->data_type() != OperandType::FLOAT32 ||
+ _weights->data_type() != OperandType::QUANT_INT8_SYMM)
+ {
+ return;
+ }
+
+ // NOTE. The condition to enable caching on ruy kernel can be changed according to ruy's version
+
+ // If input is dynamic, it changes total size of input
+ // If weights is not constant, weights cannot be cached
+ if (_input->is_dynamic() || !_weights->is_constant())
+ return;
+
+ const int rows = getTensorShape(_weights).Dims(0);
+ if (rows % 4 == 0)
+ {
+ // TODO If it's possible to extract precaching from ruy kernel,
+ // place this instead of below code
+
+ // buffer will be used by ruy kernel as a cache key
+ _cached_weights = _weights->buffer();
+ }
+#endif
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/FullyConnectedLayer.h b/runtime/onert/backend/cpu/ops/FullyConnectedLayer.h
new file mode 100644
index 000000000..cd12829a0
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/FullyConnectedLayer.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_FULLYCONNECTEDLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_FULLYCONNECTEDLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "../ExternalContext.h"
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace nnfw
+{
+namespace cker
+{
+class FCTempArena;
+}
+} // namespace nnfw
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class FullyConnectedLayer : public ::onert::exec::IFunction
+{
+public:
+ FullyConnectedLayer();
+ ~FullyConnectedLayer();
+
+public:
+ void fullyConnectedFloat32();
+
+ void fullyConnectedQuant8();
+
+ void fullyConnectedHybrid();
+
+ void fullyConnectedSparseWeight();
+
+ void fullyConnected16x1Float32();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *weights,
+ const IPortableTensor *bias, ir::Activation activation,
+ ir::FullyConnectedWeightsFormat weights_format, IPortableTensor *output,
+ const std::shared_ptr<ExternalContext> &external_context);
+
+ void run() override;
+
+ void prepare() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_weights;
+ const IPortableTensor *_bias;
+ IPortableTensor *_output;
+
+ ir::Activation _activation;
+ std::unique_ptr<nnfw::cker::FCTempArena> _temp_arena;
+
+ std::shared_ptr<ExternalContext> _external_context;
+
+ bool _is_hybrid : 1;
+ bool _is_shuffled16x1float32 : 1;
+
+#ifdef USE_RUY_GEMV
+ uint8_t *_cached_weights = nullptr; // weights to be cached and a key
+ bool _is_weights_freed = false; // is weights freed?
+#endif
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_FULLYCONNECTEDLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/FusedBatchNormLayer.cc b/runtime/onert/backend/cpu/ops/FusedBatchNormLayer.cc
new file mode 100644
index 000000000..c2c592db7
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/FusedBatchNormLayer.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FusedBatchNormLayer.h"
+
+#include <cker/operation/FusedBatchNorm.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+FusedBatchNormLayer::FusedBatchNormLayer()
+ : _inputs(), _output(nullptr), _epsilon(0), _is_training(true),
+ _fusedbatchnorm_kernel(new nnfw::cker::FusedBatchNorm())
+{
+ // DO NOTHING
+}
+
+FusedBatchNormLayer::~FusedBatchNormLayer() = default;
+
+void FusedBatchNormLayer::fusedbatchnormFloat32()
+{
+ uint32_t num_inputs = _inputs.size();
+ nnfw::cker::FusedBatchNorm &kernel = *_fusedbatchnorm_kernel;
+
+ kernel.prepare();
+
+ std::vector<nnfw::cker::Shape> inputShapes;
+ std::vector<const float *> inputFloatPtrs;
+
+ for (uint32_t i = 0; i < num_inputs; i++)
+ {
+ inputShapes.emplace_back(getTensorShape(_inputs[i]));
+ inputFloatPtrs.emplace_back(reinterpret_cast<const float *>(_inputs[i]->buffer()));
+ }
+
+ nnfw::cker::FusedBatchNormParams param;
+
+ param.epsilon = _epsilon;
+ param.is_training = _is_training;
+ param.data_format = _data_format;
+
+ kernel(inputShapes, inputFloatPtrs, getTensorShape(_output),
+ reinterpret_cast<float *>(_output->buffer()), param);
+}
+
+void FusedBatchNormLayer::run()
+{
+ if (_output->data_type() == OperandType::FLOAT32)
+ {
+ fusedbatchnormFloat32();
+ }
+ else
+ {
+ throw std::runtime_error{"FusedBatchNorm: unsupported data type"};
+ }
+}
+
+void FusedBatchNormLayer::configure(const std::vector<const IPortableTensor *> &inputs,
+ float epsilon, bool is_training, std::string data_format,
+ IPortableTensor *output)
+{
+ assert(inputs.size() > 0);
+ assert(output != nullptr);
+
+ _inputs = inputs;
+ _output = output;
+ _epsilon = epsilon;
+ _is_training = is_training;
+ _data_format = data_format;
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/FusedBatchNormLayer.h b/runtime/onert/backend/cpu/ops/FusedBatchNormLayer.h
new file mode 100644
index 000000000..d42b0c900
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/FusedBatchNormLayer.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_FUSEDBATCHNORM_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_FUSEDBATCHNORM_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+#include <functional>
+#include <memory>
+
+namespace nnfw
+{
+namespace cker
+{
+class FusedBatchNorm;
+}
+} // namespace nnfw
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class FusedBatchNormLayer : public ::onert::exec::IFunction
+{
+public:
+ FusedBatchNormLayer();
+ ~FusedBatchNormLayer();
+
+public:
+ void fusedbatchnormFloat32();
+
+ void configure(const std::vector<const IPortableTensor *> &inputs, float epsilon,
+ bool is_training, std::string data_format, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ std::vector<const IPortableTensor *> _inputs;
+ IPortableTensor *_output;
+ float _epsilon;
+ bool _is_training;
+ std::string _data_format;
+
+ std::unique_ptr<nnfw::cker::FusedBatchNorm> _fusedbatchnorm_kernel;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_FUSEDBATCHNORM_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/GatherLayer.cc b/runtime/onert/backend/cpu/ops/GatherLayer.cc
new file mode 100644
index 000000000..641daa972
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/GatherLayer.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GatherLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Gather.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+void GatherLayer::configure(const IPortableTensor *input, const IPortableTensor *indices,
+ IPortableTensor *output, int32_t axis)
+{
+ _input = input;
+ _indices = indices;
+ _axis = axis;
+ _output = output;
+}
+
+template <typename InputType> void GatherLayer::runByInputType()
+{
+ using OutputType = InputType;
+ nnfw::cker::GatherParams op_params;
+ op_params.axis = _axis;
+
+ switch (_indices->data_type())
+ {
+ case OperandType::INT32:
+ {
+ using IndicesType = int32_t;
+
+ nnfw::cker::Gather<InputType, IndicesType>(
+ op_params, getTensorShape(_input), reinterpret_cast<const InputType *>(_input->buffer()),
+ getTensorShape(_indices), reinterpret_cast<const IndicesType *>(_indices->buffer()),
+ getTensorShape(_output), reinterpret_cast<OutputType *>(_output->buffer()));
+ break;
+ }
+ case OperandType::INT64:
+ {
+ using IndicesType = int64_t;
+
+ nnfw::cker::Gather<InputType, IndicesType>(
+ op_params, getTensorShape(_input), reinterpret_cast<const InputType *>(_input->buffer()),
+ getTensorShape(_indices), reinterpret_cast<const IndicesType *>(_indices->buffer()),
+ getTensorShape(_output), reinterpret_cast<OutputType *>(_output->buffer()));
+ break;
+ }
+ default:
+ throw std::runtime_error("Gather: unsupported indices data type");
+ }
+}
+
+void GatherLayer::run()
+{
+ switch (_input->data_type())
+ {
+ case OperandType::FLOAT32:
+ runByInputType<float>();
+ break;
+ case OperandType::QUANT_UINT8_ASYMM:
+ runByInputType<uint8_t>();
+ break;
+ case OperandType::INT32:
+ runByInputType<int32_t>();
+ break;
+ default:
+ throw std::runtime_error("Gather: unsupported input data type");
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/GatherLayer.h b/runtime/onert/backend/cpu/ops/GatherLayer.h
new file mode 100644
index 000000000..8fe80cc2b
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/GatherLayer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_GATHERLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_GATHERLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class GatherLayer : public ::onert::exec::IFunction
+{
+public:
+ GatherLayer() : _input{nullptr}, _indices{nullptr}, _output{nullptr}, _axis{-1}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void configure(const IPortableTensor *input, const IPortableTensor *indices,
+ IPortableTensor *output, int32_t axis);
+
+ void run() override;
+
+private:
+ template <typename OpType> void runByInputType();
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_indices;
+ IPortableTensor *_output;
+
+ int32_t _axis;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_GATHERLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/L2NormLayer.cc b/runtime/onert/backend/cpu/ops/L2NormLayer.cc
new file mode 100644
index 000000000..0d99b0586
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/L2NormLayer.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "L2NormLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/L2Normalize.h>
+#include <cker/Types.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+void L2NormLayer::configure(const IPortableTensor *input, IPortableTensor *output)
+{
+ assert(input != nullptr);
+ assert(output != nullptr);
+
+ _input = input;
+ _output = output;
+}
+
+void L2NormLayer::run()
+{
+ switch (_input->data_type())
+ {
+ case OperandType::FLOAT32:
+ nnfw::cker::L2NormalizeFloat32(
+ getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+ break;
+
+ case OperandType::QUANT_UINT8_ASYMM:
+ {
+ nnfw::cker::L2NormParams params;
+ assert(_input->data_offset() == 128);
+ params.input_zero_point = _input->data_offset();
+ nnfw::cker::L2NormalizeQuant8(
+ params, getTensorShape(_input), reinterpret_cast<const uint8_t *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<uint8_t *>(_output->buffer()));
+ }
+ break;
+
+ default:
+ throw std::runtime_error{"L2Norm: Unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/L2NormLayer.h b/runtime/onert/backend/cpu/ops/L2NormLayer.h
new file mode 100644
index 000000000..63f2d1133
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/L2NormLayer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_L2NORM_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_L2NORM_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+class L2NormLayer : public ::onert::exec::IFunction
+{
+public:
+ L2NormLayer() : _input(nullptr), _output(nullptr)
+ {
+ // Nothing
+ }
+
+public:
+ void configure(const IPortableTensor *_input, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_L2NORM_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/LSTMLayer.cc b/runtime/onert/backend/cpu/ops/LSTMLayer.cc
new file mode 100644
index 000000000..a1b67565b
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/LSTMLayer.cc
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LSTMLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/LSTM.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+namespace
+{
+template <typename T>
+T *getOptionalOutputBuffer(onert::backend::IPortableTensor *tensor, std::vector<uint8_t> *temp_vec,
+ size_t total_size)
+{
+ if (tensor == nullptr)
+ {
+ temp_vec->reserve(total_size);
+ return reinterpret_cast<T *>(temp_vec->data());
+ }
+ else
+ {
+ assert(tensor->total_size() == total_size);
+ return reinterpret_cast<T *>(tensor->buffer());
+ }
+}
+
+inline void initializeStateBuffer(const onert::backend::IPortableTensor *tensor_in, void *buffer,
+ bool needs_memcpy)
+{
+ assert(tensor_in != nullptr);
+ assert(buffer != nullptr);
+ if (needs_memcpy)
+ memcpy(buffer, tensor_in->buffer(), tensor_in->total_size());
+ else
+ memset(buffer, 0, tensor_in->total_size());
+}
+}
+
+void LSTMLayer::LSTMFloat()
+{
+ assert(_input->num_dimensions() >= 2 && _input->num_dimensions() <= 3);
+ int max_time, n_batch;
+ if (_input->num_dimensions() == 3)
+ {
+ max_time = (_time_major) ? _input->dimension(0) : _input->dimension(1);
+ n_batch = (_time_major) ? _input->dimension(1) : _input->dimension(0);
+ }
+ else
+ {
+ max_time = 1;
+ n_batch = _input->dimension(0);
+ }
+ const int n_input = _input->dimension(_input->num_dimensions() - 1);
+ const int aux_input_size = 0;
+
+ // n_cell and n_output will be the same size when there is no projection.
+ const int n_cell = _input_to_output_weights->dimension(0);
+ const int n_output = _recurrent_to_output_weights->dimension(1);
+
+ // Since we have already checked that weights are all there or none, we can
+ // check the existence of only one to the get the condition.
+ const bool use_cifg = (_input_to_input_weights == nullptr);
+
+ // Optional outputs
+ float *output_state_buf = getOptionalOutputBuffer<float>(_output_state, &_output_state_vec,
+ _output_state_in->total_size());
+ float *cell_state_buf =
+ getOptionalOutputBuffer<float>(_cell_state, &_cell_state_vec, _cell_state_in->total_size());
+
+ initializeStateBuffer(_output_state_in, output_state_buf, _has_output_state_data);
+ initializeStateBuffer(_cell_state_in, cell_state_buf, _has_cell_state_data);
+
+ // Index the scratch buffers pointers to the global scratch buffer.
+ float *scratch_buffer_buf = getOptionalOutputBuffer<float>(
+ _scratch_buffer, &_scratch_vec, n_batch * n_cell * (use_cifg ? 3 : 4) * sizeof(float));
+ float *input_gate_scratch = nullptr;
+ float *cell_gate_scratch = nullptr;
+ float *forget_gate_scratch = nullptr;
+ float *output_gate_scratch = nullptr;
+ if (use_cifg)
+ {
+ cell_gate_scratch = scratch_buffer_buf;
+ forget_gate_scratch = scratch_buffer_buf + n_cell * n_batch;
+ output_gate_scratch = scratch_buffer_buf + 2 * n_cell * n_batch;
+ }
+ else
+ {
+ input_gate_scratch = scratch_buffer_buf;
+ cell_gate_scratch = scratch_buffer_buf + n_cell * n_batch;
+ forget_gate_scratch = scratch_buffer_buf + 2 * n_cell * n_batch;
+ output_gate_scratch = scratch_buffer_buf + 3 * n_cell * n_batch;
+ }
+
+ auto optional_tensor_ptr = [](const IPortableTensor *tensor) {
+ // If tensor is not given or the tensor size is 0, consider it was not given
+ return (tensor && tensor->total_size() > 0) ? reinterpret_cast<float *>(tensor->buffer())
+ : nullptr;
+ };
+ // Optional inputs
+ float *input_to_input_weights_ptr = optional_tensor_ptr(_input_to_input_weights);
+ float *recurrent_to_input_weights_ptr = optional_tensor_ptr(_recurrent_to_input_weights);
+ float *cell_to_input_weights_ptr = optional_tensor_ptr(_cell_to_input_weights);
+ float *cell_to_forget_weights_ptr = optional_tensor_ptr(_cell_to_forget_weights);
+ float *cell_to_output_weights_ptr = optional_tensor_ptr(_cell_to_output_weights);
+ float *input_gate_bias_ptr = optional_tensor_ptr(_input_gate_bias);
+ float *projection_weights_ptr = optional_tensor_ptr(_projection_weights);
+ float *projection_bias_ptr = optional_tensor_ptr(_projection_bias);
+ float *input_layer_norm_coefficients_ptr = optional_tensor_ptr(_input_layer_norm_coefficients);
+ float *forget_layer_norm_coefficients_ptr = optional_tensor_ptr(_forget_layer_norm_coefficients);
+ float *cell_layer_norm_coefficients_ptr = optional_tensor_ptr(_cell_layer_norm_coefficients);
+ float *output_layer_norm_coefficients_ptr = optional_tensor_ptr(_output_layer_norm_coefficients);
+
+ // Copy out the LSTM specific params so they can be passed in the function.
+ nnfw::cker::LSTMParams lstm_params;
+ lstm_params.activation = convertActivationType(_params.activation);
+ lstm_params.cell_clip = _params.cell_threshold;
+ lstm_params.proj_clip = _params.projection_threshold;
+
+ const int output_batch_leading_dim = _output->dimension(_output->num_dimensions() - 1);
+ if (_time_major)
+ {
+ // Loop through the sequence.
+ const int input_step = n_batch * n_input;
+ const int output_step = n_batch * output_batch_leading_dim;
+ for (int t = 0; t < max_time; t++)
+ {
+ // If this is the forward_sequence, step forward, otherwise step
+ // backwards.
+ const int t_rel = _forward_sequence ? t : max_time - t - 1;
+ const float *input_ptr = reinterpret_cast<float *>(_input->buffer()) + t_rel * input_step;
+ const float *aux_input_ptr = nullptr;
+ if (_aux_input)
+ {
+ aux_input_ptr = reinterpret_cast<float *>(_aux_input->buffer()) + t_rel * input_step;
+ }
+ float *output_ptr =
+ reinterpret_cast<float *>(_output->buffer()) + t_rel * output_step + _output_offset;
+
+ LstmStepFloat(
+ input_ptr, input_to_input_weights_ptr,
+ reinterpret_cast<float *>(_input_to_forget_weights->buffer()),
+ reinterpret_cast<float *>(_input_to_cell_weights->buffer()),
+ reinterpret_cast<float *>(_input_to_output_weights->buffer()), aux_input_ptr,
+ /*aux_input_to_input_weights=*/nullptr,
+ /*aux_input_to_forget_weights=*/nullptr,
+ /*aux_input_to_cell_weights=*/nullptr,
+ /*aux_input_to_output_weights=*/nullptr, recurrent_to_input_weights_ptr,
+ reinterpret_cast<float *>(_recurrent_to_forget_weights->buffer()),
+ reinterpret_cast<float *>(_recurrent_to_cell_weights->buffer()),
+ reinterpret_cast<float *>(_recurrent_to_output_weights->buffer()),
+ cell_to_input_weights_ptr, cell_to_forget_weights_ptr, cell_to_output_weights_ptr,
+ input_layer_norm_coefficients_ptr, forget_layer_norm_coefficients_ptr,
+ cell_layer_norm_coefficients_ptr, output_layer_norm_coefficients_ptr, input_gate_bias_ptr,
+ reinterpret_cast<float *>(_forget_gate_bias->buffer()),
+ reinterpret_cast<float *>(_cell_gate_bias->buffer()),
+ reinterpret_cast<float *>(_output_gate_bias->buffer()), projection_weights_ptr,
+ projection_bias_ptr, &lstm_params, n_batch, n_cell, n_input, aux_input_size, n_output,
+ output_batch_leading_dim, output_state_buf, cell_state_buf, input_gate_scratch,
+ forget_gate_scratch, cell_gate_scratch, output_gate_scratch, output_ptr);
+ }
+ }
+ else
+ {
+ for (int b = 0; b < n_batch; b++)
+ {
+ const int input_step = n_input;
+ const int output_step = output_batch_leading_dim;
+ for (int t = 0; t < max_time; t++)
+ {
+ // If this is the forward_sequence, step forward, otherwise step
+ // backwards.
+ const int t_rel = _forward_sequence ? t : max_time - t - 1;
+ const int time_offset = b * max_time + t_rel;
+ const float *input_ptr =
+ reinterpret_cast<float *>(_input->buffer()) + time_offset * input_step;
+ const float *aux_input_ptr = nullptr;
+ if (_aux_input)
+ {
+ aux_input_ptr =
+ reinterpret_cast<float *>(_aux_input->buffer()) + time_offset * input_step;
+ }
+ float *output_ptr = reinterpret_cast<float *>(_output->buffer()) +
+ time_offset * output_step + _output_offset;
+
+ // Offset the {output,cell}_state pointers to the right batch.
+ float *output_state_ptr = output_state_buf + b * output_batch_leading_dim;
+ float *cell_state_ptr = cell_state_buf + b * n_cell;
+ // Offset the scratch pointers to the right batch.
+ float *input_gate_scratch_ptr =
+ input_gate_scratch ? input_gate_scratch + b * n_cell : nullptr;
+ float *forget_gate_scratch_ptr = forget_gate_scratch + b * n_cell;
+ float *cell_gate_scratch_ptr = cell_gate_scratch + b * n_cell;
+ float *output_gate_scratch_ptr = output_gate_scratch + b * n_cell;
+
+ LstmStepFloat(
+ input_ptr, input_to_input_weights_ptr,
+ reinterpret_cast<float *>(_input_to_forget_weights->buffer()),
+ reinterpret_cast<float *>(_input_to_cell_weights->buffer()),
+ reinterpret_cast<float *>(_input_to_output_weights->buffer()), aux_input_ptr,
+ /*aux_input_to_input_weights=*/nullptr,
+ /*aux_input_to_forget_weights=*/nullptr,
+ /*aux_input_to_cell_weights=*/nullptr,
+ /*aux_input_to_output_weights=*/nullptr, recurrent_to_input_weights_ptr,
+ reinterpret_cast<float *>(_recurrent_to_forget_weights->buffer()),
+ reinterpret_cast<float *>(_recurrent_to_cell_weights->buffer()),
+ reinterpret_cast<float *>(_recurrent_to_output_weights->buffer()),
+ cell_to_input_weights_ptr, cell_to_forget_weights_ptr, cell_to_output_weights_ptr,
+ input_layer_norm_coefficients_ptr, forget_layer_norm_coefficients_ptr,
+ cell_layer_norm_coefficients_ptr, output_layer_norm_coefficients_ptr,
+ input_gate_bias_ptr, reinterpret_cast<float *>(_forget_gate_bias->buffer()),
+ reinterpret_cast<float *>(_cell_gate_bias->buffer()),
+ reinterpret_cast<float *>(_output_gate_bias->buffer()), projection_weights_ptr,
+ projection_bias_ptr, &lstm_params, /*n_batch=*/1, n_cell, n_input, aux_input_size,
+ n_output, output_batch_leading_dim, output_state_ptr, cell_state_ptr,
+ input_gate_scratch_ptr, forget_gate_scratch_ptr, cell_gate_scratch_ptr,
+ output_gate_scratch_ptr, output_ptr);
+ }
+ }
+ }
+}
+
+void LSTMLayer::configure(
+ const IPortableTensor *input, const IPortableTensor *input_to_input_weights,
+ const IPortableTensor *input_to_forget_weights, const IPortableTensor *input_to_cell_weights,
+ const IPortableTensor *input_to_output_weights,
+ const IPortableTensor *recurrent_to_input_weights,
+ const IPortableTensor *recurrent_to_forget_weights,
+ const IPortableTensor *recurrent_to_cell_weights,
+ const IPortableTensor *recurrent_to_output_weights,
+ const IPortableTensor *cell_to_input_weights, const IPortableTensor *cell_to_forget_weights,
+ const IPortableTensor *cell_to_output_weights, const IPortableTensor *input_layer_norm_weights,
+ const IPortableTensor *forget_layer_norm_weights,
+ const IPortableTensor *cell_layer_norm_weights,
+ const IPortableTensor *output_layer_norm_weights, const IPortableTensor *aux_input,
+ const IPortableTensor *aux_input_to_input_weights,
+ const IPortableTensor *aux_input_to_forget_weights,
+ const IPortableTensor *aux_input_to_cell_weights,
+ const IPortableTensor *aux_input_to_output_weights, const IPortableTensor *input_gate_bias,
+ const IPortableTensor *forget_gate_bias, const IPortableTensor *cell_gate_bias,
+ const IPortableTensor *output_gate_bias, const IPortableTensor *projection_weights,
+ const IPortableTensor *projection_bias, const IPortableTensor *output_state_in,
+ const IPortableTensor *cell_state_in, const ir::operation::LSTM::Param &params,
+ bool forward_sequence, bool time_major, int output_offset, IPortableTensor *scratch_buffer,
+ IPortableTensor *output_state, IPortableTensor *cell_state, IPortableTensor *output,
+ bool has_output_state_data, bool has_cell_state_data)
+{
+ _input = input;
+ _input_to_input_weights = input_to_input_weights;
+ _input_to_forget_weights = input_to_forget_weights;
+ _input_to_cell_weights = input_to_cell_weights;
+ _input_to_output_weights = input_to_output_weights;
+ _recurrent_to_input_weights = recurrent_to_input_weights;
+ _recurrent_to_forget_weights = recurrent_to_forget_weights;
+ _recurrent_to_cell_weights = recurrent_to_cell_weights;
+ _recurrent_to_output_weights = recurrent_to_output_weights;
+ _cell_to_input_weights = cell_to_input_weights;
+ _cell_to_forget_weights = cell_to_forget_weights;
+ _cell_to_output_weights = cell_to_output_weights;
+ _input_layer_norm_coefficients = input_layer_norm_weights;
+ _forget_layer_norm_coefficients = forget_layer_norm_weights;
+ _cell_layer_norm_coefficients = cell_layer_norm_weights;
+ _output_layer_norm_coefficients = output_layer_norm_weights;
+ _aux_input = aux_input, _aux_input_to_input_weights = aux_input_to_input_weights,
+ _aux_input_to_forget_weights = aux_input_to_forget_weights,
+ _aux_input_to_cell_weights = aux_input_to_cell_weights,
+ _aux_input_to_output_weights = aux_input_to_output_weights, _input_gate_bias = input_gate_bias;
+ _forget_gate_bias = forget_gate_bias;
+ _cell_gate_bias = cell_gate_bias;
+ _output_gate_bias = output_gate_bias;
+ _projection_weights = projection_weights;
+ _projection_bias = projection_bias;
+ _output_state_in = output_state_in;
+ _cell_state_in = cell_state_in;
+ _params = params;
+ _forward_sequence = forward_sequence;
+ _time_major = time_major;
+ _output_offset = output_offset;
+ _scratch_buffer = scratch_buffer;
+ _output_state = output_state;
+ _cell_state = cell_state;
+ _output = output;
+ _has_output_state_data = has_output_state_data;
+ _has_cell_state_data = has_cell_state_data;
+}
+
+void LSTMLayer::run()
+{
+
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ LSTMFloat();
+ }
+ else
+ {
+ throw std::runtime_error{"LSTMLayer: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/LSTMLayer.h b/runtime/onert/backend/cpu/ops/LSTMLayer.h
new file mode 100644
index 000000000..5978cce63
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/LSTMLayer.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_LSTMLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_LSTMLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+#include <ir/InternalType.h>
+#include <ir/operation/LSTM.h>
+#include <exec/IFunction.h>
+
+namespace nnfw
+{
+namespace cker
+{
+class FCTempArena;
+}
+} // namespace nnfw
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+// TODO Support LSTM, BiDirectionalSequenceLSTM
+class LSTMLayer : public ::onert::exec::IFunction
+{
+public:
+ LSTMLayer() = default;
+
+public:
+ void LSTMFloat();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *input_to_input_weights,
+ const IPortableTensor *input_to_forget_weights,
+ const IPortableTensor *input_to_cell_weights,
+ const IPortableTensor *input_to_output_weights,
+ const IPortableTensor *recurrent_to_input_weights,
+ const IPortableTensor *recurrent_to_forget_weights,
+ const IPortableTensor *recurrent_to_cell_weights,
+ const IPortableTensor *recurrent_to_output_weights,
+ const IPortableTensor *cell_to_input_weights,
+ const IPortableTensor *cell_to_forget_weights,
+ const IPortableTensor *cell_to_output_weights,
+ const IPortableTensor *input_layer_norm_weights,
+ const IPortableTensor *forget_layer_norm_weights,
+ const IPortableTensor *cell_layer_norm_weights,
+ const IPortableTensor *output_layer_norm_weights, const IPortableTensor *aux_input,
+ const IPortableTensor *aux_input_to_input_weights,
+ const IPortableTensor *aux_input_to_forget_weights,
+ const IPortableTensor *aux_input_to_cell_weights,
+ const IPortableTensor *aux_input_to_output_weights,
+ const IPortableTensor *input_gate_bias, const IPortableTensor *forget_gate_bias,
+ const IPortableTensor *cell_gate_bias, const IPortableTensor *output_gate_bias,
+ const IPortableTensor *projection_weights, const IPortableTensor *projection_bias,
+ const IPortableTensor *output_state_in, const IPortableTensor *cell_state_in,
+ const ir::operation::LSTM::Param &params, bool forward_sequence, bool time_major,
+ int32_t output_offset, IPortableTensor *scratch_buffer,
+ IPortableTensor *output_state, IPortableTensor *cell_state,
+ IPortableTensor *output, bool has_output_state_data, bool has_cell_state_data);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input{nullptr};
+ const IPortableTensor *_input_to_input_weights{nullptr};
+ const IPortableTensor *_input_to_forget_weights{nullptr};
+ const IPortableTensor *_input_to_cell_weights{nullptr};
+ const IPortableTensor *_input_to_output_weights{nullptr};
+ const IPortableTensor *_recurrent_to_input_weights{nullptr};
+ const IPortableTensor *_recurrent_to_forget_weights{nullptr};
+ const IPortableTensor *_recurrent_to_cell_weights{nullptr};
+ const IPortableTensor *_recurrent_to_output_weights{nullptr};
+ const IPortableTensor *_cell_to_input_weights{nullptr};
+ const IPortableTensor *_cell_to_forget_weights{nullptr};
+ const IPortableTensor *_cell_to_output_weights{nullptr};
+ const IPortableTensor *_input_layer_norm_coefficients{nullptr};
+ const IPortableTensor *_forget_layer_norm_coefficients{nullptr};
+ const IPortableTensor *_cell_layer_norm_coefficients{nullptr};
+ const IPortableTensor *_output_layer_norm_coefficients{nullptr};
+ const IPortableTensor *_aux_input{nullptr};
+ const IPortableTensor *_aux_input_to_input_weights{nullptr};
+ const IPortableTensor *_aux_input_to_forget_weights{nullptr};
+ const IPortableTensor *_aux_input_to_cell_weights{nullptr};
+ const IPortableTensor *_aux_input_to_output_weights{nullptr};
+ const IPortableTensor *_input_gate_bias{nullptr};
+ const IPortableTensor *_forget_gate_bias{nullptr};
+ const IPortableTensor *_cell_gate_bias{nullptr};
+ const IPortableTensor *_output_gate_bias{nullptr};
+ const IPortableTensor *_projection_weights{nullptr};
+ const IPortableTensor *_projection_bias{nullptr};
+ const IPortableTensor *_output_state_in{nullptr};
+ const IPortableTensor *_cell_state_in{nullptr};
+ IPortableTensor *_scratch_buffer{nullptr};
+ IPortableTensor *_output_state{nullptr};
+ IPortableTensor *_cell_state{nullptr};
+ IPortableTensor *_output{nullptr};
+ std::vector<uint8_t> _scratch_vec{};
+ std::vector<uint8_t> _output_state_vec{};
+ std::vector<uint8_t> _cell_state_vec{};
+ ir::operation::LSTM::Param _params{};
+ bool _forward_sequence{true};
+ bool _time_major{true};
+ int32_t _output_offset{0};
+ bool _has_output_state_data{false};
+ bool _has_cell_state_data{false};
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_LSTMLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/LogSoftMaxLayer.cc b/runtime/onert/backend/cpu/ops/LogSoftMaxLayer.cc
new file mode 100644
index 000000000..1d7ee6caa
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/LogSoftMaxLayer.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LogSoftMaxLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/LogSoftMax.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+LogSoftMaxLayer::LogSoftMaxLayer() : _input(nullptr), _output(nullptr), _beta(0.0), _axis(0)
+{
+ // DO NOTHING
+}
+
+void LogSoftMaxLayer::PopulateLookupTable(const float kBeta)
+{
+ const float scale = -_input->data_scale() * kBeta;
+ const int32_t max_uint8 = std::numeric_limits<uint8_t>::max();
+ for (int32_t val = 0; val <= max_uint8; ++val)
+ {
+ _table[max_uint8 - val] = expf(scale * val);
+ }
+}
+
+void LogSoftMaxLayer::logsoftmaxFloat32()
+{
+ nnfw::cker::SoftmaxParams op_params;
+ op_params.beta = _beta;
+ op_params.axis = _axis;
+ nnfw::cker::LogSoftmax(op_params, getTensorShape(_input),
+ reinterpret_cast<const float *>(_input->buffer()), getTensorShape(_output),
+ reinterpret_cast<float *>(_output->buffer()));
+}
+
+void LogSoftMaxLayer::logsoftmaxQuant8()
+{
+ nnfw::cker::SoftmaxParams op_params;
+ op_params.beta = _beta;
+ op_params.axis = _axis;
+ op_params.table = _table;
+ op_params.zero_point = _output->data_offset();
+ op_params.scale = _output->data_scale();
+ nnfw::cker::LogSoftmax(op_params, _input->data_scale(), getTensorShape(_input),
+ reinterpret_cast<const uint8_t *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<uint8_t *>(_output->buffer()));
+}
+
+void LogSoftMaxLayer::configure(const IPortableTensor *input, const float beta, const int axis,
+ IPortableTensor *output)
+{
+ _input = input;
+ _output = output;
+ _beta = beta;
+ _axis = axis;
+ if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ PopulateLookupTable(_beta);
+ }
+}
+
+void LogSoftMaxLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ logsoftmaxFloat32();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ logsoftmaxQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"LogSoftmax : unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/LogSoftMaxLayer.h b/runtime/onert/backend/cpu/ops/LogSoftMaxLayer.h
new file mode 100644
index 000000000..1533f3361
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/LogSoftMaxLayer.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_LOGSOFTMAXLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_LOGSOFTMAXLAYER_H__
+
+#include "../Tensor.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class LogSoftMaxLayer : public ::onert::exec::IFunction
+{
+public:
+ LogSoftMaxLayer();
+
+public:
+ void logsoftmaxFloat32();
+
+ void logsoftmaxQuant8();
+
+ void configure(const IPortableTensor *input, const float beta, const int axis,
+ IPortableTensor *output);
+
+ void run();
+
+ void PopulateLookupTable(const float kBeta);
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+
+ float _beta;
+ int _axis;
+ float _table[256];
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_LOGSOFTMAXLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/MatrixBandPartLayer.cc b/runtime/onert/backend/cpu/ops/MatrixBandPartLayer.cc
new file mode 100644
index 000000000..b770cce5d
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/MatrixBandPartLayer.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MatrixBandPartLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/MatrixBandPart.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+MatrixBandPartLayer::MatrixBandPartLayer()
+ : _input(nullptr), _num_lower_diag(nullptr), _num_upper_diag(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void MatrixBandPartLayer::matrixBandPartFloat32()
+{
+ if (_num_lower_diag->data_type() == OperandType::INT64)
+ {
+ nnfw::cker::MatrixBandPart<int64_t>(
+ *reinterpret_cast<const int64_t *>(_num_lower_diag->buffer()),
+ *reinterpret_cast<const int64_t *>(_num_upper_diag->buffer()), getTensorShape(_input),
+ reinterpret_cast<const float *>(_input->buffer()), getTensorShape(_output),
+ reinterpret_cast<float *>(_output->buffer()));
+ }
+ else
+ {
+ nnfw::cker::MatrixBandPart<int32_t>(
+ *reinterpret_cast<const int32_t *>(_num_lower_diag->buffer()),
+ *reinterpret_cast<const int32_t *>(_num_upper_diag->buffer()), getTensorShape(_input),
+ reinterpret_cast<const float *>(_input->buffer()), getTensorShape(_output),
+ reinterpret_cast<float *>(_output->buffer()));
+ }
+}
+
+void MatrixBandPartLayer::matrixBandPartQuant8() { throw std::runtime_error{"NYI"}; }
+
+void MatrixBandPartLayer::configure(const IPortableTensor *input,
+ const IPortableTensor *num_lower_diag,
+ const IPortableTensor *num_upper_diag, IPortableTensor *output)
+{
+ _input = input;
+ _num_lower_diag = num_lower_diag;
+ _num_upper_diag = num_upper_diag;
+ _output = output;
+}
+
+void MatrixBandPartLayer::run()
+{
+ if (_num_lower_diag->data_type() != _num_upper_diag->data_type())
+ {
+ throw std::runtime_error{"MatrixBandpart: num_lower and num_upper must have the same type"};
+ }
+
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ matrixBandPartFloat32();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ matrixBandPartQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"MatrixBandpart: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/MatrixBandPartLayer.h b/runtime/onert/backend/cpu/ops/MatrixBandPartLayer.h
new file mode 100644
index 000000000..9dcc6b277
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/MatrixBandPartLayer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_MATRIXBANDPARTLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_MATRIXBANDPARTLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class MatrixBandPartLayer : public ::onert::exec::IFunction
+{
+public:
+ MatrixBandPartLayer();
+
+public:
+ void matrixBandPartFloat32();
+
+ void matrixBandPartQuant8();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *num_lower_diag,
+ const IPortableTensor *num_upper_diag, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_num_lower_diag;
+ const IPortableTensor *_num_upper_diag;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_MATRIXBANDPARTLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/MeanLayer.cc b/runtime/onert/backend/cpu/ops/MeanLayer.cc
new file mode 100644
index 000000000..4921ac748
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/MeanLayer.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MeanLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/ReduceMean.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+MeanLayer::MeanLayer() : _input(nullptr), _axes(nullptr), _output(nullptr), _keep_dims(false)
+{
+ // DO NOTHING
+}
+
+void MeanLayer::MeanFloat32()
+{
+ nnfw::cker::Mean(getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()),
+ getReducerAxes(_axes));
+}
+
+void MeanLayer::MeanQuant8()
+{
+ nnfw::cker::MeanQ8Asymm(getTensorShape(_input),
+ reinterpret_cast<const uint8_t *>(_input->buffer()), _input->data_scale(),
+ _input->data_offset(), getTensorShape(_output),
+ reinterpret_cast<uint8_t *>(_output->buffer()), _output->data_scale(),
+ _output->data_offset(), getReducerAxes(_axes));
+}
+
+void MeanLayer::configure(const IPortableTensor *input, const IPortableTensor *axes,
+ IPortableTensor *output, bool keep_dims)
+{
+ _input = input;
+ _axes = axes;
+ _output = output;
+ _keep_dims = keep_dims;
+}
+
+void MeanLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ MeanFloat32();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ MeanQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"Mean: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/MeanLayer.h b/runtime/onert/backend/cpu/ops/MeanLayer.h
new file mode 100644
index 000000000..3e95c1203
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/MeanLayer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_MEANLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_MEANLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class MeanLayer : public ::onert::exec::IFunction
+{
+public:
+ MeanLayer();
+
+public:
+ void MeanFloat32();
+
+ void MeanQuant8();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *axes, IPortableTensor *output,
+ bool keep_dims);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_axes;
+ IPortableTensor *_output;
+ bool _keep_dims;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_MEANLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/OneHotLayer.cc b/runtime/onert/backend/cpu/ops/OneHotLayer.cc
new file mode 100644
index 000000000..2a82b00ee
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/OneHotLayer.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OneHotLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/OneHot.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+template <typename T> void OneHotLayer::oneHotImpl()
+{
+ // It assumes index is int32_t type.
+ nnfw::cker::OneHot<T, int32_t>(
+ *reinterpret_cast<const int32_t *>(_depth->buffer()),
+ *reinterpret_cast<T *>(_on_value->buffer()), *reinterpret_cast<T *>(_off_value->buffer()),
+ _axis, getTensorShape(_indices), reinterpret_cast<const int32_t *>(_indices->buffer()),
+ getTensorShape(_output), reinterpret_cast<T *>(_output->buffer()));
+}
+
+void OneHotLayer::configure(const IPortableTensor *indices, const IPortableTensor *depth,
+ const IPortableTensor *on_value, const IPortableTensor *off_value,
+ IPortableTensor *output, const int32_t axis)
+{
+ _indices = indices;
+ _output = output;
+ _depth = depth;
+ _on_value = on_value;
+ _off_value = off_value;
+ _axis = axis;
+}
+
+void OneHotLayer::run()
+{
+ if (_output->data_type() == OperandType::FLOAT32)
+ {
+ oneHotImpl<float>();
+ }
+ else
+ {
+ throw std::runtime_error{"OneHot: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/OneHotLayer.h b/runtime/onert/backend/cpu/ops/OneHotLayer.h
new file mode 100644
index 000000000..c05498440
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/OneHotLayer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_ONEHOTLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_ONEHOTLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class OneHotLayer : public ::onert::exec::IFunction
+{
+public:
+ OneHotLayer()
+ : _indices(nullptr), _depth(nullptr), _on_value(nullptr), _off_value(nullptr),
+ _output(nullptr), _axis(-1)
+ {
+ // DO NOTHING
+ }
+
+public:
+ template <typename T> void oneHotImpl();
+
+ void configure(const IPortableTensor *indices, const IPortableTensor *depth,
+ const IPortableTensor *on_value, const IPortableTensor *off_value,
+ IPortableTensor *output, int32_t axis);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_indices;
+ const IPortableTensor *_depth;
+ const IPortableTensor *_on_value;
+ const IPortableTensor *_off_value;
+ IPortableTensor *_output;
+
+ int32_t _axis;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_ONEHOTLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/OperationUtils.cc b/runtime/onert/backend/cpu/ops/OperationUtils.cc
new file mode 100644
index 000000000..2eee6dc85
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/OperationUtils.cc
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OperationUtils.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+uint32_t getNumberOfDimensions(const IPortableTensor *tensor)
+{
+ assert(tensor);
+ return tensor->num_dimensions();
+}
+
+uint32_t getNumberOfElements(const IPortableTensor *tensor)
+{
+ assert(tensor);
+ uint32_t count = 1;
+ for (size_t i = 0; i < tensor->num_dimensions(); i++)
+ {
+ count *= tensor->dimension(i);
+ }
+ return count;
+}
+
+uint32_t getSizeOfDimension(const IPortableTensor *tensor, uint32_t dimensionIdx)
+{
+ assert(tensor);
+ if (dimensionIdx >= tensor->num_dimensions())
+ {
+ // TODO, log the error
+ return 0;
+ }
+ return tensor->dimension(dimensionIdx);
+}
+
+void QuantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift)
+{
+ if (double_multiplier == 0.)
+ {
+ *quantized_multiplier = 0;
+ *shift = 0;
+ return;
+ }
+ const double q = std::frexp(double_multiplier, shift);
+ auto q_fixed = static_cast<int64_t>(std::round(q * (1ll << 31)));
+
+ assert(q_fixed <= (1ll << 31));
+ if (q_fixed == (1ll << 31))
+ {
+ q_fixed /= 2;
+ ++*shift;
+ }
+ assert(q_fixed <= std::numeric_limits<int32_t>::max());
+ *quantized_multiplier = static_cast<int32_t>(q_fixed);
+}
+
+void GetQuantizedConvolutionMultiplier(const IPortableTensor *input, const IPortableTensor *filter,
+ const IPortableTensor *bias, const IPortableTensor *output,
+ double *multiplier)
+{
+ const double input_product_scale = input->data_scale() * filter->data_scale();
+ const double bias_scale = (bias != nullptr) ? bias->data_scale() : input_product_scale;
+ const double output_scale = output->data_scale();
+ // The following conditions must be guaranteed by the training pipeline.
+ UNUSED_RELEASE(bias_scale);
+ assert(std::abs(input_product_scale - bias_scale) <=
+ 1e-6 * std::min(input_product_scale, bias_scale));
+ assert(input_product_scale >= 0);
+ assert(input_product_scale < output_scale);
+ *multiplier = input_product_scale / output_scale;
+}
+
+void QuantizeMultiplierGreaterThanOne(double double_multiplier, int32_t *quantized_multiplier,
+ int *left_shift)
+{
+ assert(double_multiplier > 1.);
+ const double q = std::frexp(double_multiplier, left_shift);
+ int64_t q_fixed = static_cast<int64_t>(std::round(q * (1ll << 31)));
+ assert(q_fixed <= (1ll << 31));
+ if (q_fixed == (1ll << 31))
+ {
+ q_fixed /= 2;
+ ++*left_shift;
+ }
+ assert(*left_shift >= 0);
+ assert(q_fixed <= std::numeric_limits<int32_t>::max());
+ *quantized_multiplier = static_cast<int32_t>(q_fixed);
+}
+
+void CalculateActivationRangeUint8(ir::Activation activation, const IPortableTensor *output,
+ int32_t *act_min, int32_t *act_max)
+{
+ const int32_t qmin = std::numeric_limits<uint8_t>::min();
+ const int32_t qmax = std::numeric_limits<uint8_t>::max();
+ const auto scale = output->data_scale();
+ const auto zero_point = output->data_offset();
+ auto quantize = [scale, zero_point](float f) {
+ return zero_point + static_cast<int32_t>(std::round(f / scale));
+ };
+ if (activation == ir::Activation::RELU)
+ {
+ *act_min = std::max(qmin, quantize(0.0));
+ *act_max = qmax;
+ }
+ else if (activation == ir::Activation::RELU6)
+ {
+ *act_min = std::max(qmin, quantize(0.0));
+ *act_max = std::min(qmax, quantize(6.0));
+ }
+ else if (activation == ir::Activation::RELU1)
+ {
+ *act_min = std::max(qmin, quantize(-1.0));
+ *act_max = std::min(qmax, quantize(1.0));
+ }
+ else if (activation == ir::Activation::SIGMOID)
+ {
+ *act_min = std::max(qmin, quantize(0.0));
+ *act_max = std::min(qmax, quantize(1.0));
+ }
+ else if (activation == ir::Activation::NONE)
+ {
+ *act_min = qmin;
+ *act_max = qmax;
+ }
+ else
+ {
+ std::cout << "Unsupported fused activation function." << std::endl;
+ }
+}
+
+bool HaveSameShapes(const IPortableTensor *input1, const IPortableTensor *input2)
+{
+ if (input1 == input2)
+ return true;
+ if (input2 == NULL || input2 == NULL)
+ return false;
+
+ if (input1 == NULL)
+ {
+ return (getNumberOfDimensions(input2) == 0);
+ }
+
+ if (getNumberOfDimensions(input1) != getNumberOfDimensions(input2))
+ return false;
+
+ for (uint32_t i = 0; i < getNumberOfDimensions(input1); i++)
+ if (input1->dimension(i) != input2->dimension(i))
+ return false;
+
+ return true;
+}
+
+int32_t CalculateInputRadius(int input_integer_bits, int input_left_shift)
+{
+ const double max_input_rescaled = 1.0 * ((1 << input_integer_bits) - 1) *
+ (1ll << (31 - input_integer_bits)) / (1ll << input_left_shift);
+ // Tighten bound using floor. Suppose that we could use the exact value.
+ // After scaling the difference, the result would be at the maximum. Thus we
+ // must ensure that our value has lower magnitude.
+ return static_cast<int32_t>(std::floor(max_input_rescaled));
+}
+
+uint32_t sizeOfData(OperandType type, const std::vector<int32_t> &dimensions)
+{
+ uint32_t size = 4;
+
+ switch (type)
+ {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ size = 4;
+ break;
+ case OperandType::BOOL8:
+ case OperandType::QUANT_UINT8_ASYMM:
+ case OperandType::QUANT_INT8_SYMM:
+ size = 1;
+ break;
+ case OperandType::INT64:
+ size = 8;
+ break;
+ default:
+ throw std::runtime_error("Not supported operand type.");
+ break;
+ }
+
+ for (auto d : dimensions)
+ {
+ assert(d >= 0);
+ size *= static_cast<uint32_t>(d);
+ }
+
+ return size;
+}
+
+nnfw::cker::PaddingType getPaddingType(ir::PaddingType ir_padding_type)
+{
+ switch (ir_padding_type)
+ {
+ case ir::PaddingType::EXPLICIT:
+ return nnfw::cker::PaddingType::kNone;
+ case ir::PaddingType::SAME:
+ return nnfw::cker::PaddingType::kSame;
+ case ir::PaddingType::VALID:
+ return nnfw::cker::PaddingType::kValid;
+ default:
+ throw std::runtime_error("Wrong padding type.");
+ break;
+ }
+}
+
+std::vector<int32_t> getReducerAxes(const IPortableTensor *axes)
+{
+ std::vector<int32_t> ret;
+
+ assert(axes->layout() == ir::Layout::NHWC);
+ assert(axes->dimension(0) == axes->getShape().num_elements());
+ switch (axes->data_type())
+ {
+ case ir::DataType::INT32:
+ {
+ for (size_t i = 0; i < axes->dimension(0); ++i)
+ ret.emplace_back(*(reinterpret_cast<const int32_t *>(axes->buffer()) + i));
+ break;
+ }
+ case ir::DataType::INT64:
+ {
+ for (size_t i = 0; i < axes->dimension(0); ++i)
+ ret.emplace_back(*(reinterpret_cast<const int64_t *>(axes->buffer()) + i));
+ break;
+ }
+ default:
+ throw std::runtime_error("getReducerAxes: Not supported data type");
+ break;
+ }
+ return ret;
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/OperationUtils.h b/runtime/onert/backend/cpu/ops/OperationUtils.h
new file mode 100644
index 000000000..ea44aeb7a
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/OperationUtils.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NNFW_SUPPORT_NNAPI_OPERATION_UTILS_H__
+#define __NNFW_SUPPORT_NNAPI_OPERATION_UTILS_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <cker/Shape.h>
+#include <cker/Types.h>
+#include <iostream>
+#include <ir/DataType.h>
+#include <ir/InternalType.h>
+#include <ir/Operand.h>
+#include <ir/Padding.h>
+
+#include <limits>
+#include <vector>
+
+using OperandType = onert::ir::DataType;
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+union DataPtr {
+ uint8_t *u8;
+ int8_t *i8;
+ uint32_t *u32;
+ int32_t *i32;
+ bool *b;
+ float *f;
+ int64_t *i64;
+ void *v;
+};
+
+union ConstDataPtr {
+ const uint8_t *u8;
+ const int8_t *i8;
+ const uint32_t *u32;
+ const int32_t *i32;
+ const bool *b;
+ const float *f;
+ const int64_t *i64;
+ const void *v;
+};
+
+uint32_t getNumberOfDimensions(const IPortableTensor *tensor);
+
+uint32_t getNumberOfElements(const IPortableTensor *tensor);
+
+uint32_t getSizeOfDimension(const IPortableTensor *tensor, uint32_t dimensionIdx);
+
+inline nnfw::cker::Shape getExtendedTensorShape(const IPortableTensor *tensor)
+{
+ assert(tensor);
+ const int32_t extended_rank = 4;
+ int32_t raw_shape[extended_rank];
+ uint32_t src = extended_rank - tensor->num_dimensions();
+ for (uint32_t i = 0; i < extended_rank; ++i)
+ {
+ if (i < src)
+ {
+ raw_shape[i] = 1;
+ }
+ else
+ {
+ raw_shape[i] = tensor->dimension(i - src);
+ }
+ }
+
+ return nnfw::cker::Shape(extended_rank, raw_shape);
+}
+
+inline nnfw::cker::Shape getTensorShape(const IPortableTensor *tensor)
+{
+ if (tensor == nullptr)
+ return nnfw::cker::Shape();
+
+ const ir::Shape &shape = tensor->get_info().shape();
+
+ assert(tensor->layout() == ir::Layout::NHWC);
+
+ auto rank = shape.rank();
+ nnfw::cker::Shape ret(rank);
+ auto data = ret.DimsData();
+ for (int i = 0; i < rank; ++i)
+ {
+ data[i] = shape.dim(i);
+ }
+ return ret;
+}
+
+inline nnfw::cker::FusedActivationFunctionType
+convertActivationType(const ir::Activation activation)
+{
+ switch (activation)
+ {
+ case ir::Activation::NONE:
+ return nnfw::cker::FusedActivationFunctionType::kNone;
+ case ir::Activation::RELU:
+ return nnfw::cker::FusedActivationFunctionType::kRelu;
+ case ir::Activation::RELU1:
+ return nnfw::cker::FusedActivationFunctionType::kRelu1;
+ case ir::Activation::RELU6:
+ return nnfw::cker::FusedActivationFunctionType::kRelu6;
+ case ir::Activation::TANH:
+ return nnfw::cker::FusedActivationFunctionType::kTanh;
+ case ir::Activation::SIGMOID:
+ return nnfw::cker::FusedActivationFunctionType::kSigmoid;
+ default:
+ throw std::runtime_error{"CPU backend: Cannot convert activation type"};
+ }
+}
+
+inline int32_t getAxis(uint32_t rank, int32_t axis, ir::Layout frontend_layout)
+{
+ auto ret = axis;
+
+ if (axis < 0)
+ {
+ ret += rank;
+ }
+
+ // NCHW -> NHWC
+ if (frontend_layout == ir::Layout::NCHW)
+ {
+ int32_t permutation[4] = {0, 3, 1, 2};
+ ret = permutation[ret];
+ }
+
+ return ret;
+}
+
+void QuantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift);
+
+void GetQuantizedConvolutionMultiplier(const IPortableTensor *inputDescr,
+ const IPortableTensor *filterDescr,
+ const IPortableTensor *biasDescr,
+ const IPortableTensor *outputDescr, double *multiplier);
+
+void QuantizeMultiplierGreaterThanOne(double double_multiplier, int32_t *quantized_multiplier,
+ int *left_shift);
+
+template <typename T>
+void CalculateActivationRange(ir::Activation activation, T *activation_min, T *activation_max)
+{
+ if (activation == ir::Activation::RELU)
+ {
+ *activation_min = 0;
+ *activation_max = std::numeric_limits<T>::max();
+ }
+ else if (activation == ir::Activation::RELU6)
+ {
+ *activation_min = 0;
+ *activation_max = 6;
+ }
+ else if (activation == ir::Activation::RELU1)
+ {
+ *activation_min = -1;
+ *activation_max = 1;
+ }
+ else if (activation == ir::Activation::SIGMOID)
+ {
+ *activation_min = 0;
+ *activation_max = 1;
+ }
+ else if (activation == ir::Activation::NONE)
+ {
+ *activation_min = std::numeric_limits<T>::lowest();
+ *activation_max = std::numeric_limits<T>::max();
+ }
+ else
+ {
+ std::cout << "Unsupported fused activation function." << std::endl;
+ }
+}
+
+void CalculateActivationRangeUint8(ir::Activation activation, const IPortableTensor *output,
+ int32_t *act_min, int32_t *act_max);
+
+bool HaveSameShapes(const IPortableTensor *input1, const IPortableTensor *input2);
+
+int32_t CalculateInputRadius(int input_integer_bits, int input_left_shift);
+
+uint32_t sizeOfData(OperandType type, const std::vector<int32_t> &dimensions);
+
+nnfw::cker::PaddingType getPaddingType(ir::PaddingType ir_padding_type);
+
+std::vector<int32_t> getReducerAxes(const IPortableTensor *axes);
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __NNFW_SUPPORT_NNAPI_OPERATION_UTILS_H__
diff --git a/runtime/onert/backend/cpu/ops/PackLayer.cc b/runtime/onert/backend/cpu/ops/PackLayer.cc
new file mode 100644
index 000000000..314b192a2
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/PackLayer.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PackLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Pack.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+PackLayer::PackLayer() : _inputs(), _output(nullptr), _axis(0)
+{
+ // DO NOTHING
+}
+
+template <typename T> void PackLayer::packImpl()
+{
+ uint32_t num_inputs = _inputs.size();
+ nnfw::cker::PackParams op_params;
+ op_params.axis = _axis;
+ op_params.inputs_count = num_inputs;
+
+ std::vector<nnfw::cker::Shape *> inputDimsPtr;
+ std::vector<nnfw::cker::Shape> inputDims;
+ inputDimsPtr.reserve(num_inputs);
+ inputDims.reserve(num_inputs);
+
+ for (uint32_t i = 0; i < num_inputs; i++)
+ {
+ inputDims.push_back(getTensorShape(_inputs[i]));
+ inputDimsPtr.push_back(&inputDims[i]);
+ }
+
+ std::vector<const T *> inputPtrs;
+
+ for (const auto input : _inputs)
+ {
+ inputPtrs.emplace_back(reinterpret_cast<const T *>(input->buffer()));
+ }
+
+ nnfw::cker::Pack<T>(op_params, inputPtrs.data(), getTensorShape(_output),
+ reinterpret_cast<T *>(_output->buffer()));
+}
+
+void PackLayer::configure(const std::vector<const IPortableTensor *> &inputs, int32_t axis,
+ IPortableTensor *output)
+{
+ assert(inputs.size() > 0);
+ assert(output != nullptr);
+
+ _inputs = inputs;
+ _axis = axis;
+ _output = output;
+}
+
+void PackLayer::run()
+{
+ if (_output->data_type() == OperandType::FLOAT32)
+ {
+ packImpl<float>();
+ }
+ else if (_output->data_type() == OperandType::INT32)
+ {
+ packImpl<int32_t>();
+ }
+ else
+ {
+ throw std::runtime_error{"Pack: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/PackLayer.h b/runtime/onert/backend/cpu/ops/PackLayer.h
new file mode 100644
index 000000000..b92c8d48c
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/PackLayer.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_PACKLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_PACKLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class PackLayer : public ::onert::exec::IFunction
+{
+public:
+ PackLayer();
+
+public:
+ template <typename T> void packImpl();
+
+ void configure(const std::vector<const IPortableTensor *> &inputs, int32_t axis,
+ IPortableTensor *output);
+ void run() override;
+
+private:
+ std::vector<const IPortableTensor *> _inputs;
+ IPortableTensor *_output;
+ int32_t _axis;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_PACKLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/PadLayer.cc b/runtime/onert/backend/cpu/ops/PadLayer.cc
new file mode 100644
index 000000000..6a2bf9da0
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/PadLayer.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PadLayer.h"
+
+#include <cker/operation/Pad.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+PadLayer::PadLayer()
+ : _input(nullptr), _output(nullptr), _padData(), _padRank(), _constantValueData()
+{
+ // DO NOTHING
+}
+
+template <typename T> void PadLayer::padImpl(const T *constant_value_data)
+{
+ nnfw::cker::Pad<T>(_padData, _padRank, getTensorShape(_input),
+ reinterpret_cast<const T *>(_input->buffer()), getTensorShape(_output),
+ reinterpret_cast<T *>(_output->buffer()), constant_value_data);
+}
+
+void PadLayer::configure(const IPortableTensor *input, IPortableTensor *output,
+ const int32_t *padData, int32_t padRank, const void *constantValueData)
+{
+ _input = input;
+ _output = output;
+ memcpy(_padData, padData, sizeof(_padData));
+ _padRank = padRank;
+ _constantValueData.v = constantValueData;
+}
+
+void PadLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ padImpl<float>(_constantValueData.f);
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ if (_constantValueData.u8 == nullptr)
+ {
+ uint8_t pad_value = static_cast<uint8_t>(_output->data_offset());
+ padImpl<uint8_t>(&pad_value);
+ }
+ else
+ {
+ padImpl<uint8_t>(_constantValueData.u8);
+ }
+ }
+ else
+ {
+ throw std::runtime_error{"Pad: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/PadLayer.h b/runtime/onert/backend/cpu/ops/PadLayer.h
new file mode 100644
index 000000000..efd73d5e5
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/PadLayer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_PADLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_PADLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+// Note, this is pad with mode=`CONSTANT`: it doesn't support `REFLECT` and
+// `SYMMETRIC`
+class PadLayer : public ::onert::exec::IFunction
+{
+public:
+ PadLayer();
+
+public:
+ template <typename T> void padImpl(const T *constant_value_data);
+
+ void configure(const IPortableTensor *input, IPortableTensor *output, const int32_t *padData,
+ int32_t padRank, const void *constantValueData = nullptr);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+
+ int32_t _padData[8];
+ int32_t _padRank;
+ ConstDataPtr _constantValueData;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_PADLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/PoolLayer.cc b/runtime/onert/backend/cpu/ops/PoolLayer.cc
new file mode 100644
index 000000000..85d02a751
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/PoolLayer.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PoolLayer.h"
+
+#include <cker/operation/AveragePool.h>
+#include <cker/operation/MaxPool.h>
+
+#include <unordered_map>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+namespace
+{
+template <typename T>
+void avgPool2D(const nnfw::cker::PoolParams &params, const IPortableTensor *input,
+ IPortableTensor *output)
+{
+ nnfw::cker::AveragePool<T>(params, getTensorShape(input),
+ reinterpret_cast<const T *>(input->buffer()), getTensorShape(output),
+ reinterpret_cast<T *>(output->buffer()));
+}
+
+template <typename T>
+void maxPool2D(const nnfw::cker::PoolParams &params, const IPortableTensor *input,
+ IPortableTensor *output)
+{
+ nnfw::cker::MaxPool<T>(params, getTensorShape(input),
+ reinterpret_cast<const T *>(input->buffer()), getTensorShape(output),
+ reinterpret_cast<T *>(output->buffer()));
+}
+
+template <typename T>
+std::function<void(const IPortableTensor *, IPortableTensor *)>
+generateKernelGeneric(const nnfw::cker::PoolParams &params, PoolType op_type)
+{
+ if (op_type == PoolType::kAvg)
+ {
+ return std::bind(&avgPool2D<T>, params, std::placeholders::_1, std::placeholders::_2);
+ }
+ else if (op_type == PoolType::kMax)
+ {
+ return std::bind(&maxPool2D<T>, params, std::placeholders::_1, std::placeholders::_2);
+ }
+ else
+ {
+ throw std::runtime_error{"Pool: unsupported pool type"};
+ }
+}
+} // namespace
+
+PoolLayer::PoolLayer() : _input(nullptr), _output(nullptr), _kernel()
+{
+ // DO NOTHING
+}
+
+#define POOLING_PARAMETERS \
+ nnfw::cker::PoolParams op_params; \
+ op_params.stride_height = strideHeight; \
+ op_params.stride_width = strideWidth; \
+ op_params.filter_height = kernelHeight; \
+ op_params.filter_width = kernelWidth; \
+ op_params.padding_values.height = (int8_t)paddingTop; \
+ op_params.padding_values.width = (int8_t)paddingLeft;
+
+void PoolLayer::configure(const IPortableTensor *input, const uint32_t paddingLeft, const uint32_t,
+ const uint32_t paddingTop, const uint32_t, const uint32_t strideWidth,
+ const uint32_t strideHeight, const uint32_t kernelWidth,
+ const uint32_t kernelHeight, const ir::Activation activation,
+ IPortableTensor *output, const PoolType op_type)
+{
+ assert(input != nullptr);
+ assert(output != nullptr);
+
+ _input = input;
+ _output = output;
+
+ POOLING_PARAMETERS
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ float output_activation_min = 0;
+ float output_activation_max = 0;
+ CalculateActivationRange<float>(activation, &output_activation_min, &output_activation_max);
+ op_params.float_activation_min = output_activation_min;
+ op_params.float_activation_max = output_activation_max;
+
+ _kernel = generateKernelGeneric<float>(op_params, op_type);
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ int32_t output_activation_min = 0;
+ int32_t output_activation_max = 0;
+ CalculateActivationRangeUint8(activation, _output, &output_activation_min,
+ &output_activation_max);
+ op_params.quantized_activation_min = output_activation_min;
+ op_params.quantized_activation_max = output_activation_max;
+ _kernel = generateKernelGeneric<uint8_t>(op_params, op_type);
+ }
+ else
+ {
+ throw std::runtime_error{"Pool: unsupported data type"};
+ }
+}
+
+void PoolLayer::run() { _kernel(_input, _output); }
+
+#undef AVGPOOLING_PARAMETERS
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/PoolLayer.h b/runtime/onert/backend/cpu/ops/PoolLayer.h
new file mode 100644
index 000000000..b37835946
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/PoolLayer.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_POOLLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_POOLLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+enum class PoolType
+{
+ kAvg,
+ kL2,
+ kMax,
+};
+
+class PoolLayer : public ::onert::exec::IFunction
+{
+public:
+ PoolLayer();
+
+public:
+ void configure(const IPortableTensor *input, const uint32_t paddingLeft,
+ const uint32_t paddingRight, const uint32_t paddingTop,
+ const uint32_t paddingBottom, const uint32_t strideWidth,
+ const uint32_t strideHeight, const uint32_t kernelWidth,
+ const uint32_t kernelHeight, const ir::Activation activation,
+ IPortableTensor *output, const PoolType op_type);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+
+ std::function<void(const IPortableTensor *, IPortableTensor *)> _kernel;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_POOLLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/PowLayer.cc b/runtime/onert/backend/cpu/ops/PowLayer.cc
new file mode 100644
index 000000000..04a1af1e1
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/PowLayer.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PowLayer.h"
+
+#include <cker/operation/Pow.h>
+#include <cker/operation/BinaryArithmeticOps.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+void PowLayer::powFloat32()
+{
+ float output_activation_min = 0, output_activation_max = 0;
+ CalculateActivationRange(_activation, &output_activation_min, &output_activation_max);
+ nnfw::cker::BinaryArithmeticOpParam op_params;
+ op_params.float_activation_max = output_activation_max;
+ op_params.float_activation_min = output_activation_min;
+
+ if (!HaveSameShapes(_lhs, _rhs))
+ {
+ nnfw::cker::BroadcastBinaryArithmeticOp<nnfw::cker::BinaryArithmeticOpType::POW>(
+ op_params, getTensorShape(_lhs), reinterpret_cast<const float *>(_lhs->buffer()),
+ getTensorShape(_rhs), reinterpret_cast<const float *>(_rhs->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+ return;
+ }
+
+ nnfw::cker::powImpl(getTensorShape(_lhs), reinterpret_cast<const float *>(_lhs->buffer()),
+ getTensorShape(_rhs), reinterpret_cast<const float *>(_rhs->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+}
+
+void PowLayer::configure(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ ir::Activation activation, IPortableTensor *output)
+{
+ _lhs = lhs;
+ _rhs = rhs;
+ _activation = activation;
+ _output = output;
+}
+
+void PowLayer::run()
+{
+ if (_output->data_type() == OperandType::FLOAT32)
+ powFloat32();
+ else
+ throw std::runtime_error{"Pow: unsupportted data type"};
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/PowLayer.h b/runtime/onert/backend/cpu/ops/PowLayer.h
new file mode 100644
index 000000000..2689aad17
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/PowLayer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_POWLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_POWLAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class PowLayer : public ::onert::exec::IFunction
+{
+public:
+ PowLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr)
+ {
+ // DO NOTHING
+ }
+
+public:
+ void powFloat32();
+
+ void configure(const IPortableTensor *lhs, const IPortableTensor *rhs,
+ const ir::Activation activation, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_lhs;
+ const IPortableTensor *_rhs;
+ IPortableTensor *_output;
+
+ ir::Activation _activation{ir::Activation::NONE};
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_POWLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/RangeLayer.cc b/runtime/onert/backend/cpu/ops/RangeLayer.cc
new file mode 100644
index 000000000..f00101fa8
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/RangeLayer.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RangeLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Range.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+RangeLayer::RangeLayer() : _start(nullptr), _limit(nullptr), _delta(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void RangeLayer::configure(const IPortableTensor *start, const IPortableTensor *limit,
+ const IPortableTensor *delta, IPortableTensor *output)
+{
+ _start = start;
+ _limit = limit;
+ _delta = delta;
+ _output = output;
+}
+
+void RangeLayer::run()
+{
+ switch (_output->data_type())
+ {
+ case OperandType::FLOAT32:
+ nnfw::cker::Range<float>(reinterpret_cast<float *>(_start->buffer()),
+ reinterpret_cast<float *>(_limit->buffer()),
+ reinterpret_cast<float *>(_delta->buffer()),
+ reinterpret_cast<float *>(_output->buffer()));
+ break;
+ case OperandType::INT32:
+ nnfw::cker::Range<int32_t>(reinterpret_cast<int32_t *>(_start->buffer()),
+ reinterpret_cast<int32_t *>(_limit->buffer()),
+ reinterpret_cast<int32_t *>(_delta->buffer()),
+ reinterpret_cast<int32_t *>(_output->buffer()));
+ break;
+ default:
+ throw std::runtime_error{"Range: unsupported data type"};
+ break;
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/RangeLayer.h b/runtime/onert/backend/cpu/ops/RangeLayer.h
new file mode 100644
index 000000000..2d83b39b1
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/RangeLayer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_RANGELAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_RANGELAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+class RangeLayer : public ::onert::exec::IFunction
+{
+public:
+ RangeLayer();
+
+ void configure(const IPortableTensor *start, const IPortableTensor *limit,
+ const IPortableTensor *delta, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_start;
+ const IPortableTensor *_limit;
+ const IPortableTensor *_delta;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_RANGELAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/RankLayer.cc b/runtime/onert/backend/cpu/ops/RankLayer.cc
new file mode 100644
index 000000000..184f4925b
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/RankLayer.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RankLayer.h"
+
+#include "OperationUtils.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+RankLayer::RankLayer() : _input(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void RankLayer::configure(const IPortableTensor *input, IPortableTensor *output)
+{
+ _input = input;
+ _output = output;
+}
+
+void RankLayer::run()
+{
+ int32_t *output_data = reinterpret_cast<int32_t *>(_output->buffer());
+ output_data[0] = _input->num_dimensions();
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/RankLayer.h b/runtime/onert/backend/cpu/ops/RankLayer.h
new file mode 100644
index 000000000..6282ceb07
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/RankLayer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_RANKLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_RANKLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class RankLayer : public ::onert::exec::IFunction
+{
+public:
+ RankLayer();
+
+public:
+ void configure(const IPortableTensor *input, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_RANKLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ReduceLayer.cc b/runtime/onert/backend/cpu/ops/ReduceLayer.cc
new file mode 100644
index 000000000..4a55b2a33
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ReduceLayer.cc
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ReduceLayer.h"
+
+#include "OperationUtils.h"
+
+#include "cker/neon/neon_check.h"
+#include <cker/operation/Reduce.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+namespace
+{
+
+template <typename T>
+void evalLogic(const IPortableTensor *input, IPortableTensor *output, const std::vector<int> &axes,
+ bool keep_dims, T init_value, nnfw::cker::Reduce &reduce_kernel,
+ T reducer(const T current, const T in))
+{
+ reduce_kernel.prepare(input->num_dimensions(), axes.size());
+ bool result = reduce_kernel.ReduceGeneric<T>(
+ getTensorShape(input), reinterpret_cast<const T *>(input->buffer()), getTensorShape(output),
+ reinterpret_cast<T *>(output->buffer()), axes, keep_dims, init_value, reducer);
+
+ if (!result)
+ {
+ throw std::runtime_error{"Reduce: Fail to run"};
+ }
+}
+
+template <typename T>
+std::function<void(const IPortableTensor *, IPortableTensor *, const std::vector<int> &)>
+evalType(bool keep_dims, nnfw::cker::Reduce &reduce_kernel, ReduceType reduce_type)
+{
+ switch (reduce_type)
+ {
+ case ReduceType::kSum:
+ return std::bind(&evalLogic<T>, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, keep_dims, static_cast<T>(0), reduce_kernel,
+ [](const T current, const T in) -> T { return in + current; });
+ break;
+ case ReduceType::kProd:
+ return std::bind(&evalLogic<T>, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, keep_dims, static_cast<T>(1), reduce_kernel,
+ [](const T current, const T in) -> T { return in * current; });
+ break;
+ case ReduceType::kMax:
+ return std::bind(
+ &evalLogic<T>, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
+ keep_dims, std::numeric_limits<T>::lowest(), reduce_kernel,
+ [](const T current, const T in) -> T { return (in > current) ? in : current; });
+ break;
+ case ReduceType::kMin:
+ return std::bind(
+ &evalLogic<T>, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
+ keep_dims, std::numeric_limits<T>::max(), reduce_kernel,
+ [](const T current, const T in) -> T { return (in < current) ? in : current; });
+ break;
+ default:
+ throw std::runtime_error{"Reduce: Unsupported reduce type"};
+ }
+}
+
+// Template specialization for bool type
+template <>
+std::function<void(const IPortableTensor *, IPortableTensor *, const std::vector<int> &)>
+evalType<bool>(bool keep_dims, nnfw::cker::Reduce &reduce_kernel, ReduceType reduce_type)
+{
+ switch (reduce_type)
+ {
+ case ReduceType::kAny:
+ return std::bind(&evalLogic<bool>, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, keep_dims, false, reduce_kernel,
+ [](const bool current, const bool in) -> bool { return in || current; });
+ break;
+ case ReduceType::kAll:
+ return std::bind(&evalLogic<bool>, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, keep_dims, true, reduce_kernel,
+ [](const bool current, const bool in) -> bool { return in && current; });
+ break;
+ default:
+ throw std::runtime_error{"Reduce: Unsupported reduce type"};
+ }
+}
+
+std::function<void(const IPortableTensor *, IPortableTensor *, const std::vector<int> &)>
+generateKernelGeneric(const IPortableTensor *input, bool keep_dims,
+ nnfw::cker::Reduce &reduce_kernel, ReduceType reduce_type)
+{
+ switch (input->data_type())
+ {
+ case OperandType::FLOAT32:
+ return evalType<float>(keep_dims, reduce_kernel, reduce_type);
+ case OperandType::INT32:
+ return evalType<int32_t>(keep_dims, reduce_kernel, reduce_type);
+ case OperandType::BOOL8:
+ return evalType<bool>(keep_dims, reduce_kernel, reduce_type);
+ default:
+ throw std::runtime_error{"Reduce(generic): unsupported data type"};
+ }
+}
+
+// TODO Refine this function
+void evalSumQuantized(const IPortableTensor *input, IPortableTensor *output,
+ const std::vector<int> &axes, bool keep_dims,
+ nnfw::cker::Reduce &reduce_kernel)
+{
+ const bool same_scale = (input->data_scale() == output->data_scale() &&
+ input->data_offset() == output->data_offset());
+
+ reduce_kernel.prepare(input->num_dimensions(), axes.size());
+
+ if (!same_scale)
+ {
+ std::vector<int32_t> temp_sum(output->getShape().num_elements());
+ bool result = reduce_kernel.QuantizedMeanOrSum<uint8_t, int32_t>(
+ reinterpret_cast<const uint8_t *>(input->buffer()), input->data_offset(),
+ input->data_scale(), getTensorShape(input), reinterpret_cast<uint8_t *>(output->buffer()),
+ output->data_offset(), output->data_scale(), getTensorShape(output), axes, keep_dims,
+ temp_sum.data(), true, [](const int32_t current, const uint8_t in) -> int32_t {
+ const int32_t actual_in = static_cast<int32_t>(in);
+ return current + actual_in;
+ });
+
+ if (!result)
+ {
+ throw std::runtime_error{"Reduce: Fail to run"};
+ }
+
+ return;
+ }
+
+ const auto kernel = generateKernelGeneric(input, keep_dims, reduce_kernel, ReduceType::kSum);
+ kernel(input, output, axes);
+}
+
+} // namespace
+
+ReduceLayer::ReduceLayer()
+ : _input(nullptr), _axes(nullptr), _output(nullptr), _reduce_kernel(new nnfw::cker::Reduce()),
+ _kernel(), _reduceType(ReduceType::kInvalid)
+{
+ // DO NOTHING
+}
+
+ReduceLayer::~ReduceLayer() = default;
+
+void ReduceLayer::configure(const IPortableTensor *input, const IPortableTensor *axes,
+ IPortableTensor *output, ReduceType reduceType, bool keep_dims)
+{
+ _input = input;
+ _axes = axes;
+ _output = output;
+ _reduceType = reduceType;
+
+ switch (_reduceType)
+ {
+ case ReduceType::kSum:
+ if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ _kernel = std::bind(&evalSumQuantized, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, keep_dims, *_reduce_kernel);
+ return;
+ }
+ _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kSum);
+ break;
+ case ReduceType::kProd:
+ _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kProd);
+ break;
+ case ReduceType::kMax:
+ _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kMax);
+ break;
+ case ReduceType::kMin:
+ _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kMin);
+ break;
+ case ReduceType::kAny:
+ _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kAny);
+ break;
+ case ReduceType::kAll:
+ _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kAll);
+ break;
+ default:
+ throw std::runtime_error{"Reduce: Unsupported reduce type"};
+ }
+}
+
+void ReduceLayer::run()
+{
+ const auto axes = getReducerAxes(_axes);
+#ifdef USE_NEON
+ int32_t rank = _input->num_dimensions();
+ if (_input->data_type() == ir::DataType::FLOAT32 && _reduceType == ReduceType::kSum &&
+ axes.size() == 1 && (axes[0] == -1 || axes[0] == rank - 1))
+ {
+ OptimizedReduceSum(reinterpret_cast<const float *>(_input->buffer()), getTensorShape(_input),
+ reinterpret_cast<float *>(_output->buffer()));
+ return;
+ }
+#endif // NEON
+ _kernel(_input, _output, axes);
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ReduceLayer.h b/runtime/onert/backend/cpu/ops/ReduceLayer.h
new file mode 100644
index 000000000..8265dd41f
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ReduceLayer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_REDUCESUMLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_REDUCESUMLAYER_H__
+
+#include "cker/neon/neon_check.h"
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+#include <memory>
+
+namespace nnfw
+{
+namespace cker
+{
+class Reduce;
+}
+} // namespace nnfw
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+enum class ReduceType
+{
+ kSum,
+ kProd,
+ kMax,
+ kMin,
+ kAny,
+ kAll,
+ kInvalid // For debug and initialize
+};
+
+class ReduceLayer : public ::onert::exec::IFunction
+{
+public:
+ ReduceLayer();
+ ~ReduceLayer();
+
+public:
+ void configure(const IPortableTensor *input, const IPortableTensor *axes, IPortableTensor *output,
+ ReduceType reduceType, bool keep_dims);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_axes;
+ IPortableTensor *_output;
+
+ std::unique_ptr<nnfw::cker::Reduce> _reduce_kernel;
+ std::function<void(const IPortableTensor *input, IPortableTensor *output,
+ const std::vector<int> &axes)>
+ _kernel;
+
+ ReduceType _reduceType;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_REDUCESUMLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ReshapeLayer.cc b/runtime/onert/backend/cpu/ops/ReshapeLayer.cc
new file mode 100644
index 000000000..3c2b115f4
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ReshapeLayer.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ReshapeLayer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+ReshapeLayer::ReshapeLayer() : _input(nullptr), _shape(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void ReshapeLayer::reshapeGeneric()
+{
+ size_t count = _input->total_size();
+ memcpy(_output->buffer(), _input->buffer(), count);
+}
+
+void ReshapeLayer::configure(const IPortableTensor *input, const IPortableTensor *shape,
+ IPortableTensor *output)
+{
+ _input = input;
+ /* note : shape is optional. If not provided from model, _shape is nullptr. */
+ _shape = shape;
+ _output = output;
+}
+
+void ReshapeLayer::run() { reshapeGeneric(); }
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ReshapeLayer.h b/runtime/onert/backend/cpu/ops/ReshapeLayer.h
new file mode 100644
index 000000000..b49c0bf7d
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ReshapeLayer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_RESHAPELAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_RESHAPELAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class ReshapeLayer : public ::onert::exec::IFunction
+{
+public:
+ ReshapeLayer();
+
+public:
+ void reshapeGeneric();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *shape,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_shape;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_RESHAPELAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ResizeBilinearLayer.cc b/runtime/onert/backend/cpu/ops/ResizeBilinearLayer.cc
new file mode 100644
index 000000000..1fe56cb99
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ResizeBilinearLayer.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "OperationUtils.h"
+#include "ResizeBilinearLayer.h"
+#include "cker/operation/ResizeBilinear.h"
+#include <cker/Types.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+ResizeBilinearLayer::ResizeBilinearLayer()
+ : _input(nullptr), _output(nullptr), _size(nullptr), _output_height(0), _output_width(0),
+ _align_corners(false), _half_pixel_centers(false)
+{
+ // DO NOTHING
+}
+
+void ResizeBilinearLayer::configure(const IPortableTensor *input, IPortableTensor *output,
+ const IPortableTensor *size, bool align_corners,
+ bool half_pixel_centers)
+{
+ assert(!size->is_constant());
+ _input = input;
+ _output = output;
+ _size = size;
+ _align_corners = align_corners;
+ _half_pixel_centers = half_pixel_centers;
+}
+
+void ResizeBilinearLayer::configure(const IPortableTensor *input, IPortableTensor *output,
+ int32_t output_height, int32_t output_width, bool align_corners,
+ bool half_pixel_centers)
+{
+ assert(_size == nullptr);
+ if (output_height < 0)
+ {
+ throw std::runtime_error{"ResizeBilinear: size value must be positive value, output_height = " +
+ std::to_string(output_height)};
+ }
+ if (output_width < 0)
+ {
+ throw std::runtime_error{"ResizeBilinear: size value must be positive value, output_width = " +
+ std::to_string(output_width)};
+ }
+ _input = input;
+ _output = output;
+ _output_height = output_height;
+ _output_width = output_width;
+ _align_corners = align_corners;
+ _half_pixel_centers = half_pixel_centers;
+}
+
+void ResizeBilinearLayer::run()
+{
+ nnfw::cker::ResizeBilinearParams params;
+ if (_size == nullptr)
+ {
+ params.output_height = _output_height;
+ params.output_width = _output_width;
+ }
+ else
+ {
+ const auto size_buf = reinterpret_cast<const int32_t *>(_size->buffer());
+ params.output_height = size_buf[0];
+ params.output_width = size_buf[1];
+ }
+ params.align_corners = _align_corners;
+ params.half_pixel_centers = _half_pixel_centers;
+
+ switch (_input->data_type())
+ {
+ case OperandType::FLOAT32:
+ nnfw::cker::ResizeBilinear(
+ params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+ break;
+
+ case OperandType::QUANT_UINT8_ASYMM:
+ nnfw::cker::ResizeBilinear(
+ params, getTensorShape(_input), reinterpret_cast<const uint8_t *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<uint8_t *>(_output->buffer()));
+ break;
+
+ case OperandType::UINT8:
+ case OperandType::BOOL8:
+ case OperandType::FLOAT16:
+ case OperandType::INT32:
+ case OperandType::INT64:
+ case OperandType::QUANT_INT8_SYMM:
+ std::runtime_error("ResizeBilinear NYI");
+ break;
+ default:
+ std::runtime_error("ResizeBilinear unsupported data type");
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ResizeBilinearLayer.h b/runtime/onert/backend/cpu/ops/ResizeBilinearLayer.h
new file mode 100644
index 000000000..d7ae1c620
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ResizeBilinearLayer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_RESIZEBILINEAR_H__
+#define __ONERT_BACKEND_CPU_OPS_RESIZEBILINEAR_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class ResizeBilinearLayer : public ::onert::exec::IFunction
+{
+public:
+ ResizeBilinearLayer();
+
+public:
+ void configure(const IPortableTensor *input1, IPortableTensor *output,
+ const IPortableTensor *size, bool align_corners, bool half_pixel_centers);
+
+ void configure(const IPortableTensor *input, IPortableTensor *output, int32_t output_height,
+ int32_t output_width, bool align_corners, bool half_pixel_centers);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+ const IPortableTensor *_size;
+ int32_t _output_height;
+ int32_t _output_width;
+ bool _align_corners;
+ bool _half_pixel_centers;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_RESIZEBILINEAR_H__
diff --git a/runtime/onert/backend/cpu/ops/ReverseLayer.cc b/runtime/onert/backend/cpu/ops/ReverseLayer.cc
new file mode 100644
index 000000000..7979e77a0
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ReverseLayer.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ReverseLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Reverse.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+void ReverseLayer::run()
+{
+
+ if (_axis->total_size() != 4)
+ {
+ throw std::runtime_error{"Reverse: only support 1 axis"};
+ }
+ int32_t axis = *(reinterpret_cast<int32_t *>(_axis->buffer()));
+ if (axis < 0)
+ {
+ axis += _input->num_dimensions();
+ }
+
+ switch (_input->data_type())
+ {
+ case OperandType::FLOAT32:
+ nnfw::cker::Reverse<float>(
+ axis, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+ break;
+ default:
+ throw std::runtime_error{"Reverse: unsupported data type"};
+ }
+}
+
+void ReverseLayer::configure(const IPortableTensor *input, const IPortableTensor *axis,
+ IPortableTensor *output)
+{
+ _input = input;
+ _axis = axis;
+ _output = output;
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ReverseLayer.h b/runtime/onert/backend/cpu/ops/ReverseLayer.h
new file mode 100644
index 000000000..9591dae32
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ReverseLayer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_REVERSE_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_REVERSE_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class ReverseLayer : public ::onert::exec::IFunction
+{
+public:
+ ReverseLayer() : _input{nullptr}, _axis{nullptr}, _output{nullptr}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void configure(const IPortableTensor *input, const IPortableTensor *axis,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_axis;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_REVERSE_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/SelectLayer.cc b/runtime/onert/backend/cpu/ops/SelectLayer.cc
new file mode 100644
index 000000000..95cfe1df0
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SelectLayer.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SelectLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Select.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+SelectLayer::SelectLayer()
+ : _cond(nullptr), _input_true(nullptr), _input_false(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void SelectLayer::configure(const IPortableTensor *cond, const IPortableTensor *input_true,
+ const IPortableTensor *input_false, IPortableTensor *output)
+{
+ _cond = cond;
+ _input_true = input_true;
+ _input_false = input_false;
+ _output = output;
+}
+
+void SelectLayer::run()
+{
+
+#define KERNEL_SELECT(type, op) \
+ nnfw::cker::op(getTensorShape(_cond), reinterpret_cast<uint8_t *>(_cond->buffer()), \
+ getTensorShape(_input_true), reinterpret_cast<type *>(_input_true->buffer()), \
+ getTensorShape(_input_false), reinterpret_cast<type *>(_input_false->buffer()), \
+ getTensorShape(_output), reinterpret_cast<type *>(_output->buffer()));
+
+#define KERNEL_SWITCH(type, op) \
+ switch (type) \
+ { \
+ break; \
+ case OperandType::FLOAT32: \
+ KERNEL_SELECT(float, op); \
+ break; \
+ default: \
+ throw std::runtime_error{"Select: unsupported data type"}; \
+ }
+
+ auto input_type = _input_true->data_type();
+ bool require_broadcast =
+ !HaveSameShapes(_input_true, _cond) || !HaveSameShapes(_input_false, _cond);
+ bool rank_one_select = ((_input_true->num_dimensions() == 1) && !require_broadcast);
+
+ if (rank_one_select)
+ {
+ KERNEL_SWITCH(input_type, RankOneSelect);
+ }
+ else if (require_broadcast)
+ {
+ KERNEL_SWITCH(input_type, BroadcastSelect4DSlow);
+ }
+ else
+ {
+ KERNEL_SWITCH(input_type, Select);
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/SelectLayer.h b/runtime/onert/backend/cpu/ops/SelectLayer.h
new file mode 100644
index 000000000..2ef50f369
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SelectLayer.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SELECT_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SELECT_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class SelectLayer : public ::onert::exec::IFunction
+{
+public:
+ SelectLayer();
+
+public:
+ void configure(const IPortableTensor *cond, const IPortableTensor *input_true,
+ const IPortableTensor *input_false, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_cond;
+ const IPortableTensor *_input_true;
+ const IPortableTensor *_input_false;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SELECT_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/ShapeLayer.cc b/runtime/onert/backend/cpu/ops/ShapeLayer.cc
new file mode 100644
index 000000000..7268a89fa
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ShapeLayer.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ShapeLayer.h"
+
+#include "OperationUtils.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+ShapeLayer::ShapeLayer() : _input(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+template <typename T> void GetRawShape(const IPortableTensor *input, T *output_data)
+{
+ for (uint32_t i = 0; i < input->num_dimensions(); ++i)
+ {
+ output_data[i] = static_cast<T>(input->dimension(i));
+ }
+}
+
+void ShapeLayer::configure(const IPortableTensor *input, IPortableTensor *output)
+{
+ _input = input;
+ _output = output;
+}
+
+void ShapeLayer::run()
+{
+ if (_output->data_type() == OperandType::UINT32)
+ {
+ GetRawShape(_input, reinterpret_cast<uint32_t *>(_output->buffer()));
+ }
+ else if (_output->data_type() == OperandType::INT32)
+ {
+ GetRawShape(_input, reinterpret_cast<int32_t *>(_output->buffer()));
+ }
+ else if (_output->data_type() == OperandType::INT64)
+ {
+ GetRawShape(_input, reinterpret_cast<int64_t *>(_output->buffer()));
+ }
+ else
+ {
+ throw std::runtime_error{"NYI : not supported output type for ShapeLayer"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/ShapeLayer.h b/runtime/onert/backend/cpu/ops/ShapeLayer.h
new file mode 100644
index 000000000..bd2a7abde
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/ShapeLayer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SHAPELAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SHAPELAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class ShapeLayer : public ::onert::exec::IFunction
+{
+public:
+ ShapeLayer();
+
+public:
+ void configure(const IPortableTensor *input, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SHAPELAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/SliceLayer.cc b/runtime/onert/backend/cpu/ops/SliceLayer.cc
new file mode 100644
index 000000000..449c073e6
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SliceLayer.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SliceLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Slice.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+SliceLayer::SliceLayer() : _input(nullptr), _begin(nullptr), _size(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+template <typename T>
+void SliceLayer::GetBeginAndSizeVectors(int dimensions, const IPortableTensor *begin,
+ const IPortableTensor *size, std::vector<int> *begins,
+ std::vector<int> *sizes)
+{
+ for (int idx = dimensions - 1; idx >= 0; --idx)
+ {
+ begins->push_back(reinterpret_cast<T *>(begin->buffer())[idx]);
+ sizes->push_back(reinterpret_cast<T *>(size->buffer())[idx]);
+ }
+}
+
+template <typename T> void SliceLayer::sliceImpl()
+{
+ const int kMaxDim = nnfw::cker::Shape::kMaxSmallSize;
+
+ std::vector<int> begins;
+ std::vector<int> sizes;
+ begins.reserve(kMaxDim);
+ sizes.reserve(kMaxDim);
+
+ GetBeginAndSizeVectors<int32_t>(_input->num_dimensions(), _begin, _size, &begins, &sizes);
+
+ // begins : 0-based, sizes : 1-based
+ for (int i = _input->num_dimensions(); i < kMaxDim; ++i)
+ {
+ begins.push_back(0);
+ sizes.push_back(1);
+ }
+
+ nnfw::cker::SliceParams op_params;
+ op_params.begin_count = 4;
+ op_params.size_count = 4;
+ for (int i = 0; i < 4; ++i)
+ {
+ op_params.begin[i] = begins[3 - i];
+ op_params.size[i] = sizes[3 - i];
+ }
+
+ nnfw::cker::Slice(op_params, getExtendedTensorShape(_input),
+ reinterpret_cast<const T *>(_input->buffer()),
+ reinterpret_cast<T *>(_output->buffer()));
+}
+
+void SliceLayer::configure(const IPortableTensor *input, const IPortableTensor *begin,
+ const IPortableTensor *size, IPortableTensor *output)
+{
+ _input = input;
+ _output = output;
+ _begin = begin;
+ _size = size;
+}
+
+void SliceLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ sliceImpl<float>();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ sliceImpl<uint8_t>();
+ }
+ else
+ {
+ throw std::runtime_error{"Slice: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/SliceLayer.h b/runtime/onert/backend/cpu/ops/SliceLayer.h
new file mode 100644
index 000000000..650e2c97a
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SliceLayer.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SLICELAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SLICELAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class SliceLayer : public ::onert::exec::IFunction
+{
+public:
+ SliceLayer();
+
+public:
+ void configure(const IPortableTensor *input, const IPortableTensor *begin,
+ const IPortableTensor *size, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ template <typename T> void sliceImpl();
+
+ template <typename T>
+ void GetBeginAndSizeVectors(int dimensions, const IPortableTensor *begin,
+ const IPortableTensor *size, std::vector<int> *begins,
+ std::vector<int> *sizes);
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_begin;
+ const IPortableTensor *_size;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SLICELAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/SoftMaxLayer.cc b/runtime/onert/backend/cpu/ops/SoftMaxLayer.cc
new file mode 100644
index 000000000..b42be3042
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SoftMaxLayer.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SoftMaxLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/SoftMax.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+SoftMaxLayer::SoftMaxLayer() : _input(nullptr), _output(nullptr), _beta(0.0)
+{
+ // DO NOTHING
+}
+
+void SoftMaxLayer::softmaxFloat32()
+{
+ if (getNumberOfDimensions(_input) == 1)
+ {
+ uint32_t input_size = getNumberOfElements(_input);
+ nnfw::cker::Softmax(reinterpret_cast<const float *>(_input->buffer()), input_size, 1, _beta,
+ reinterpret_cast<float *>(_output->buffer()));
+ }
+ else if (getNumberOfDimensions(_input) == 2)
+ {
+ uint32_t batch_size = getSizeOfDimension(_input, 0);
+ if (batch_size == 0)
+ throw std::runtime_error("batch_size should not be 0");
+
+ uint32_t input_size = getNumberOfElements(_input) / batch_size;
+ nnfw::cker::Softmax(reinterpret_cast<const float *>(_input->buffer()), input_size, batch_size,
+ _beta, reinterpret_cast<float *>(_output->buffer()));
+ }
+ else if (getNumberOfDimensions(_input) == 4)
+ {
+ nnfw::cker::SoftmaxParams op_params;
+ op_params.beta = _beta;
+ nnfw::cker::Softmax(op_params, getTensorShape(_input),
+ reinterpret_cast<const float *>(_input->buffer()), getTensorShape(_output),
+ reinterpret_cast<float *>(_output->buffer()));
+ }
+ else
+ {
+ nnfw::cker::SoftmaxParams op_params;
+ op_params.beta = _beta;
+ nnfw::cker::reference::Softmax(
+ op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+ }
+}
+
+void SoftMaxLayer::softmaxQuant8()
+{
+ nnfw::cker::Shape descrIn4D(4);
+
+ if (getNumberOfDimensions(_input) == 2)
+ {
+ auto batch_size = getSizeOfDimension(_input, 0);
+ if (batch_size == 0)
+ throw std::runtime_error("batch_size should not be 0");
+
+ auto input_size = getNumberOfElements(_input) / batch_size;
+ descrIn4D.SetDim(0, batch_size);
+ descrIn4D.SetDim(1, 1);
+ descrIn4D.SetDim(2, 1);
+ descrIn4D.SetDim(3, input_size);
+ }
+ else if (getNumberOfDimensions(_input) == 4)
+ {
+ descrIn4D.SetDim(0, _input->dimension(0));
+ descrIn4D.SetDim(1, _input->dimension(1));
+ descrIn4D.SetDim(2, _input->dimension(2));
+ descrIn4D.SetDim(3, _input->dimension(3));
+ }
+ else
+ {
+ throw std::runtime_error{"only 2D and 4D tensors supported"};
+ }
+ if (_output->data_offset() != 0 || _output->data_scale() != 1.f / 256)
+ {
+ throw std::runtime_error{"incorrect scale / offset for output"};
+ }
+ static const int32_t kScaledDiffIntegerBits = 5;
+ const double input_beta_real_multiplier = std::min(
+ 1.0 * _beta * _input->data_scale() * (1 << (31 - kScaledDiffIntegerBits)), (1ll << 31) - 1.0);
+ int32_t input_multiplier = 0;
+ int32_t input_left_shift = 0;
+ QuantizeMultiplierGreaterThanOne(input_beta_real_multiplier, &input_multiplier,
+ &input_left_shift);
+ float diff_min = -1.0f * CalculateInputRadius(kScaledDiffIntegerBits, input_left_shift);
+
+ nnfw::cker::SoftmaxParams op_params;
+ op_params.input_multiplier = input_multiplier;
+ op_params.input_left_shift = input_left_shift;
+ op_params.diff_min = diff_min;
+ nnfw::cker::Softmax(op_params, descrIn4D, reinterpret_cast<const uint8_t *>(_input->buffer()),
+ descrIn4D, reinterpret_cast<uint8_t *>(_output->buffer()));
+}
+
+void SoftMaxLayer::configure(const IPortableTensor *input, const float beta,
+ IPortableTensor *output)
+{
+ _input = input;
+ _output = output;
+ _beta = beta;
+}
+
+void SoftMaxLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ softmaxFloat32();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ softmaxQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"SoftMax: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/SoftMaxLayer.h b/runtime/onert/backend/cpu/ops/SoftMaxLayer.h
new file mode 100644
index 000000000..d0c704c2c
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SoftMaxLayer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SOFTMAXLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SOFTMAXLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class SoftMaxLayer : public ::onert::exec::IFunction
+{
+public:
+ SoftMaxLayer();
+
+public:
+ void softmaxFloat32();
+
+ void softmaxQuant8();
+
+ void configure(const IPortableTensor *input, const float beta, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ IPortableTensor *_output;
+
+ float _beta;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SOFTMAXLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/SpaceToBatchNDLayer.cc b/runtime/onert/backend/cpu/ops/SpaceToBatchNDLayer.cc
new file mode 100644
index 000000000..896e262ba
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SpaceToBatchNDLayer.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SpaceToBatchNDLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/SpaceToBatchND.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+SpaceToBatchNDLayer::SpaceToBatchNDLayer()
+ : _input(nullptr), _block_shape(nullptr), _padding(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+// TO DO : move into shape inferer
+void SpaceToBatchNDLayer::checkDimension()
+{
+ const int kSpatialDimensionNum = 2;
+ if (_block_shape->dimension(0) != kSpatialDimensionNum)
+ {
+ throw std::runtime_error("SpaceToBatchND : block_shape(block_size) tensor's rank is wrong\n");
+ }
+
+ // Ensures the input height and width (with padding) is a multiple of block
+ // shape height and width.
+ for (int dim = 0; dim < kSpatialDimensionNum; ++dim)
+ {
+ int final_dim_size =
+ (_input->dimension(dim + 1) + reinterpret_cast<int32_t *>(_padding->buffer())[dim * 2] +
+ reinterpret_cast<int32_t *>(_padding->buffer())[dim * 2 + 1]);
+
+ if (final_dim_size % reinterpret_cast<int32_t *>(_block_shape->buffer())[dim] != 0)
+ {
+ throw std::runtime_error(
+ "SpaceToBatchND : padded input's dimension is not a multiple of block size\n");
+ }
+
+ if ((int32_t)_output->dimension(dim + 1) !=
+ final_dim_size / reinterpret_cast<int32_t *>(_block_shape->buffer())[dim])
+ {
+ throw std::runtime_error("SpaceToBatchND : wrong output dimension\n");
+ }
+ }
+}
+
+template <> uint32_t SpaceToBatchNDLayer::getPad<float>() { return 0; }
+template <> uint32_t SpaceToBatchNDLayer::getPad<uint8_t>() { return _output->data_offset(); }
+
+template <typename T> void SpaceToBatchNDLayer::spaceToBatchND()
+{
+ checkDimension();
+
+ nnfw::cker::SpaceToBatchParams params;
+ params.output_offset = getPad<T>();
+
+ nnfw::cker::SpaceToBatchND(
+ params, getTensorShape(_input), reinterpret_cast<const T *>(_input->buffer()),
+ getTensorShape(_block_shape), reinterpret_cast<const int32_t *>(_block_shape->buffer()),
+ getTensorShape(_padding), reinterpret_cast<const int32_t *>(_padding->buffer()),
+ getTensorShape(_output), reinterpret_cast<T *>(_output->buffer()));
+}
+
+void SpaceToBatchNDLayer::configure(const IPortableTensor *input,
+ const IPortableTensor *block_shape,
+ const IPortableTensor *padding, IPortableTensor *output)
+{
+ _input = input;
+ _block_shape = block_shape;
+ _padding = padding;
+ _output = output;
+}
+
+void SpaceToBatchNDLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ spaceToBatchND<float>();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ spaceToBatchND<uint8_t>();
+ }
+ else
+ {
+ throw std::runtime_error{"SpaceToBatchND: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/SpaceToBatchNDLayer.h b/runtime/onert/backend/cpu/ops/SpaceToBatchNDLayer.h
new file mode 100644
index 000000000..6f4638719
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SpaceToBatchNDLayer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SPACE_TO_BATCH_ND_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SPACE_TO_BATCH_ND_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+class SpaceToBatchNDLayer : public ::onert::exec::IFunction
+{
+public:
+ SpaceToBatchNDLayer();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *block_shape,
+ const IPortableTensor *padding, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ void checkDimension();
+
+ template <typename T> uint32_t getPad();
+
+ template <typename T> void spaceToBatchND();
+
+ const IPortableTensor *_input;
+ const IPortableTensor *_block_shape;
+ const IPortableTensor *_padding;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SPACE_TO_BATCH_ND_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/SpaceToDepthLayer.cc b/runtime/onert/backend/cpu/ops/SpaceToDepthLayer.cc
new file mode 100644
index 000000000..a0869aed8
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SpaceToDepthLayer.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SpaceToDepthLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/SpaceToDepth.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+SpaceToDepthLayer::SpaceToDepthLayer() : _input(nullptr), _block_size(0), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+template <typename T> void SpaceToDepthLayer::spaceToDepth()
+{
+
+ nnfw::cker::SpaceToDepthParams params;
+ params.block_size = _block_size;
+
+ nnfw::cker::SpaceToDepth(params, getTensorShape(_input),
+ reinterpret_cast<const T *>(_input->buffer()), getTensorShape(_output),
+ reinterpret_cast<T *>(_output->buffer()));
+}
+
+void SpaceToDepthLayer::configure(const IPortableTensor *input, const int32_t block_size,
+ IPortableTensor *output)
+{
+ _input = input;
+ _block_size = block_size;
+ _output = output;
+}
+
+void SpaceToDepthLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ spaceToDepth<float>();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ spaceToDepth<uint8_t>();
+ }
+ else
+ {
+ throw std::runtime_error{"SpaceToDepth: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/SpaceToDepthLayer.h b/runtime/onert/backend/cpu/ops/SpaceToDepthLayer.h
new file mode 100644
index 000000000..c11ef2b0a
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SpaceToDepthLayer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SPACE_TO_DEPTH_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SPACE_TO_DEPTH_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+class SpaceToDepthLayer : public ::onert::exec::IFunction
+{
+public:
+ SpaceToDepthLayer();
+
+ void configure(const IPortableTensor *input, const int32_t block_size, IPortableTensor *output);
+
+ void run() override;
+
+private:
+ template <typename T> void spaceToDepth();
+
+ const IPortableTensor *_input;
+ int32_t _block_size;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SPACE_TO_BATCH_ND_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/SplitLayer.cc b/runtime/onert/backend/cpu/ops/SplitLayer.cc
new file mode 100644
index 000000000..922cde2e3
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SplitLayer.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SplitLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Split.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+SplitLayer::SplitLayer() : _input(nullptr), _axis(nullptr), _num_splits(0), _outputs()
+{
+ // DO NOTHING
+}
+
+template <typename T> void SplitLayer::split(void)
+{
+ nnfw::cker::SplitParams op_params;
+ if (_axis->total_size() != sizeof(int32_t))
+ {
+ throw std::runtime_error("ArgMinMax: wrong shape of axis");
+ }
+ auto axis = *reinterpret_cast<const int32_t *>(_axis->buffer());
+ if (axis < 0)
+ {
+ axis += _input->num_dimensions();
+ }
+ op_params.axis = axis;
+ op_params.num_split = _num_splits;
+
+ std::vector<T *> outputPtrs;
+
+ for (const auto output : _outputs)
+ {
+ assert(output->total_size() == sizeOfData(output->data_type(), output->getShape().dims()));
+ outputPtrs.emplace_back(reinterpret_cast<T *>(output->buffer()));
+ }
+
+ assert(_input->total_size() == sizeOfData(_input->data_type(), _input->getShape().dims()));
+ nnfw::cker::Split<T>(op_params, getTensorShape(_input), reinterpret_cast<T *>(_input->buffer()),
+ getTensorShape(_outputs[0]), outputPtrs.data());
+}
+
+void SplitLayer::configure(const IPortableTensor *input, const IPortableTensor *axis,
+ uint16_t num_splits, std::vector<IPortableTensor *> &outputs)
+{
+ assert(input != nullptr);
+
+ _num_splits = num_splits;
+ _input = input;
+ _axis = axis;
+ _outputs = outputs;
+}
+
+void SplitLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ split<float>();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ split<uint8_t>();
+ }
+ else if (_input->data_type() == OperandType::INT32)
+ {
+ split<int32_t>();
+ }
+ else if (_input->data_type() == OperandType::INT64)
+ {
+ split<int64_t>();
+ }
+ else
+ {
+ throw std::runtime_error{"Split: unsupported input type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/SplitLayer.h b/runtime/onert/backend/cpu/ops/SplitLayer.h
new file mode 100644
index 000000000..090f87166
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SplitLayer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SPLITLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SPLITLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class SplitLayer : public ::onert::exec::IFunction
+{
+public:
+ SplitLayer();
+
+public:
+ template <typename T> void split(void);
+
+ void configure(const IPortableTensor *input, const IPortableTensor *axis, uint16_t num_splits,
+ std::vector<IPortableTensor *> &outputs);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_axis;
+ uint16_t _num_splits;
+ std::vector<IPortableTensor *> _outputs;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SPLITLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/SplitVLayer.cc b/runtime/onert/backend/cpu/ops/SplitVLayer.cc
new file mode 100644
index 000000000..d6ca12442
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SplitVLayer.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SplitVLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/SplitV.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+SplitVLayer::SplitVLayer()
+ : _input(nullptr), _size_splits(nullptr), _split_dim(nullptr), _num_splits(0), _outputs()
+{
+ // DO NOTHING
+}
+
+template <typename T> void SplitVLayer::splitV(void)
+{
+ nnfw::cker::SplitVParams op_params;
+ op_params.axis = *(reinterpret_cast<const int32_t *>(_split_dim->buffer()));
+ op_params.num_split = _num_splits;
+
+ std::vector<T *> outputPtrs;
+ std::vector<nnfw::cker::Shape> outshape;
+
+ for (const auto output : _outputs)
+ {
+ assert(output->total_size() == sizeOfData(output->data_type(), output->getShape().dims()));
+ outputPtrs.emplace_back(reinterpret_cast<T *>(output->buffer()));
+ outshape.emplace_back(getTensorShape(output));
+ }
+
+ assert(_input->total_size() == sizeOfData(_input->data_type(), _input->getShape().dims()));
+ nnfw::cker::SplitV<T>(op_params, getTensorShape(_input), reinterpret_cast<T *>(_input->buffer()),
+ outshape, outputPtrs.data());
+}
+
+void SplitVLayer::configure(const IPortableTensor *input, const IPortableTensor *size_splits,
+ const IPortableTensor *split_dim, uint16_t num_splits,
+ std::vector<IPortableTensor *> &outputs)
+{
+ assert(input != nullptr);
+
+ _num_splits = num_splits;
+ _size_splits = size_splits;
+ _input = input;
+ _split_dim = split_dim;
+ _outputs = outputs;
+}
+
+void SplitVLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ splitV<float>();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ splitV<uint8_t>();
+ }
+ else if (_input->data_type() == OperandType::INT32)
+ {
+ splitV<int32_t>();
+ }
+ else if (_input->data_type() == OperandType::INT64)
+ {
+ splitV<int64_t>();
+ }
+ else
+ {
+ throw std::runtime_error{"SplitV: unsupported input type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/SplitVLayer.h b/runtime/onert/backend/cpu/ops/SplitVLayer.h
new file mode 100644
index 000000000..98f2f4406
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SplitVLayer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SPLIT_V_LAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SPLIT_V_LAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class SplitVLayer : public ::onert::exec::IFunction
+{
+public:
+ SplitVLayer();
+
+public:
+ template <typename T> void splitV(void);
+
+ void configure(const IPortableTensor *input, const IPortableTensor *size_splits,
+ const IPortableTensor *size_dim, uint16_t num_splits,
+ std::vector<IPortableTensor *> &outputs);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_size_splits;
+ const IPortableTensor *_split_dim;
+ uint16_t _num_splits;
+ std::vector<IPortableTensor *> _outputs;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SPLIT_V_LAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/SquaredDiffLayer.cc b/runtime/onert/backend/cpu/ops/SquaredDiffLayer.cc
new file mode 100644
index 000000000..cf67a5c00
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SquaredDiffLayer.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SquaredDiffLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/SqDiff.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+SqDiffLayer::SqDiffLayer() : _input1(nullptr), _input2(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void SqDiffLayer::SqDiffFloat32()
+{
+ nnfw::cker::SqDiff(getTensorShape(_input1), reinterpret_cast<const float *>(_input1->buffer()),
+ getTensorShape(_input2), reinterpret_cast<const float *>(_input2->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+}
+
+void SqDiffLayer::configure(const IPortableTensor *input1, const IPortableTensor *input2,
+ IPortableTensor *output)
+{
+ _input1 = input1;
+ _input2 = input2;
+ _output = output;
+}
+
+void SqDiffLayer::run()
+{
+ if (_input1->data_type() == OperandType::FLOAT32)
+ {
+ SqDiffFloat32();
+ }
+ else
+ {
+ throw std::runtime_error{"SquaredDiff: unsupported data type"};
+ }
+}
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/SquaredDiffLayer.h b/runtime/onert/backend/cpu/ops/SquaredDiffLayer.h
new file mode 100644
index 000000000..386eea9ae
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/SquaredDiffLayer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in riting, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_SQDIFFLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_SQDIFFLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class SqDiffLayer : public ::onert::exec::IFunction
+{
+public:
+ SqDiffLayer();
+
+public:
+ void SqDiffFloat32();
+
+ void configure(const IPortableTensor *input1, const IPortableTensor *input2,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input1;
+ const IPortableTensor *_input2;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_SQDIFFLAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/StatelessRandomUniformLayer.cc b/runtime/onert/backend/cpu/ops/StatelessRandomUniformLayer.cc
new file mode 100644
index 000000000..b8dfcb4b5
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/StatelessRandomUniformLayer.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "StatelessRandomUniformLayer.h"
+
+#include <cker/operation/StatelessRandomUniform.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+StatelessRandomUniformLayer::StatelessRandomUniformLayer()
+ : _shape(nullptr), _seed(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void StatelessRandomUniformLayer::configure(const IPortableTensor *shape,
+ const IPortableTensor *seed, IPortableTensor *output)
+{
+ _shape = shape;
+ _seed = seed;
+ _output = output;
+}
+
+void StatelessRandomUniformLayer::StatelessRandomUniformFloat32()
+{
+ nnfw::cker::StatelessRandomUniform(
+ getTensorShape(_shape), reinterpret_cast<const int *>(_shape->buffer()),
+ getTensorShape(_seed), reinterpret_cast<const int *>(_seed->buffer()),
+ getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
+}
+
+void StatelessRandomUniformLayer::run()
+{
+ switch (_output->data_type())
+ {
+ // ToDo : It need to support INT8 and UINT8 also when will be applied quantization.
+ case OperandType::FLOAT32:
+ StatelessRandomUniformFloat32();
+ break;
+ default:
+ throw std::runtime_error{"StatelessRandomUniformLayer: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/StatelessRandomUniformLayer.h b/runtime/onert/backend/cpu/ops/StatelessRandomUniformLayer.h
new file mode 100644
index 000000000..ef11d623d
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/StatelessRandomUniformLayer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_STATELESS_RANDOM_UNIFORM_H__
+#define __ONERT_BACKEND_CPU_OPS_STATELESS_RANDOM_UNIFORM_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class StatelessRandomUniformLayer : public ::onert::exec::IFunction
+{
+public:
+ StatelessRandomUniformLayer();
+
+public:
+ void configure(const IPortableTensor *shape, const IPortableTensor *seed,
+ IPortableTensor *output);
+
+ void StatelessRandomUniformFloat32();
+
+ void run() override;
+
+private:
+ const IPortableTensor *_shape;
+ const IPortableTensor *_seed;
+
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_STATELESS_RANDOM_UNIFORM_H__
diff --git a/runtime/onert/backend/cpu/ops/StridedSliceLayer.cc b/runtime/onert/backend/cpu/ops/StridedSliceLayer.cc
new file mode 100644
index 000000000..f77f4d691
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/StridedSliceLayer.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "StridedSliceLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/StridedSlice.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+StridedSliceLayer::StridedSliceLayer()
+ : _input(nullptr), _begin(nullptr), _end(nullptr), _strides(nullptr), _output(nullptr),
+ _begin_mask(0), _ellipsis_mask(0), _end_mask(0), _new_axis_mask(0), _shrink_axis_mask(0)
+{
+}
+
+template <typename T> void StridedSliceLayer::stridedSliceImpl()
+{
+ const auto input_shape = getTensorShape(_input);
+ const auto output_shape = getTensorShape(_output);
+ auto op_params = nnfw::cker::buildStridedSliceParams(
+ reinterpret_cast<uint32_t *>(_begin->buffer()), reinterpret_cast<uint32_t *>(_end->buffer()),
+ reinterpret_cast<uint32_t *>(_strides->buffer()), _begin_mask, _end_mask, _shrink_axis_mask,
+ input_shape.DimensionsCount());
+
+ nnfw::cker::checkOutputSize(op_params, input_shape, output_shape, input_shape.DimensionsCount());
+
+ nnfw::cker::StridedSlice(op_params, input_shape, reinterpret_cast<const T *>(_input->buffer()),
+ output_shape, reinterpret_cast<T *>(_output->buffer()));
+}
+
+void StridedSliceLayer::configure(const IPortableTensor *input, const IPortableTensor *begin,
+ const IPortableTensor *end, const IPortableTensor *strides,
+ IPortableTensor *output, const int32_t begin_mask,
+ const int32_t end_mask, const int32_t shrink_axis_mask)
+{
+ _input = input;
+ _begin = begin;
+ _end = end;
+ _strides = strides;
+ _output = output;
+
+ _begin_mask = begin_mask;
+ _ellipsis_mask = 0;
+ _end_mask = end_mask;
+ _new_axis_mask = 0;
+ _shrink_axis_mask = shrink_axis_mask;
+}
+
+void StridedSliceLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ stridedSliceImpl<float>();
+ }
+ else if (_input->data_type() == OperandType::INT32)
+ {
+ stridedSliceImpl<int32_t>();
+ }
+ else if (_input->data_type() == OperandType::INT64)
+ {
+ stridedSliceImpl<int64_t>();
+ }
+ else
+ {
+ throw std::runtime_error{"StridedSlice: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/StridedSliceLayer.h b/runtime/onert/backend/cpu/ops/StridedSliceLayer.h
new file mode 100644
index 000000000..468408152
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/StridedSliceLayer.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_STRIDEDSLICELAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_STRIDEDSLICELAYER_H__
+
+#include <backend/IPortableTensor.h>
+#include "OperationUtils.h"
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class StridedSliceLayer : public ::onert::exec::IFunction
+{
+public:
+ StridedSliceLayer();
+
+public:
+ void configure(const IPortableTensor *input, const IPortableTensor *begin,
+ const IPortableTensor *end, const IPortableTensor *strides,
+ IPortableTensor *output, const int32_t begin_mask, const int32_t end_mask,
+ const int32_t shrink_axis_mask);
+ void run() override;
+
+private:
+ template <typename T> void stridedSliceImpl();
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_begin;
+ const IPortableTensor *_end;
+ const IPortableTensor *_strides;
+ IPortableTensor *_output;
+
+ int32_t _begin_mask;
+ int32_t _ellipsis_mask;
+ int32_t _end_mask;
+ int32_t _new_axis_mask;
+ int32_t _shrink_axis_mask;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_STRIDEDSLICELAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/TileLayer.cc b/runtime/onert/backend/cpu/ops/TileLayer.cc
new file mode 100644
index 000000000..bfc371972
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/TileLayer.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TileLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Tile.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+TileLayer::TileLayer() : _input(nullptr), _multipliers(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+void TileLayer::tileFloat32()
+{
+ TileOneDimension(getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
+ reinterpret_cast<const int *>(_multipliers->buffer()),
+ reinterpret_cast<float *>(_output->buffer()), 0);
+}
+
+void TileLayer::tileQuant8()
+{
+ // cker quant8 tile is not implemented yet
+ throw std::runtime_error{"NYI"};
+}
+
+void TileLayer::configure(const IPortableTensor *input, const IPortableTensor *multipliers,
+ IPortableTensor *output)
+{
+ _input = input;
+ _multipliers = multipliers;
+ _output = output;
+}
+
+void TileLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ tileFloat32();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ tileQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"Tile: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/TileLayer.h b/runtime/onert/backend/cpu/ops/TileLayer.h
new file mode 100644
index 000000000..d7b793ecc
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/TileLayer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_TILELAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_TILELAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class TileLayer : public ::onert::exec::IFunction
+{
+public:
+ TileLayer();
+
+public:
+ void tileFloat32();
+
+ void tileQuant8();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *_multipliers,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_multipliers;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_TILELAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/TransposeLayer.cc b/runtime/onert/backend/cpu/ops/TransposeLayer.cc
new file mode 100644
index 000000000..3362c3396
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/TransposeLayer.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TransposeLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Transpose.h>
+#include <numeric>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+TransposeLayer::TransposeLayer() : _input(nullptr), _perm(nullptr), _output(nullptr)
+{
+ // DO NOTHING
+}
+
+template <typename T> void TransposeLayer::transpose()
+{
+ nnfw::cker::TransposeParams param;
+ assert(_perm->num_dimensions() == 1);
+
+ param.perm_count = _input->num_dimensions();
+ if (_perm->dimension(0) == 0) // This means _perm is (n-1...0)
+ {
+ const auto begin = param.perm;
+ const auto end = param.perm + _input->num_dimensions();
+ std::iota(begin, end, 0);
+ std::reverse(begin, end);
+ }
+ else
+ {
+ assert(param.perm_count == static_cast<int>(_perm->dimension(0)));
+ for (auto i = 0; i < param.perm_count; i++)
+ {
+ param.perm[i] = *(reinterpret_cast<const int32_t *>(_perm->buffer()) + i);
+ }
+ }
+
+ nnfw::cker::Transpose(param, getTensorShape(_input),
+ reinterpret_cast<const T *>(_input->buffer()), getTensorShape(_output),
+ reinterpret_cast<T *>(_output->buffer()));
+}
+
+void TransposeLayer::transposeQuant8()
+{
+ if (_input->data_offset() != _output->data_offset())
+ {
+ throw std::runtime_error("TransposeLayer : qassym8 input and output offsets unmatched");
+ }
+
+ if (_input->data_scale() != _output->data_scale())
+ {
+ throw std::runtime_error("TransposeLayer : qassym8 input and output scales unmatched");
+ }
+
+ transpose<uint8_t>();
+}
+
+void TransposeLayer::configure(const IPortableTensor *input, const IPortableTensor *perm,
+ IPortableTensor *output)
+{
+ _input = input;
+ _perm = perm;
+ _output = output;
+}
+
+void TransposeLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ {
+ transpose<float>();
+ }
+ else if (_input->data_type() == OperandType::INT32)
+ {
+ transpose<int32_t>();
+ }
+ else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
+ {
+ transposeQuant8();
+ }
+ else
+ {
+ throw std::runtime_error{"Transpose: unsupported data type"};
+ }
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/TransposeLayer.h b/runtime/onert/backend/cpu/ops/TransposeLayer.h
new file mode 100644
index 000000000..c8e9f8ae7
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/TransposeLayer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_TRANSPOSELAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_TRANSPOSELAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class TransposeLayer : public ::onert::exec::IFunction
+{
+public:
+ TransposeLayer();
+
+public:
+ template <typename T> void transpose();
+
+ void transposeQuant8();
+
+ void configure(const IPortableTensor *input, const IPortableTensor *perm,
+ IPortableTensor *output);
+
+ void run() override;
+
+private:
+ const IPortableTensor *_input;
+ const IPortableTensor *_perm;
+ IPortableTensor *_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_TRANSPOSELAYER_H__
diff --git a/runtime/onert/backend/cpu/ops/UnpackLayer.cc b/runtime/onert/backend/cpu/ops/UnpackLayer.cc
new file mode 100644
index 000000000..428b38588
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/UnpackLayer.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UnpackLayer.h"
+
+#include "OperationUtils.h"
+
+#include <cker/operation/Unpack.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+UnpackLayer::UnpackLayer() : _input(nullptr), _outputs(), _axis(0), _num_output(0)
+{
+ // DO NOTHING
+}
+
+template <typename T> void UnpackLayer::unpackImpl()
+{
+ nnfw::cker::UnpackParams op_params;
+ op_params.axis = _axis;
+ op_params.num_split = _num_output;
+
+ std::vector<nnfw::cker::Shape *> outputDimsPtr;
+ std::vector<nnfw::cker::Shape> outputDims;
+ outputDimsPtr.reserve(_num_output);
+ outputDims.reserve(_num_output);
+
+ for (int32_t i = 0; i < _num_output; i++)
+ {
+ outputDims.push_back(getTensorShape(_outputs[i]));
+ outputDimsPtr.push_back(&outputDims[i]);
+ }
+
+ std::vector<T *> outputPtrs;
+
+ for (const auto output : _outputs)
+ {
+ outputPtrs.emplace_back(reinterpret_cast<T *>(output->buffer()));
+ }
+
+ nnfw::cker::Unpack<T>(op_params, getTensorShape(_input), reinterpret_cast<T *>(_input->buffer()),
+ getTensorShape(_outputs[0]), outputPtrs.data());
+}
+
+void UnpackLayer::configure(const IPortableTensor *input, uint32_t axis, int32_t num,
+ std::vector<IPortableTensor *> &outputs)
+{
+ assert(input != nullptr);
+ assert(outputs.size() > 0);
+ assert(outputs.size() == (size_t)num);
+
+ _input = input;
+ _axis = axis;
+ _num_output = num;
+ _outputs = outputs;
+}
+
+void UnpackLayer::run()
+{
+ if (_input->data_type() == OperandType::FLOAT32)
+ unpackImpl<float>();
+ else if (_input->data_type() == OperandType::INT32)
+ unpackImpl<int32_t>();
+ else
+ throw std::runtime_error{"Unpack: Unsupported data type"};
+}
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/backend/cpu/ops/UnpackLayer.h b/runtime/onert/backend/cpu/ops/UnpackLayer.h
new file mode 100644
index 000000000..a185b31a0
--- /dev/null
+++ b/runtime/onert/backend/cpu/ops/UnpackLayer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_OPS_UNPACKLAYER_H__
+#define __ONERT_BACKEND_CPU_OPS_UNPACKLAYER_H__
+
+#include <backend/IPortableTensor.h>
+
+#include <exec/IFunction.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu
+{
+namespace ops
+{
+
+class UnpackLayer : public ::onert::exec::IFunction
+{
+public:
+ UnpackLayer();
+
+public:
+ void configure(const IPortableTensor *input, uint32_t axis, int32_t num_output,
+ std::vector<IPortableTensor *> &output);
+ void run() override;
+
+private:
+ template <typename T> void unpackImpl();
+
+private:
+ const IPortableTensor *_input;
+ std::vector<IPortableTensor *> _outputs;
+ uint32_t _axis;
+ int32_t _num_output;
+};
+
+} // namespace ops
+} // namespace cpu
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_OPS_UNPACKLAYER_H__
diff --git a/runtime/onert/core/CMakeLists.txt b/runtime/onert/core/CMakeLists.txt
new file mode 100644
index 000000000..ea212a42b
--- /dev/null
+++ b/runtime/onert/core/CMakeLists.txt
@@ -0,0 +1,54 @@
+file(GLOB_RECURSE SOURCES "src/*.cc")
+file(GLOB_RECURSE TESTS "*.test.cc")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+nnfw_find_package(Ruy REQUIRED)
+
+add_library(onert_core SHARED ${SOURCES})
+set_target_properties(onert_core PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(onert_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_include_directories(onert_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
+target_link_libraries(onert_core PUBLIC nnfw_lib_misc half)
+target_link_libraries(onert_core PRIVATE nnfw_lib_cker)
+target_link_libraries(onert_core PRIVATE nnfw_common)
+target_link_libraries(onert_core PRIVATE nnfw_coverage)
+target_link_libraries(onert_core PRIVATE dl ${LIB_PTHREAD})
+target_link_libraries(onert_core PRIVATE jsoncpp)
+target_link_libraries(onert_core PRIVATE ruy)
+target_link_libraries(onert_core INTERFACE ruy_instrumentation)
+
+if(CMAKE_BUILD_TYPE_LC STREQUAL "release")
+ add_custom_command(TARGET onert_core POST_BUILD
+ COMMAND ${CMAKE_STRIP} "--strip-unneeded" $<TARGET_FILE_NAME:onert_core>)
+endif()
+
+# NOTE Below line is added to remove warning for android build
+# It will be removed after android build uses gold linker
+if (ANDROID)
+ target_link_libraries(onert_core INTERFACE log)
+endif (ANDROID)
+
+if(ENVVAR_ONERT_CONFIG)
+ target_compile_definitions(onert_core PRIVATE ENVVAR_FOR_DEFAULT_CONFIG)
+endif(ENVVAR_ONERT_CONFIG)
+
+install(TARGETS onert_core LIBRARY DESTINATION lib)
+install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+ DESTINATION "include/onert"
+ FILES_MATCHING PATTERN "*.h" PATTERN "*.lst"
+ )
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+# Unit Tests
+set(TEST_ONERT_BACKEND_CPU_COMMON test_onert_backend_cpu_common)
+
+add_executable(${TEST_ONERT_BACKEND_CPU_COMMON} ${TESTS})
+
+target_link_libraries(${TEST_ONERT_BACKEND_CPU_COMMON} onert_core)
+target_link_libraries(${TEST_ONERT_BACKEND_CPU_COMMON} gtest gtest_main dl ${LIB_PTHREAD})
+
+add_test(${TEST_ONERT_BACKEND_CPU_COMMON} ${TEST_ONERT_BACKEND_CPU_COMMON})
+install(TARGETS ${TEST_ONERT_BACKEND_CPU_COMMON} DESTINATION unittest_standalone)
diff --git a/runtime/onert/core/include/backend/Backend.h b/runtime/onert/core/include/backend/Backend.h
new file mode 100644
index 000000000..4f6ebbba7
--- /dev/null
+++ b/runtime/onert/core/include/backend/Backend.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_BACKEND_H__
+#define __ONERT_BACKEND_BACKEND_H__
+
+#include <memory>
+
+#include "ir/Graph.h"
+#include "backend/IConfig.h"
+#include "backend/BackendContext.h"
+
+namespace onert
+{
+namespace backend
+{
+
+namespace custom
+{
+class IKernelBuilder;
+}
+
+class Backend
+{
+public:
+ virtual ~Backend() = default;
+ virtual std::shared_ptr<onert::backend::IConfig> config() const = 0;
+
+ virtual std::unique_ptr<BackendContext>
+ newContext(const ir::Graph &graph, const std::shared_ptr<backend::custom::IKernelBuilder> &kb,
+ bool is_linear_executor) const = 0;
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_BACKEND_H__
diff --git a/runtime/onert/core/include/backend/BackendContext.h b/runtime/onert/core/include/backend/BackendContext.h
new file mode 100644
index 000000000..1eba29550
--- /dev/null
+++ b/runtime/onert/core/include/backend/BackendContext.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_BACKEND_CONTEXT_H__
+#define __ONERT_BACKEND_BACKEND_CONTEXT_H__
+
+#include <memory>
+#include "ir/Graph.h"
+
+namespace onert
+{
+namespace backend
+{
+
+class Backend;
+class IConstantInitializer;
+class IKernelGenerator;
+class ITensorRegister;
+struct ITensorRegistry;
+struct ITensorBuilder;
+struct IOptimizer;
+
+class BackendContext
+{
+public:
+ struct OperationInfo
+ {
+ ir::OperationIndex index;
+ ir::Layout layout;
+
+ OperationInfo(ir::OperationIndex index, ir::Layout layout) : index{index}, layout{layout} {}
+ };
+
+public:
+ BackendContext(const Backend *backend, const ir::Graph *graph,
+ std::shared_ptr<ITensorRegistry> tensor_registry = nullptr,
+ std::shared_ptr<ITensorBuilder> tensor_builder = nullptr,
+ std::shared_ptr<IConstantInitializer> constant_initializer = nullptr,
+ std::shared_ptr<IKernelGenerator> kernel_gen = nullptr,
+ std::shared_ptr<ITensorRegister> tensor_register = nullptr,
+ std::shared_ptr<IOptimizer> optimizer = nullptr)
+ : _backend{backend}, _graph{graph}, tensor_registry{tensor_registry},
+ tensor_builder{tensor_builder}, constant_initializer{constant_initializer},
+ kernel_gen{kernel_gen}, tensor_register{tensor_register}, optimizer{optimizer}
+ {
+ }
+
+ virtual ~BackendContext() = default;
+
+ void initialize(const std::vector<OperationInfo> &operation_list,
+ const std::vector<ir::OperandIndex> &operand_list);
+ void initConsts();
+
+ const Backend *backend() const { return _backend; }
+ const ir::Graph *graph() const { return _graph; }
+ const std::vector<OperationInfo> &operation_list() { return _operation_list; }
+ const std::vector<ir::OperandIndex> &operand_list() { return _operand_list; }
+
+private:
+ const Backend *_backend{nullptr};
+ const ir::Graph *_graph{nullptr};
+ std::vector<OperationInfo> _operation_list;
+ std::vector<ir::OperandIndex> _operand_list;
+
+public:
+ std::shared_ptr<ITensorRegistry> tensor_registry;
+ std::shared_ptr<ITensorBuilder> tensor_builder;
+ std::shared_ptr<IConstantInitializer> constant_initializer;
+ std::shared_ptr<IKernelGenerator> kernel_gen;
+ std::shared_ptr<ITensorRegister> tensor_register;
+ std::shared_ptr<IOptimizer> optimizer;
+};
+
+using BackendContexts = std::unordered_map<const Backend *, std::unique_ptr<BackendContext>>;
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_BACKEND_CONTEXT_H__
diff --git a/runtime/onert/core/include/backend/CustomKernelBuilder.h b/runtime/onert/core/include/backend/CustomKernelBuilder.h
new file mode 100644
index 000000000..cae2fc1a3
--- /dev/null
+++ b/runtime/onert/core/include/backend/CustomKernelBuilder.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CUSTOM_KERNEL_BUILDER_H__
+#define __ONERT_BACKEND_CUSTOM_KERNEL_BUILDER_H__
+
+#include "backend/IPortableTensor.h"
+#include "ir/Shape.h"
+#include "ir/DataType.h"
+
+#include <vector>
+#include <memory>
+
+namespace onert
+{
+namespace exec
+{
+
+class IFunction;
+
+} // namespace exec
+} // namespace onert
+
+namespace onert
+{
+namespace backend
+{
+namespace custom
+{
+
+struct TypeInfo
+{
+ ir::Shape shape;
+ ir::DataType dtype;
+};
+
+struct CustomKernelConfigParams
+{
+ std::vector<backend::IPortableTensor *> input_tensors;
+ std::vector<TypeInfo> input_types;
+
+ std::vector<backend::IPortableTensor *> output_tensors;
+ std::vector<TypeInfo> output_types;
+
+ char *userdata;
+ size_t userdata_size;
+};
+
+class IKernelBuilder
+{
+public:
+ virtual ~IKernelBuilder() = default;
+ virtual std::unique_ptr<exec::IFunction> buildKernel(const std::string &id,
+ CustomKernelConfigParams &&params) const = 0;
+};
+
+} // namespace custom
+
+} // namespace backend
+
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CUSTOM_KERNEL_BUILDER_H__
diff --git a/runtime/onert/core/include/backend/IConfig.h b/runtime/onert/core/include/backend/IConfig.h
new file mode 100644
index 000000000..ef9c5cdb2
--- /dev/null
+++ b/runtime/onert/core/include/backend/IConfig.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ICONFIG_H__
+#define __ONERT_BACKEND_ICONFIG_H__
+
+#include "ir/Layout.h"
+#include "ir/Operation.h"
+#include "util/ITimer.h"
+
+#include <memory>
+#include <string>
+
+namespace onert
+{
+namespace backend
+{
+
+struct IConfig
+{
+ virtual ~IConfig() = default;
+ /**
+ * @brief Returns ID of the backend
+ *
+ * @return std::string ID of this backend
+ */
+ virtual std::string id() = 0;
+ /**
+ * @brief Initialize the backend. This is called as soon as the backend is loaded.
+ *
+ * @return true Initialization succeeded
+ * @return false Initialization failed, so it cannot use this backend
+ */
+ virtual bool initialize() = 0;
+ /**
+ * @brief Returns supported layout for the given \p node and \p frontend_layout
+ *
+ * @param node Operation
+ * @param frontend_layout The layout defined in the model
+ * @return ir::Layout The layout that the backend kernel actually uses
+ */
+ virtual ir::Layout supportLayout(const ir::Operation &node, ir::Layout frontend_layout) = 0;
+ /**
+ * @brief The function that is called after each OpSequence run on profiling mode.
+ * This may be useful for profiling GPU-based or special computing units.
+ */
+ virtual void sync() const {}
+ /**
+ * @brief Returns Timer object for this backend. For some computing units, it may need its own
+ * Timer implementation.
+ *
+ * @return std::unique_ptr<util::ITimer> Timer object for this backend
+ */
+ virtual std::unique_ptr<util::ITimer> timer() { return nullptr; }
+
+ virtual bool supportPermutation() = 0;
+ virtual bool supportDynamicTensor() = 0;
+ virtual bool supportFP16() = 0;
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ICONFIG_H__
diff --git a/runtime/onert/core/include/backend/IConstantInitializer.h b/runtime/onert/core/include/backend/IConstantInitializer.h
new file mode 100644
index 000000000..149acecb4
--- /dev/null
+++ b/runtime/onert/core/include/backend/IConstantInitializer.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ICONSTANT_INITIALIZER_H__
+#define __ONERT_BACKEND_ICONSTANT_INITIALIZER_H__
+
+#include <unordered_map>
+#include <functional>
+
+#include "ITensorBuilder.h"
+#include "ir/Coordinates.h"
+#include "ir/Layout.h"
+#include "ir/Operand.h"
+#include "ir/Operands.h"
+#include "ir/OperationVisitor.h"
+#include "ir/OpSequence.h"
+#include "util/logging.h"
+
+namespace
+{
+template <typename T>
+static void Init(const onert::ir::Operand &model_obj, onert::backend::ITensor &obj, const bool copy,
+ const onert::ir::Layout frontend_layout = onert::ir::Layout::UNKNOWN)
+{
+ const auto shape = model_obj.shape();
+ assert(model_obj.data());
+ auto base = reinterpret_cast<const T *>(model_obj.data()->base());
+
+ obj.access([&](::onert::backend::ITensor &tensor) {
+ switch (shape.rank())
+ {
+ case 0:
+ {
+ assert(model_obj.data()->size() == sizeof(T));
+ const auto value = *reinterpret_cast<const T *>(base);
+ T *into = reinterpret_cast<T *>(tensor.buffer());
+ *into = value;
+ break;
+ }
+ case 1:
+ {
+ auto vec_size = shape.dim(0);
+ for (int32_t n = 0; n < vec_size; ++n)
+ {
+ const T *from = reinterpret_cast<const T *>(base) + n;
+ const auto value = *from;
+
+ T *into = reinterpret_cast<T *>(tensor.buffer()) + n;
+
+ *into = value;
+ }
+ break;
+ }
+ case 2:
+ {
+ const int32_t copy_len = shape.dim(1);
+
+ for (auto i = 0; i < shape.dim(0); ++i)
+ {
+ ::onert::ir::Coordinates coords{i, 0};
+ memcpy(tensor.buffer() + tensor.calcOffset(coords), base + i * copy_len,
+ copy_len * sizeof(T));
+ }
+ break;
+ }
+ case 3:
+ {
+ const int32_t width = shape.dim(1);
+ const int32_t copy_len = shape.dim(2);
+
+ for (auto i = 0; i < shape.dim(0); ++i)
+ {
+ for (auto j = 0; j < shape.dim(1); ++j)
+ {
+ ::onert::ir::Coordinates coords{i, j, 0};
+ memcpy(tensor.buffer() + tensor.calcOffset(coords),
+ base + i * width * copy_len + j * copy_len, copy_len * sizeof(T));
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ const int32_t height = shape.dim(1);
+ const int32_t width = shape.dim(2);
+ const int32_t copy_len = shape.dim(3);
+ for (auto i = 0; i < shape.dim(0); ++i)
+ {
+ for (auto j = 0; j < shape.dim(1); ++j)
+ {
+ for (auto k = 0; k < shape.dim(2); ++k)
+ {
+ if (copy)
+ {
+ ::onert::ir::Coordinates coords{i, j, k, 0};
+ memcpy(tensor.buffer() + tensor.calcOffset(coords),
+ base + i * height * width * copy_len + j * width * copy_len + k * copy_len,
+ copy_len * sizeof(T));
+ }
+ else
+ {
+ for (auto l = 0; l < shape.dim(3); ++l)
+ {
+ const auto coords = ::onert::ir::convertCoordinates({i, j, k, l}, frontend_layout,
+ tensor.layout());
+ T *into = reinterpret_cast<T *>(tensor.buffer() + tensor.calcOffset(coords));
+ T value = *(base + i * height * width * copy_len + j * width * copy_len +
+ k * copy_len + l);
+ *into = value;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ throw std::runtime_error{"Not yet supported"};
+ }
+ });
+}
+
+template <typename T>
+void copyInit(const onert::ir::Operand &model_obj, onert::backend::ITensor &obj)
+{
+ Init<T>(model_obj, obj, true);
+}
+
+template <typename T>
+void permuteInit(const onert::ir::Operand &model_obj, onert::backend::ITensor &obj,
+ const onert::ir::Layout frontend_layout)
+{
+ const bool copy = frontend_layout == obj.layout();
+ Init<T>(model_obj, obj, copy, frontend_layout);
+}
+
+} // namespace
+
+namespace onert
+{
+namespace backend
+{
+
+class IConstantInitializer : public ir::OperationVisitor
+{
+public:
+ virtual ~IConstantInitializer() = default;
+
+public:
+ void run()
+ {
+ assert(tensor_registry());
+ for (const auto &it : _init_map)
+ {
+ const auto &ind = it.first;
+ const auto &fn = it.second;
+
+ const auto &model_obj = _operands.at(ind);
+ auto tensor_obj = tensor_registry()->getNativeITensor(ind);
+ assert(tensor_obj != nullptr);
+ fn(model_obj, *tensor_obj);
+ VERBOSE(FillOperandData) << "Fill data for operand " << ind.value() << std::endl;
+ }
+ _init_map.clear();
+ }
+
+public:
+ IConstantInitializer(const ir::Operands &operands)
+ : _operands{operands}, _current_op_seq_layout{ir::Layout::UNKNOWN}
+ {
+ }
+
+public:
+ using Initializer = std::function<void(const ir::Operand &, backend::ITensor &)>;
+
+ void setLayout(ir::Layout layout) { _current_op_seq_layout = layout; }
+
+protected:
+ virtual std::shared_ptr<ITensorRegistry> tensor_registry() const = 0;
+
+public:
+ virtual void registerDefaultInitializer(const ir::OperandIndex &index, const ir::Operand &obj)
+ {
+ registerPermuteInitializer(index, obj); // as default
+ }
+
+public:
+ void registerCopyInitializer(const ir::OperandIndex &index, const ir::Operand &obj);
+ void registerPermuteInitializer(const ir::OperandIndex &index, const ir::Operand &obj);
+
+public:
+ void registerCustomInitializer(const ir::OperandIndex &index, const ir::Operand &obj,
+ void (*customInit)(const onert::ir::Operand &model_obj,
+ onert::backend::ITensor &obj))
+ {
+ // For only CONSTANTS
+ // TODO Add to check if tensor has been allocated
+ if (!obj.isConstant())
+ return;
+
+ using namespace std::placeholders;
+ _init_map[index] = std::bind(customInit, _1, _2);
+ }
+
+public:
+ bool exist(const ir::OperandIndex &ind) { return _init_map.find(ind) != _init_map.end(); }
+
+protected:
+ const ir::Operands &_operands;
+ std::unordered_map<ir::OperandIndex, Initializer> _init_map;
+ ir::Layout _current_op_seq_layout; // TODO Rename this to _current_layout
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ICONSTANT_INITIALIZER_H__
diff --git a/runtime/onert/core/include/backend/IDynamicTensorManager.h b/runtime/onert/core/include/backend/IDynamicTensorManager.h
new file mode 100644
index 000000000..67cfda24e
--- /dev/null
+++ b/runtime/onert/core/include/backend/IDynamicTensorManager.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_IDYNAMICTENSOR_MANAGER_H__
+#define __ONERT_BACKEND_IDYNAMICTENSOR_MANAGER_H__
+
+#include "ITensorManager.h"
+
+#include <ir/Index.h>
+#include <ir/Operation.h>
+#include <ir/Shape.h>
+#include <backend/ITensor.h>
+
+namespace onert
+{
+namespace backend
+{
+
+/**
+ * @brief Interface as an abstract tensor manager, providing ways to handle memory
+ * for dynamic tensors.
+ */
+struct IDynamicTensorManager : public ITensorManager
+{
+ virtual ~IDynamicTensorManager() = default;
+
+public:
+ /**
+ * @brief Plan when to delete a tensor. Note this planning is done at compilation time.
+ * @param op_ind operation index
+ * @param tensor candidate ITensor to dealloc. Tensor can be static
+ * or dynamic since tensor type may not be clearly known at compilation time.
+ */
+ virtual void planDealloc(ir::OperationIndex op_ind, backend::ITensor *tensor) = 0;
+
+ /**
+ * @brief Deallocate input tensors of op if an input tensor is a dynamic tensor and it won't
+ * be used anymore
+ * @note This will work after calling planDealloc
+ */
+ virtual void deallocInput(ir::OperationIndex op_ind) = 0;
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_IDYNAMICTENSOR_MANAGER_H__
diff --git a/runtime/onert/core/include/backend/IExternalContext.h b/runtime/onert/core/include/backend/IExternalContext.h
new file mode 100644
index 000000000..88ffb502c
--- /dev/null
+++ b/runtime/onert/core/include/backend/IExternalContext.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_IEXTERNAL_CONTEXT_H__
+#define __ONERT_BACKEND_IEXTERNAL_CONTEXT_H__
+
+namespace onert
+{
+namespace backend
+{
+
+struct IExternalContext
+{
+ virtual ~IExternalContext() = default;
+ virtual void setMaxNumThreads(int) = 0;
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_IEXTERNAL_CONTEXT__
diff --git a/runtime/onert/core/include/backend/IKernelGenerator.h b/runtime/onert/core/include/backend/IKernelGenerator.h
new file mode 100644
index 000000000..afc34ec21
--- /dev/null
+++ b/runtime/onert/core/include/backend/IKernelGenerator.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_IKERNEL_GENERATOR_H__
+#define __ONERT_BACKEND_IKERNEL_GENERATOR_H__
+
+#include <assert.h>
+#include <memory>
+#include <functional>
+
+#include "ITensorBuilder.h"
+#include "ir/OperationVisitor.h"
+#include "ir/OpSequence.h"
+#include <memory>
+#include "exec/FunctionSequence.h"
+
+namespace onert
+{
+namespace backend
+{
+
+class IKernelGenerator : public ir::OperationVisitor
+{
+public:
+ virtual ~IKernelGenerator() = default;
+
+ std::unique_ptr<exec::IFunction> releaseFunction()
+ {
+ assert(_return_fn);
+ return std::move(_return_fn);
+ }
+
+ std::unique_ptr<exec::FunctionSequence> generate(const ir::OpSequence &op_seq)
+ {
+ op_seq.accept(*this);
+ return std::move(_return_fn_seq);
+ }
+
+protected:
+ using OperationVisitor::visit;
+
+ void visit(const ir::OpSequence &) override
+ {
+ throw std::runtime_error("KernelGenerator: NYI for operation 'OpSequence'");
+ }
+
+#define OP(InternalName) \
+ void visit(const ir::operation::InternalName &) override \
+ { \
+ throw std::runtime_error("KernelGenerator: NYI for operation '" #InternalName "'"); \
+ }
+#include "ir/Operations.lst"
+#undef OP
+
+protected:
+ std::unique_ptr<exec::IFunction> _return_fn;
+ std::unique_ptr<exec::FunctionSequence> _return_fn_seq; // TODO Extract this out
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_IKERNEL_GENERATOR_H__
diff --git a/runtime/onert/core/include/backend/IMemoryManager.h b/runtime/onert/core/include/backend/IMemoryManager.h
new file mode 100644
index 000000000..bad2fd51a
--- /dev/null
+++ b/runtime/onert/core/include/backend/IMemoryManager.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_IMEMORY_MANAGER_H__
+#define __ONERT_BACKEND_IMEMORY_MANAGER_H__
+
+namespace onert
+{
+namespace backend
+{
+
+struct IMemoryManager
+{
+ virtual ~IMemoryManager() = default;
+
+ virtual void allocate(void) = 0;
+ virtual void deallocate(void) = 0;
+};
+
+} // namespace backend
+} // namespace onert
+
+#include <unordered_set>
+#include <memory>
+
+namespace onert
+{
+namespace backend
+{
+
+using MemoryManagerSet = std::unordered_set<std::unique_ptr<backend::IMemoryManager>>;
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_IMEMORY_MANAGER_H__
diff --git a/runtime/onert/core/include/backend/IOptimizer.h b/runtime/onert/core/include/backend/IOptimizer.h
new file mode 100644
index 000000000..4844d21b9
--- /dev/null
+++ b/runtime/onert/core/include/backend/IOptimizer.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_I_OPTIMIZER_H__
+#define __ONERT_BACKEND_I_OPTIMIZER_H__
+
+namespace onert
+{
+namespace ir
+{
+class LoweredGraph;
+}
+} // namespace onert
+
+namespace onert
+{
+namespace backend
+{
+
+/**
+ * @brief Class for backend optimizations. This is an optional class so not all backends must have
+ * it.
+ *
+ */
+struct IOptimizer
+{
+ virtual ~IOptimizer() = default;
+ /**
+ * @brief Run optimization
+ *
+ */
+ virtual void optimize() = 0;
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_I_OPTIMIZER_H__
diff --git a/runtime/onert/core/include/backend/IPortableTensor.h b/runtime/onert/core/include/backend/IPortableTensor.h
new file mode 100644
index 000000000..1b1f05fe1
--- /dev/null
+++ b/runtime/onert/core/include/backend/IPortableTensor.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_I_PORTABLE_TENSOR_H__
+#define __ONERT_BACKEND_I_PORTABLE_TENSOR_H__
+
+#include "backend/ITensor.h"
+#include "ir/OperandInfo.h"
+#include "ir/Sparsity.h"
+
+namespace onert
+{
+namespace backend
+{
+
+/**
+ * @brief A tensor class that is portable for other backends
+ *
+ * Backends that use derivatives of this interface can reuse each other's tensors without copying.
+ * Here's criterion to be a portable tensor:
+ * - it must not have any paddings
+ * - No special operations on @c access method
+ * - e.g. CL memory must map/unmap to use it from CPU, the memory so it cannot be portable
+ */
+class IPortableTensor : public ITensor
+{
+public:
+ IPortableTensor(const ir::OperandInfo &info) : _info(info) {}
+
+ virtual ~IPortableTensor();
+ virtual const ir::Sparsity *sparsity() const { return nullptr; }
+ const ir::OperandInfo &get_info() const { return _info; }
+
+public:
+ bool has_padding() const final { return false; }
+ void access(const std::function<void(ITensor &tensor)> &fn) final { fn(*this); }
+
+protected:
+ ir::OperandInfo _info;
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_I_PORTABLE_TENSOR_H__
diff --git a/runtime/onert/core/include/backend/IStaticTensorManager.h b/runtime/onert/core/include/backend/IStaticTensorManager.h
new file mode 100644
index 000000000..cef1f8a0a
--- /dev/null
+++ b/runtime/onert/core/include/backend/IStaticTensorManager.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ISTATICTENSOR_MANAGER_H__
+#define __ONERT_BACKEND_ISTATICTENSOR_MANAGER_H__
+
+#include "ITensorManager.h"
+
+namespace onert
+{
+namespace backend
+{
+
+struct IStaticTensorManager : public ITensorManager
+{
+ virtual ~IStaticTensorManager() = default;
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ISTATICTENSOR_MANAGER_H__
diff --git a/runtime/onert/core/include/backend/ITensor.h b/runtime/onert/core/include/backend/ITensor.h
new file mode 100644
index 000000000..3fadda1f5
--- /dev/null
+++ b/runtime/onert/core/include/backend/ITensor.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_OPERAND_I_TENSOR_H__
+#define __ONERT_BACKEND_OPERAND_I_TENSOR_H__
+
+#include <cstring>
+#include <cstdint>
+#include <functional>
+
+#include "ir/DataType.h"
+#include "ir/Layout.h"
+#include "ir/Shape.h"
+#include "ir/Coordinates.h"
+#include "util/Utils.h"
+
+namespace onert
+{
+namespace backend
+{
+
+struct IDynamicTensorManager;
+
+class ITensor
+{
+public:
+ virtual ~ITensor() = default;
+
+public:
+ virtual uint8_t *buffer() const = 0;
+ virtual size_t total_size() const = 0;
+ virtual size_t dimension(size_t index) const = 0;
+ virtual size_t num_dimensions() const = 0;
+ virtual size_t calcOffset(const ir::Coordinates &coords) const = 0;
+ virtual ir::Layout layout() const = 0;
+ virtual ir::DataType data_type() const = 0;
+ virtual float data_scale() const = 0;
+ virtual int32_t data_offset() const = 0;
+ virtual bool has_padding() const = 0;
+ virtual void access(const std::function<void(ITensor &tensor)> &fn) = 0;
+
+ /**
+ * @brief Set the shape to @c shape and possibly re-allocate the buffer
+ *
+ * If a tensor is dynamic tensor and previously allocated memory exists,
+ * it will be deallocated.
+ * If a tensor is static tensor (with previously allocated memory by StaticTensorManager),
+ * @c buffer() will be overwriten
+ *
+ * @param shape tensor's new shape. While allocating memory for this new_shape,
+ * tensor's shape is set to new_shape
+ * @return true If applying shape is successful
+ * @return false If not applying shape is not supported (it throws for other errors)
+ */
+ virtual bool applyShape(const ir::Shape &) { return false; }
+
+ /**
+ * @brief Return true if the tensor is constant
+ */
+ virtual bool is_constant() const
+ {
+ throw std::runtime_error("This backend does not support checking constant");
+ }
+
+ /**
+ * @brief Return true if the tensor needs dynamic allocation, meaning that during compile-time
+ * the outpus shape cannot be known and the output shape is calculated during
+ * kernel execution-time.
+ */
+ virtual bool is_dynamic() const = 0;
+
+ /// @brief set this tensor dynamic
+ virtual void set_dynamic()
+ {
+ throw std::runtime_error("This backend does not support dynamic tensor");
+ }
+
+ /**
+ * @brief Set the shape of tenser to new_shape
+ * @note Higer dimension will be placed on front.
+ */
+ virtual void setShape(const ir::Shape &new_shape)
+ {
+ UNUSED_RELEASE(new_shape);
+ throw std::runtime_error("This backend does not support dynamic setShape");
+ }
+
+ /**
+ * @brief Get ir::Shape of tensor
+ * @note Higer dimension will be placed on front.
+ */
+ virtual ir::Shape getShape() const;
+
+ virtual bool is_subtensor() const { return false; }
+ virtual bool needMemoryMap() const { return false; }
+ virtual void enqueueWriteBuffer(const void *, bool)
+ {
+ throw std::runtime_error("This backend does not support enqueueWriteBuffer");
+ }
+ virtual void enqueueReadBuffer(void *, bool)
+ {
+ throw std::runtime_error("This backend does not support enqueueReadBuffer");
+ }
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_OPERAND_I_TENSOR_H__
diff --git a/runtime/onert/core/include/backend/ITensorBuilder.h b/runtime/onert/core/include/backend/ITensorBuilder.h
new file mode 100644
index 000000000..97721cf19
--- /dev/null
+++ b/runtime/onert/core/include/backend/ITensorBuilder.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ITENSOR_BUILDER_H__
+#define __ONERT_BACKEND_ITENSOR_BUILDER_H__
+
+#include <map>
+
+#include "ir/Index.h"
+#include "ir/OperandInfo.h"
+#include "ir/Operation.h"
+#include "ir/Layout.h"
+#include "ITensor.h"
+#include "ITensorManager.h"
+#include "ITensorRegistry.h"
+#include "IDynamicTensorManager.h"
+
+namespace onert
+{
+namespace backend
+{
+
+struct ITensorBuilder
+{
+ using IterateFunction = std::function<void(const ir::OperandIndex &)>;
+
+ virtual ~ITensorBuilder(void) = default;
+
+ /**
+ * @brief Register tensor information to allocate on backend
+ *
+ * @param ind Index
+ * @param info Info
+ * @param backend_layout Backend layout
+ * @param as_const Whether this tensor is constant
+ */
+ virtual void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
+ ir::Layout backend_layout) = 0;
+
+ /**
+ * @brief Check if the tensor has been registered with @c registerTensorInfo
+ *
+ * @return true If the tensor has been registered
+ * @return false Otherwise
+ */
+ virtual bool isRegistered(const ir::OperandIndex &) const = 0;
+
+public: // methods for static tensor allocation
+ /**
+ * @brief Let the tensor builder know first use(start of lifetime) of a tensor
+ * Must be called before calling @c prepare
+ * Must be run up to once for each tensor before calling @c notifyLastUse
+ * NOTE: Useful only for static models
+ */
+ virtual void notifyFirstUse(const ir::OperandIndex &) = 0;
+ /**
+ * @brief Let the tensor builder know last use(end of lifetime) of a tensor
+ * Must be run up to once for each tensor after calling @c notifyFirstUse
+ * NOTE: Useful only for static models
+ */
+ virtual void notifyLastUse(const ir::OperandIndex &) = 0;
+ /**
+ * @brief Prepare the tensors
+ * Before calling this, all the tensors must be registered
+ */
+ virtual void prepare(void) = 0;
+ /**
+ * @brief Allocate the tensors
+ * Before calling this, @c prepare must be called
+ */
+ virtual void allocate() = 0;
+ /**
+ * @brief Some actions after functions' @c IFunction::prepare method.
+ * This is called right after each function's @c IFunction::prepare function has been
+ * called.
+ */
+ virtual void postFunctionPrepare() = 0;
+
+public: // methods for dynamic tensor allocation
+ /**
+ * @brief Get dynamicTensorManager. If a backend does not support dynamic tensor, exception
+ * will be thrown.
+ *
+ * @return pointer of IDynamicTensorManager object
+ *
+ * @note Since it is a pointer, its life time is from the cration of TensorBuilder
+ * to the end of execution
+ */
+ virtual IDynamicTensorManager *dynamicTensorManager(void) { return nullptr; }
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ITENSOR_BUILDER_H__
diff --git a/runtime/onert/core/include/backend/ITensorManager.h b/runtime/onert/core/include/backend/ITensorManager.h
new file mode 100644
index 000000000..4974b6645
--- /dev/null
+++ b/runtime/onert/core/include/backend/ITensorManager.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ITENSOR_MANAGER_H__
+#define __ONERT_BACKEND_ITENSOR_MANAGER_H__
+
+namespace onert
+{
+namespace backend
+{
+
+// NOTE This name ITensorManager has been discussed whether or not the name is proper.
+// Anyone can argue with any better name.
+/**
+ * @brief Interface as an abstract tensor manager which has MemoryManager
+ * This is used as a base class for IStaticTensorManager and IDynamicTensorManager
+ */
+struct ITensorManager
+{
+ virtual ~ITensorManager() = default;
+};
+
+} // namespace backend
+} // namespace onert
+
+#include <unordered_set>
+#include <memory>
+
+namespace onert
+{
+namespace backend
+{
+
+using TensorManagerSet = std::unordered_set<std::unique_ptr<backend::ITensorManager>>;
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ITENSOR_MANAGER_H__
diff --git a/runtime/onert/core/include/backend/ITensorRegister.h b/runtime/onert/core/include/backend/ITensorRegister.h
new file mode 100644
index 000000000..b8e521ce3
--- /dev/null
+++ b/runtime/onert/core/include/backend/ITensorRegister.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ITENSOR_REGISTER_H__
+#define __ONERT_BACKEND_ITENSOR_REGISTER_H__
+
+#include "ir/LowerInfoMap.h"
+#include "ITensorBuilder.h"
+#include "ir/Layout.h"
+#include "ir/OperandIndexSequence.h"
+#include "ir/OperandInfo.h"
+#include "ir/Operands.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace backend
+{
+
+class ITensorRegister : public ir::OperationVisitor
+{
+public:
+ virtual ~ITensorRegister() = default;
+
+public:
+ void registerTensors(const ir::OpSequence &op_seq, const ir::LowerInfoMap *lower_info_map)
+ {
+ _current_op_seq_layout = op_seq.getLayout();
+ _lower_info_map = lower_info_map;
+ assert(_lower_info_map != nullptr);
+ assert(tensor_builder().get() != nullptr);
+ op_seq.accept(*this);
+ }
+
+protected:
+ virtual const ir::Operands &operands() const = 0;
+ virtual std::shared_ptr<ITensorBuilder> tensor_builder() const = 0;
+
+protected:
+#define OP(InternalName) \
+ void visit(const ir::operation::InternalName &node) override \
+ { \
+ for (const auto &ind : (node.getInputs() | ir::Remove::UNDEFINED) + node.getOutputs()) \
+ { \
+ defaultRegisterTensorInfo(ind); \
+ } \
+ }
+#include "ir/Operations.lst"
+#undef OP
+
+protected:
+ void defaultRegisterTensorInfo(const ir::OperandIndex &index) const
+ {
+ if (tensor_builder()->isRegistered(index))
+ {
+ return;
+ }
+
+ const auto &obj = operands().at(index);
+ const auto frontend_layout = frontendLayout();
+ const auto backend_layout = backendLayout(index);
+ ir::OperandInfo backend_info{permuteShape(obj.shape(), frontend_layout, backend_layout),
+ obj.typeInfo(), obj.info().memAllocType(), obj.isConstant()};
+ tensor_builder()->registerTensorInfo(index, backend_info, backend_layout);
+ }
+
+protected:
+ ir::Layout frontendLayout() const { return _current_op_seq_layout; }
+ ir::Layout backendLayout(const ir::OperandIndex &index) const
+ {
+ assert(_lower_info_map != nullptr);
+ const auto lower_info = _lower_info_map->operand.at(index).get();
+ return lower_info->def_factors().getOnlyElement().layout();
+ }
+
+private:
+ ir::Layout _current_op_seq_layout;
+ const ir::LowerInfoMap *_lower_info_map{nullptr};
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ITENSOR_REGISTER_H__
diff --git a/runtime/onert/core/include/backend/ITensorRegistry.h b/runtime/onert/core/include/backend/ITensorRegistry.h
new file mode 100644
index 000000000..b256a1fb8
--- /dev/null
+++ b/runtime/onert/core/include/backend/ITensorRegistry.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_ITENSOR_REGISTRY__
+#define __ONERT_BACKEND_ITENSOR_REGISTRY__
+
+#include <memory>
+
+#include "ir/Index.h"
+#include "backend/ITensor.h"
+#include "backend/IPortableTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+
+struct ITensorRegistry
+{
+ /**
+ * @brief Deconstruct itself
+ */
+ virtual ~ITensorRegistry() = default;
+
+ /**
+ * @brief Returns pointer of ITensor among native and migrant tensors
+ *
+ * Native Tensor is a tensor that is managed by this backend
+ * Migrant Tensor is a tensor that is imported from another backend
+ *
+ * @note Return tensor cannot be used longer than dynamic tensor manager
+ */
+ virtual ITensor *getITensor(const ir::OperandIndex &) = 0;
+ /**
+ * @brief Returns pointer of ITensor among native tensors
+ *
+ * Unlike @c getITensor , this function only searches from native tensors
+ *
+ * @note Returned tensor cannot be used longer than dynamic tensor manager
+ */
+ virtual ITensor *getNativeITensor(const ir::OperandIndex &) = 0;
+ /**
+ * @brief Set the Migrant Tensor which are from other backends
+ *
+ * @return true if supported
+ * @return false if not supported
+ */
+ virtual bool setMigrantTensor(const ir::OperandIndex &, IPortableTensor *) { return false; }
+};
+
+} // namespace backend
+} // namespace onert
+
+#include "ir/OperandIndexMap.h"
+
+namespace onert
+{
+namespace backend
+{
+
+/**
+ * @brief TensorRegistry template class for the convenience of backend implementations
+ *
+ * If a backend uses @c IPortableTensor , and there is no special reason to implement @c
+ * ITensorRegistry on your own, you may just use this default implementation.
+ *
+ * @tparam T_Tensor Tensor type. Must be a subclass of @c onert::backend::IPortableTensor .
+ */
+template <typename T_Tensor> class PortableTensorRegistryTemplate : public ITensorRegistry
+{
+public:
+ ITensor *getITensor(const ir::OperandIndex &ind) override
+ {
+ static_assert(std::is_base_of<ITensor, T_Tensor>::value, "T_Tensor must derive from ITensor.");
+ auto _migrant_tensor = _migrant.find(ind);
+ if (_migrant_tensor != _migrant.end())
+ return _migrant_tensor->second;
+ return getNativeTensor(ind);
+ }
+
+ ITensor *getNativeITensor(const ir::OperandIndex &ind) override { return getNativeTensor(ind); }
+
+ IPortableTensor *getPortableTensor(const ir::OperandIndex &ind)
+ {
+ auto _migrant_tensor = _migrant.find(ind);
+ if (_migrant_tensor != _migrant.end())
+ {
+ if (_migrant_tensor->second)
+ return _migrant_tensor->second;
+ }
+ return getNativeTensor(ind);
+ }
+
+ T_Tensor *getNativeTensor(const ir::OperandIndex &ind)
+ {
+ auto tensor = _native.find(ind);
+ if (tensor != _native.end())
+ return tensor->second.get();
+ return nullptr;
+ }
+
+ bool setMigrantTensor(const ir::OperandIndex &ind, IPortableTensor *tensor) override
+ {
+ assert(tensor != nullptr);
+ auto itr = _native.find(ind);
+ if (itr != _native.end())
+ throw std::runtime_error{"Tried to set a migrant tensor but a native tensor already exists."};
+ _migrant[ind] = tensor;
+ return true;
+ }
+
+ void setNativeTensor(const ir::OperandIndex &ind, std::unique_ptr<T_Tensor> &&tensor)
+ {
+ assert(tensor != nullptr);
+ auto itr = _migrant.find(ind);
+ if (itr != _migrant.end())
+ throw std::runtime_error{"Tried to set a native tensor but a migrant tensor already exists."};
+ _native[ind] = std::move(tensor);
+ }
+
+ const ir::OperandIndexMap<std::unique_ptr<T_Tensor>> &native_tensors() { return _native; }
+
+ const ir::OperandIndexMap<IPortableTensor *> &migrant_tensors() { return _migrant; }
+
+private:
+ ir::OperandIndexMap<IPortableTensor *> _migrant;
+ ir::OperandIndexMap<std::unique_ptr<T_Tensor>> _native;
+};
+
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_ITENSOR_REGISTRY__
diff --git a/runtime/onert/core/include/backend/cpu_common/Allocator.h b/runtime/onert/core/include/backend/cpu_common/Allocator.h
new file mode 100644
index 000000000..fa67fc7c4
--- /dev/null
+++ b/runtime/onert/core/include/backend/cpu_common/Allocator.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        Allocator.h
+ * @brief       This file contains Allocator related classes
+ */
+
+#ifndef __ONERT_BACKEND_CPU_COMMON_ALLOCATOR_H__
+#define __ONERT_BACKEND_CPU_COMMON_ALLOCATOR_H__
+
+#include <memory>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+/**
+ * @brief Class to allocate memory
+ */
+class Allocator
+{
+public:
+ Allocator(uint32_t capacity);
+ /**
+ * @brief Get memory base pointer
+ * @return base pointer
+ */
+ uint8_t *base() const { return _base.get(); }
+ void release() { _base.reset(); }
+
+private:
+ std::unique_ptr<uint8_t[]> _base;
+};
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_COMMON_ALLOCATOR_H__
diff --git a/runtime/onert/core/include/backend/cpu_common/DynamicTensorManager.h b/runtime/onert/core/include/backend/cpu_common/DynamicTensorManager.h
new file mode 100644
index 000000000..c4e06aa82
--- /dev/null
+++ b/runtime/onert/core/include/backend/cpu_common/DynamicTensorManager.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_COMMON_DYNAMICTENSOR_MANAGER_H__
+#define __ONERT_BACKEND_CPU_COMMON_DYNAMICTENSOR_MANAGER_H__
+
+#include "MemoryManager.h"
+#include "TensorRegistry.h"
+
+#include <backend/IDynamicTensorManager.h>
+#include <ir/OperandInfo.h>
+#include <ir/Operation.h>
+#include <ir/Index.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+// TODO Find optimized algorithm to manage memory.
+
+/**
+ * @brief Class to manage dynamic tensor and its memory
+ */
+class DynamicTensorManager : public backend::IDynamicTensorManager
+{
+public:
+ DynamicTensorManager(const std::shared_ptr<TensorRegistry> &reg);
+
+ virtual ~DynamicTensorManager() = default;
+
+ void buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &tensor_info,
+ ir::Layout backend_layout);
+
+ void planDealloc(ir::OperationIndex op_ind, backend::ITensor *tensor) override;
+ void deallocInput(ir::OperationIndex op_ind) override;
+
+ std::shared_ptr<DynamicMemoryManager> dynamic_mem_mgr() { return _dynamic_mem_mgr; }
+
+private:
+ const ITensor *getRawITensor(ir::OperandIndex ind);
+
+private:
+ /**
+ * @brief Memory manager for dynamic tensor.
+ * @todo DynamicMemoryManager is not optimized. Optimized one is needed
+ */
+ std::shared_ptr<DynamicMemoryManager> _dynamic_mem_mgr;
+ const std::shared_ptr<TensorRegistry> _tensors;
+
+ // contains list of dynamic tensor index, which can be deallocated after running operation
+ // note: this map could contain static tensor index too. Careful use is required.
+ std::unordered_map<ir::OperationIndex, std::unordered_set<backend::ITensor *>>
+ _dealloc_tensor_map;
+};
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_COMMON_DYNAMICTENSOR_MANAGER_H__
diff --git a/runtime/onert/core/include/backend/cpu_common/IMemoryPlanner.h b/runtime/onert/core/include/backend/cpu_common/IMemoryPlanner.h
new file mode 100644
index 000000000..335f8f5c0
--- /dev/null
+++ b/runtime/onert/core/include/backend/cpu_common/IMemoryPlanner.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_IMEMORY_PLANNER_H__
+#define __ONERT_BACKEND_IMEMORY_PLANNER_H__
+
+#include "ir/OperandIndexMap.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+/**
+ * @brief Structure to have memory offset and size
+ */
+struct Block
+{
+ uint32_t offset;
+ size_t size;
+};
+
+/**
+ * @brief Interface to plan memory
+ */
+struct IMemoryPlanner
+{
+ using MemoryPlans = ir::OperandIndexMap<Block>;
+
+ /**
+ * @brief Claim memory for operand
+ * @param[in] index The operand index
+ * @param[in] size The size of the memory
+ */
+ virtual void claim(const ir::OperandIndex &, size_t) = 0;
+ /**
+ * @brief Release memory for operand
+ * @param[in] index The operand index
+ */
+ virtual void release(const ir::OperandIndex &) = 0;
+ /**
+ * @brief Get capacity for memory planning
+ * @return The value of capacity
+ */
+ virtual uint32_t capacity() = 0;
+ /**
+ * @brief Get MemoryPlans
+ * @return MemoryPlans
+ */
+ virtual MemoryPlans &memory_plans() = 0;
+
+ virtual ~IMemoryPlanner() = default;
+};
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_IMEMORY_PLANNER_H__
diff --git a/runtime/onert/core/include/backend/cpu_common/MemoryManager.h b/runtime/onert/core/include/backend/cpu_common/MemoryManager.h
new file mode 100644
index 000000000..28ec6b803
--- /dev/null
+++ b/runtime/onert/core/include/backend/cpu_common/MemoryManager.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_MEMORY_MANAGER_H__
+#define __ONERT_BACKEND_CPU_MEMORY_MANAGER_H__
+
+#include "Allocator.h"
+#include "backend/IMemoryManager.h"
+#include "IMemoryPlanner.h"
+
+namespace onert
+{
+namespace backend
+{
+
+class ITensor;
+
+namespace cpu_common
+{
+
+class MemoryManager : public backend::IMemoryManager
+{
+public:
+ MemoryManager();
+ MemoryManager(const std::string);
+ virtual ~MemoryManager() = default;
+
+ void allocate(void) override;
+ uint8_t *getBuffer(const ir::OperandIndex &ind) const;
+ void deallocate(void) override { _mem_alloc->release(); }
+
+ void claimPlan(const ir::OperandIndex &ind, uint32_t size);
+ void releasePlan(const ir::OperandIndex &ind);
+
+private:
+ IMemoryPlanner *createMemoryPlanner();
+ IMemoryPlanner *createMemoryPlanner(const std::string);
+
+private:
+ ir::OperandIndexMap<Block> _tensor_mem_map;
+ std::shared_ptr<IMemoryPlanner> _mem_planner;
+ std::shared_ptr<Allocator> _mem_alloc;
+};
+
+class DynamicMemoryManager
+{
+public:
+ DynamicMemoryManager() = default;
+ virtual ~DynamicMemoryManager() = default;
+
+ std::shared_ptr<Allocator> allocate(const ITensor *tensor, uint32_t capacity);
+ void deallocate(const ITensor *tensor);
+ void deallocate(void);
+
+private:
+ std::unordered_map<const ITensor *, std::shared_ptr<Allocator>> _mem_alloc_map;
+};
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_MEMORY_MANAGER_H__
diff --git a/runtime/onert/core/include/backend/cpu_common/StaticTensorManager.h b/runtime/onert/core/include/backend/cpu_common/StaticTensorManager.h
new file mode 100644
index 000000000..fa50b551e
--- /dev/null
+++ b/runtime/onert/core/include/backend/cpu_common/StaticTensorManager.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_COMMON_STATICTENSOR_MANAGER_H__
+#define __ONERT_BACKEND_CPU_COMMON_STATICTENSOR_MANAGER_H__
+
+#include "MemoryManager.h"
+
+#include "backend/IStaticTensorManager.h"
+#include "ir/OperandIndexMap.h"
+#include "ir/OperandInfo.h"
+#include "TensorRegistry.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+class DynamicTensorManager;
+
+class StaticTensorManager : public backend::IStaticTensorManager
+{
+public:
+ StaticTensorManager(const std::shared_ptr<TensorRegistry> &reg,
+ DynamicMemoryManager *dynamic_mem_mgr);
+ virtual ~StaticTensorManager() = default;
+
+ void allocateConsts(void);
+ void allocateNonconsts(void);
+ void deallocateConsts(void);
+ void deallocateNonconsts(void);
+
+ void buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &tensor_info,
+ ir::Layout backend_layout, bool as_const);
+
+ void claimPlan(const ir::OperandIndex &ind, uint32_t size);
+ void releasePlan(const ir::OperandIndex &ind);
+
+ void iterate(const std::function<void(const ir::OperandIndex &)> &fn);
+
+private:
+ std::unique_ptr<DynamicMemoryManager> _const_mgr;
+ std::unique_ptr<MemoryManager> _nonconst_mgr;
+ const std::shared_ptr<TensorRegistry> _tensors;
+ ir::OperandIndexMap<bool> _as_constants;
+ DynamicMemoryManager *_dynamic_mem_mgr;
+};
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_COMMON_STATICTENSOR_MANAGER_H__
diff --git a/runtime/onert/core/include/backend/cpu_common/Tensor.h b/runtime/onert/core/include/backend/cpu_common/Tensor.h
new file mode 100644
index 000000000..5fa20e15d
--- /dev/null
+++ b/runtime/onert/core/include/backend/cpu_common/Tensor.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_COMMON_TENSOR_H__
+#define __ONERT_BACKEND_CPU_COMMON_TENSOR_H__
+
+#include "Allocator.h"
+
+#include <backend/IPortableTensor.h>
+#include <ir/OperandInfo.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+class DynamicMemoryManager;
+
+class Tensor : public IPortableTensor
+{
+public:
+ Tensor() = delete;
+ virtual ~Tensor();
+
+public:
+ Tensor(const ir::OperandInfo &info, const ir::Layout layout,
+ DynamicMemoryManager *dynamic_mem_mgr)
+ : IPortableTensor(info), _layout(layout), _buffer(nullptr), _num_references(0),
+ _dynamic_mem_mgr(dynamic_mem_mgr), _allocator(nullptr)
+ {
+ // DO NOTHING
+ }
+
+public:
+ // Only one of two method 'setBuffer' must be called once
+
+ /**
+ * @brief Set the Buffer object. This method is called for static and non-const tensor
+ */
+ void setBuffer(uint8_t *buffer)
+ {
+ assert(_buffer == nullptr);
+ _buffer = buffer;
+ }
+
+ /**
+ * @brief Set the Buffer object. This method is called for dynamic or const tensor
+ */
+ void setBuffer(const std::shared_ptr<Allocator> &alloc)
+ {
+ assert(_buffer == nullptr);
+ _allocator = alloc;
+ _buffer = alloc->base();
+ }
+
+ // This works just as setBuffer but it simply overwrite existing Allocator without nullptr check
+ void overwriteBuffer(const std::shared_ptr<Allocator> &alloc)
+ {
+ _allocator = alloc;
+ _buffer = alloc->base();
+ }
+
+ /**
+ * @brief Mark this tensor does not have memory.
+ * Real memory deallocation should be done by caller.
+ */
+ void resetBuffer()
+ {
+ _allocator.reset();
+ _buffer = nullptr;
+ }
+
+public:
+ uint8_t *buffer() const override { return _buffer; }
+ /**
+ * @brief Get dimension by index
+ *
+ * @param index Index to get diemension
+ * @return size_t Dimension at index
+ * @note N : dimension(0)
+ * H : dimension(1)
+ * W : dimension(2)
+ * C : dimension(3)
+ */
+ size_t dimension(size_t index) const final override { return _info.shape().dim(index); }
+ size_t num_dimensions() const override { return _info.shape().rank(); }
+ size_t total_size() const override { return _info.total_size(); }
+ size_t calcOffset(const ir::Coordinates &coords) const override;
+ ir::Layout layout() const override { return _layout; }
+ ir::DataType data_type() const override { return _info.typeInfo().type(); }
+ float data_scale() const override { return _info.typeInfo().scale(); }
+ int32_t data_offset() const override { return _info.typeInfo().offset(); }
+ bool is_constant() const override { return _info.isConstant(); }
+ bool is_dynamic() const override { return _info.isDynamic(); }
+ void set_dynamic() override { _info.setDynamic(); }
+ bool applyShape(const ir::Shape &new_shape) override;
+ const ir::Sparsity *sparsity() const override { return _info.typeInfo().sparsity(); }
+
+ virtual void increase_ref()
+ {
+ assert(is_dynamic() ||
+ // when not dynamic
+ (_buffer != nullptr));
+
+ ++_num_references;
+ }
+
+ virtual void decrease_ref()
+ {
+ assert(_buffer != nullptr || _allocator != nullptr);
+ assert(_num_references > 0);
+ --_num_references;
+ // constant tensor and dynamic tensor has _allocator
+ if (_num_references == 0)
+ {
+ if (_buffer != nullptr)
+ _buffer = nullptr;
+ if (_allocator != nullptr)
+ {
+ _allocator->release();
+ _allocator = nullptr;
+ }
+ }
+ }
+
+ /**
+ * @brief Reset reference count to zero and release data
+ */
+ virtual void reset_ref()
+ {
+ assert(_buffer != nullptr || _allocator != nullptr);
+ assert(_num_references > 0);
+ _num_references = 0;
+
+ // Only constant tensor has allocator pointer
+ if (_buffer != nullptr)
+ _buffer = nullptr;
+ else
+ {
+ _allocator->release();
+ _allocator = nullptr;
+ }
+ }
+
+ virtual int32_t num_references() { return _num_references; }
+
+ void setShape(const ir::Shape &new_shape) override;
+
+protected:
+ ir::Layout _layout;
+ uint8_t *_buffer;
+ int32_t _num_references;
+ DynamicMemoryManager *_dynamic_mem_mgr;
+
+private:
+ /**
+ * @brief Memory allocator for dynamic tensor and const tensor
+ * Since maintaing _allocator and also _buffer makes confusion,
+ * we will mainly use _buffer (not _allocator.base()) for memory pointer in this code.
+ * _allocator(shared_ptr) is used to guarantee that we have valid _buffer.
+ */
+ std::shared_ptr<Allocator> _allocator;
+};
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_COMMON_TENSOR_H__
diff --git a/runtime/onert/core/include/backend/cpu_common/TensorRegistry.h b/runtime/onert/core/include/backend/cpu_common/TensorRegistry.h
new file mode 100644
index 000000000..5896fb7ad
--- /dev/null
+++ b/runtime/onert/core/include/backend/cpu_common/TensorRegistry.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_COMMON_TENSOR_REGISTRY__
+#define __ONERT_BACKEND_CPU_COMMON_TENSOR_REGISTRY__
+
+#include "backend/ITensorRegistry.h"
+#include "Tensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+using TensorRegistry = PortableTensorRegistryTemplate<cpu_common::Tensor>;
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_COMMON_TENSOR_REGISTRY__
diff --git a/runtime/onert/core/include/compiler/BackendManager.h b/runtime/onert/core/include/compiler/BackendManager.h
new file mode 100644
index 000000000..af13d13f7
--- /dev/null
+++ b/runtime/onert/core/include/compiler/BackendManager.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_BACKEND_MANAGER_H__
+#define __ONERT_COMPILER_BACKEND_MANAGER_H__
+
+#include <memory>
+#include <map>
+
+#include "ir/Operands.h"
+#include "backend/Backend.h"
+#include "backend/controlflow/Backend.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+class BackendManager
+{
+public:
+ using backend_create_t = backend::Backend *(*)();
+ using backend_destroy_t = void (*)(backend::Backend *);
+ using dlhandle_destroy_t = void (*)(void *);
+
+ static BackendManager &get();
+
+public:
+ backend::Backend *get(const std::string &key);
+ const backend::Backend *get(const std::string &key) const;
+ const backend::controlflow::Backend *getControlflow() const;
+ const std::vector<const backend::Backend *> getAll() const
+ {
+ std::vector<const backend::Backend *> v;
+ for (const auto &p : _gen_map)
+ v.emplace_back(p.second.get());
+ return v;
+ }
+ size_t num_backends() const { return _gen_map.size(); }
+ /**
+ * @brief load backend plugin
+ *
+ * @param backend backend to be loaded
+ *
+ * @return
+ */
+ void loadBackend(const std::string &backend);
+
+private:
+ BackendManager();
+
+private:
+ std::map<std::string, std::unique_ptr<void, dlhandle_destroy_t>> _handle_map;
+ std::map<std::string, std::unique_ptr<backend::Backend, backend_destroy_t>> _gen_map;
+ backend::controlflow::Backend *_controlflow{nullptr};
+ /**
+ * @brief load controlflow backend
+ *
+ * @param backend backend to be loaded
+ *
+ * @return
+ */
+ void loadControlflowBackend();
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_BACKEND_MANAGER_H__
diff --git a/runtime/onert/core/include/compiler/BackendResolver.h b/runtime/onert/core/include/compiler/BackendResolver.h
new file mode 100644
index 000000000..a316b4335
--- /dev/null
+++ b/runtime/onert/core/include/compiler/BackendResolver.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_BACKEND_RESOLVER_H__
+#define __ONERT_COMPILER_BACKEND_RESOLVER_H__
+
+#include <unordered_map>
+#include <typeindex>
+
+#include "backend/Backend.h"
+#include "ir/OperationIndexMap.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+class BackendResolver
+{
+public:
+ const backend::Backend *getBackend(const ir::OperationIndex &index) const
+ {
+ return _gen_map.at(index);
+ }
+
+ void setBackend(const ir::OperationIndex &index, const backend::Backend *backend)
+ {
+ _gen_map[index] = backend;
+ }
+
+ void
+ iterate(const std::function<void(const ir::OperationIndex &, const backend::Backend &)> &fn) const
+ {
+ for (const auto &e : _gen_map)
+ {
+ fn(e.first, *e.second);
+ }
+ }
+
+private:
+ ir::OperationIndexMap<const backend::Backend *> _gen_map;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_BACKEND_RESOLVER_H__
diff --git a/runtime/onert/core/include/compiler/CodeMap.h b/runtime/onert/core/include/compiler/CodeMap.h
new file mode 100644
index 000000000..e13d3334c
--- /dev/null
+++ b/runtime/onert/core/include/compiler/CodeMap.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_CODE_MAP_H__
+#define __ONERT_COMPILER_CODE_MAP_H__
+
+#include <unordered_map>
+
+namespace onert
+{
+namespace compiler
+{
+
+struct CodeAndInfo
+{
+ const ir::OpSequence *op_seq;
+ const ir::operation::LowerInfo *lower_info;
+ std::unique_ptr<exec::FunctionSequence> fn_seq;
+
+ CodeAndInfo(const ir::OpSequence *op_seq, const ir::operation::LowerInfo *lower_info,
+ std::unique_ptr<exec::FunctionSequence> &&fn_seq)
+ : op_seq{op_seq}, lower_info{lower_info}, fn_seq{std::move(fn_seq)}
+ {
+ }
+};
+
+using CodeMap = std::unordered_map<ir::OpSequenceIndex, CodeAndInfo>;
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_CODE_MAP_H__
diff --git a/runtime/onert/core/include/compiler/Compiler.h b/runtime/onert/core/include/compiler/Compiler.h
new file mode 100644
index 000000000..3098be7ba
--- /dev/null
+++ b/runtime/onert/core/include/compiler/Compiler.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Compiler.h
+ * @brief This file contains Compiler class to define and run compilation phase
+ */
+
+#ifndef __ONERT_COMPILER_COMPILE_H_
+#define __ONERT_COMPILER_COMPILE_H_
+
+#include "ir/Graph.h"
+#include "exec/IExecutor.h"
+
+namespace onert
+{
+
+namespace compiler
+{
+
+enum class State
+{
+ CREATED, // Before compilation
+ COMPILED // Success compilation
+};
+
+struct ManualSchedulerOptions
+{
+ std::string backend_for_all;
+ std::unordered_map<ir::OpCode, std::string> opcode_to_backend;
+ std::unordered_map<ir::OperationIndex, std::string> index_to_backend;
+};
+
+struct CompilerOptions
+{
+ // GENERAL OPTIONS
+ std::vector<std::string> backend_list;
+ bool is_primary_subgraph; // TODO Remove this out of this struct as it is not user-given option
+
+ // OPTIONS ONLY FOR DEBUGGING/PROFILING
+ std::string trace_filepath; //< File path to save trace records
+ int graph_dump_level; //< Graph dump level, values between 0 and 2 are valid
+ int op_seq_max_node; //< Number of nodes that can be
+ std::string executor; //< Executor name to use
+ ManualSchedulerOptions manual_scheduler_options; //< Options for ManualScheduler
+ bool he_scheduler; //< HEScheduler if true, ManualScheduler otherwise
+ bool he_profiling_mode; //< Whether HEScheduler profiling mode ON/OFF
+ bool disable_compile; //< Run with Interpreter if true, try compilation otherwise
+ bool fp16_enable; //< Whether fp16 mode ON/OFF
+};
+
+CompilerOptions fetchCompilerOptionsFromGlobalConfig(const ir::Subgraphs &subgs);
+
+/**
+ * @brief Class to compile graph model
+ */
+class Compiler
+{
+public:
+ /**
+ * @brief Construct a new Compiler object
+ * @param[in] subgs All subgraphs of a model
+ */
+ Compiler(const std::shared_ptr<ir::Subgraphs> &subgs);
+
+public:
+ /**
+ * @brief Do compilation with the options
+ *
+ * @return std::shared_ptr<exec::ExecutorMap> Executors as a result of compilation
+ */
+ std::shared_ptr<exec::ExecutorMap> compile(void);
+
+ State state(void) const { return _state; }
+
+ /**
+ * @brief Check if model can compile
+ * @return @c true if model can compile, otherwise @c false
+ * @note This method don't check model correctness,\n
+ * so model verification should be done before calling this method
+ */
+ bool checkCompilable();
+ CompilerOptions &options() { return _options; }
+
+ /**
+ * @brief Allow to compute float32 using float16 data type
+ */
+ void enableToFp16();
+
+private:
+ void checkProfilerConditions();
+ std::shared_ptr<ir::Graph> &primary_subgraph() { return _subgraphs->at(ir::SubgraphIndex{0}); }
+
+private:
+ std::shared_ptr<ir::Subgraphs> _subgraphs;
+ // NOTE These executors does not have duplicated subgraph. This mean they do not allow support
+ // subgraphs being called recursively because data of non-constant tensor of parent executor will
+ // be updated by child executor. If you want to support subgraphs being called recursively, you
+ // have to add allocate non-constant tensor memory of executors in execution time when each
+ // subgraph is called.
+ State _state;
+ CompilerOptions _options;
+};
+
+} // namespace compiler
+
+} // namespace onert
+
+#endif // __ONERT_COMPILER_COMPILE_H_
diff --git a/runtime/onert/core/include/compiler/ExecutionBuilder.h b/runtime/onert/core/include/compiler/ExecutionBuilder.h
new file mode 100644
index 000000000..d54d9d046
--- /dev/null
+++ b/runtime/onert/core/include/compiler/ExecutionBuilder.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_EXECUTION_BUILDER_H__
+#define __ONERT_COMPILER_EXECUTION_BUILDER_H__
+
+#include <memory>
+
+#include "ir/operation/LowerInfo.h"
+#include "ir/OpSequence.h"
+#include "exec/FunctionSequence.h"
+#include "CodeMap.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+class ExecutionBuilder
+{
+public:
+ void append(const ir::OpSequenceIndex index, CodeAndInfo &&code_and_info)
+ {
+ _code_map.emplace(index, std::move(code_and_info));
+ }
+
+ CodeMap releaseCodeMap() { return std::move(_code_map); }
+
+private:
+ CodeMap _code_map;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_EXECUTION_BUILDER_H__
diff --git a/runtime/onert/core/include/compiler/LoweredGraph.h b/runtime/onert/core/include/compiler/LoweredGraph.h
new file mode 100644
index 000000000..aadba6857
--- /dev/null
+++ b/runtime/onert/core/include/compiler/LoweredGraph.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_LOWERED_GRAPH_H__
+#define __ONERT_IR_LOWERED_GRAPH_H__
+
+#include "ir/Graph.h"
+#include "ir/LowerInfoMap.h"
+#include "ir/OpSequences.h"
+#include "compiler/BackendResolver.h"
+#include "compiler/Compiler.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+/**
+ * @brief Class that contains lowering information on graph.
+ * In addition, after lowering, operands in graph will be set to "dynamic"
+ * if the shape of output of an operation cannot be decided at compilation time.
+ */
+class LoweredGraph
+{
+public:
+ LoweredGraph(const ir::Graph &graph, const compiler::CompilerOptions &options);
+
+ ir::Graph &graph() { return _graph; }
+ const ir::Graph &graph() const { return _graph; }
+ const ir::LowerInfoMap *getLowerInfo() const { return &_lower_info_map; }
+ const ir::operation::LowerInfo *getLowerInfo(const ir::OpSequenceIndex &op_seq_index) const;
+ void setLowerInfo(const ir::OpSequenceIndex &op_seq_index,
+ std::unique_ptr<ir::operation::LowerInfo> &&lower_info);
+ void removeLowerInfo(const ir::OpSequenceIndex &op_seq_index);
+ const ir::operand::LowerInfo *getLowerInfo(const ir::OperandIndex &index) const;
+ ir::operand::LowerInfo *getLowerInfo(const ir::OperandIndex &index);
+ void setLowerInfo(const ir::OperandIndex &index,
+ std::unique_ptr<ir::operand::LowerInfo> &&lower_info);
+ void removeLowerInfo(const ir::OperandIndex &index);
+ ir::OpSequences &op_seqs() { return _op_seqs; }
+ const ir::OpSequences &op_seqs() const { return _op_seqs; }
+ void iterateTopolOpSeqs(
+ const std::function<void(const ir::OpSequenceIndex &, const ir::OpSequence &)> &fn) const;
+ void
+ iterateTopolOpSeqs(const std::function<void(const ir::OpSequenceIndex &, ir::OpSequence &)> &fn);
+ const backend::BackendContexts &backend_contexts() { return _backend_contexts; }
+ const backend::BackendContexts &backend_contexts() const { return _backend_contexts; }
+ std::shared_ptr<ir::OperationIndexMap<int64_t>> indexed_ranks() { return _indexed_ranks; }
+
+private:
+ void
+ makeOpSequences(ir::OperandIndexMap<std::unique_ptr<ir::operand::LowerInfo>> &operands_lower_info,
+ const compiler::CompilerOptions &options,
+ const compiler::BackendResolver &backend_resolver);
+
+ void manipulateLowerInfo(
+ ir::OperandIndexMap<std::unique_ptr<ir::operand::LowerInfo>> &operands_lower_info,
+ bool is_primary);
+ void dumpLowerInfo();
+ bool mergeable(const ir::OpSequenceIndex &op_seq_index, const ir::OperationIndex &node_index,
+ ir::Layout layout, const compiler::BackendResolver &backend_resolver);
+ ir::OpSequenceIndex appendFreshSingleOpSequence(const ir::OperationIndex &node_index,
+ const ir::Operation &node);
+
+private:
+ ir::Graph _graph;
+ backend::BackendContexts _backend_contexts;
+ std::shared_ptr<ir::OperationIndexMap<int64_t>> _indexed_ranks;
+ ir::LowerInfoMap _lower_info_map;
+ // Pass(for Perm) can accept only graph so that Graph has OpSequences as a member
+ ir::OpSequences _op_seqs;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_IR_LOWERED_GRAPH_H__
diff --git a/runtime/onert/core/include/compiler/StaticShapeInferer.h b/runtime/onert/core/include/compiler/StaticShapeInferer.h
new file mode 100644
index 000000000..05f2679fc
--- /dev/null
+++ b/runtime/onert/core/include/compiler/StaticShapeInferer.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_STATIC_SHAPE_INFERER_H__
+#define __ONERT_COMPILER_STATIC_SHAPE_INFERER_H__
+
+#include "ir/OperationVisitor.h"
+#include "ir/OpSequence.h"
+#include "compiler/LoweredGraph.h"
+#include "ir/Index.h"
+
+#include <memory>
+#include <unordered_map>
+
+namespace onert
+{
+namespace compiler
+{
+
+/**
+ * @brief Class to infer shape before running kernels. It does the following:
+ * - re-calculate and set output shape at compile time (before running kernels)
+ * - if calculation cannot be done at compile time, mark the outputs to be dynamic, meaning
+ * shapes of outputs will be calculated during running kernels
+ */
+class StaticShapeInferer : public ir::OperationVisitor
+{
+public:
+ StaticShapeInferer(
+ const ir::SubgraphIndex &subg_idx,
+ const std::unordered_map<ir::SubgraphIndex, std::unique_ptr<compiler::LoweredGraph>>
+ &lowered_subgs)
+ : _lowered_subgs(lowered_subgs), _operands(lowered_subgs.at(subg_idx)->graph().operands()),
+ _operations(lowered_subgs.at(subg_idx)->graph().operations()),
+ _return_has_dynamic_tensor(false)
+ { /* empty */
+ }
+ virtual ~StaticShapeInferer() = default;
+
+public:
+ /**
+ * @brief Infer shape of operands beloning to ops and set the output shape.
+ * If output shape cannot be known without running op, mark it so that it can be allocated
+ * when running kernel.
+ * @param op_seq sequence of operations
+ * @return @c true if op_seq's input or output has any dynamic tensor; @c false otherwise.
+ */
+ bool infer(const ir::OpSequence &op_seq);
+
+ void dump();
+
+private:
+ bool checkDynamicInput(const ir::Operation &op);
+ void setDynamicOutput(const ir::Operation &op);
+
+private:
+ // TODO Define visitors for operations. List them in alphabetic order.
+ void visit(const ir::operation::ArgMax &op) override;
+ void visit(const ir::operation::BatchMatMul &op) override;
+ void visit(const ir::operation::BCQFullyConnected &op) override;
+ void visit(const ir::operation::BCQGather &op) override;
+ void visit(const ir::operation::BinaryArithmetic &op) override;
+ void visit(const ir::operation::BroadcastTo &op) override;
+ void visit(const ir::operation::Comparison &op) override;
+ void visit(const ir::operation::Concat &op) override;
+ void visit(const ir::operation::Conv2D &op) override;
+ void visit(const ir::operation::ElementwiseActivation &op) override;
+ void visit(const ir::operation::ElementwiseBinary &op) override;
+ void visit(const ir::operation::ElementwiseUnary &op) override;
+ void visit(const ir::operation::ExpandDims &op) override;
+ void visit(const ir::operation::Fill &op) override;
+ void visit(const ir::operation::FullyConnected &op) override;
+ void visit(const ir::operation::FusedBatchNorm &op) override;
+ void visit(const ir::operation::Gather &op) override;
+ void visit(const ir::operation::If &op) override;
+ void visit(const ir::operation::L2Normalization &op) override;
+ void visit(const ir::operation::LSTM &op) override;
+ void visit(const ir::operation::MatrixBandPart &op) override;
+ void visit(const ir::operation::OneHot &op) override;
+ void visit(const ir::operation::Pack &op) override;
+ void visit(const ir::operation::Pad &op) override;
+ void visit(const ir::operation::Permute &op) override;
+ void visit(const ir::operation::Pow &op) override;
+ void visit(const ir::operation::Range &op) override;
+ void visit(const ir::operation::Reduce &op) override;
+ void visit(const ir::operation::Reshape &op) override;
+ void visit(const ir::operation::ResizeBilinear &op) override;
+ void visit(const ir::operation::Reverse &op) override;
+ void visit(const ir::operation::Select &op) override;
+ void visit(const ir::operation::Shape &op) override;
+ void visit(const ir::operation::Slice &op) override;
+ void visit(const ir::operation::Softmax &op) override;
+ void visit(const ir::operation::SpaceToBatchND &op) override;
+ void visit(const ir::operation::Split &op) override;
+ void visit(const ir::operation::Squeeze &op) override;
+ void visit(const ir::operation::StridedSlice &op) override;
+ void visit(const ir::operation::SquaredDifference &op) override;
+ void visit(const ir::operation::Tile &op) override;
+ void visit(const ir::operation::Transpose &op) override;
+ void visit(const ir::operation::Unpack &op) override;
+ void visit(const ir::operation::While &op) override;
+
+private:
+ /**
+ * @brief Performs shape inference for arithmetic operation
+ */
+ void handleBinaryArithmeticOp(const ir::Operation &op, const ir::OperandIndex lhs_idx,
+ const ir::OperandIndex rhs_idx);
+
+ /**
+ * @brief Performs shape inference for unary op whose output shape is
+ * always same with input shape
+ */
+ void handleSimpleUnaryOp(const ir::Operation &op, const ir::OperandIndex input_idx);
+
+private:
+ const std::unordered_map<ir::SubgraphIndex, std::unique_ptr<compiler::LoweredGraph>>
+ &_lowered_subgs;
+ // _operands and _operations can be changed by controlflow operation
+ ir::Operands &_operands; // operands of current subgraph
+ ir::Operations &_operations; // operations of current subgraph
+ bool _return_has_dynamic_tensor;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_STATIC_SHAPE_INFERER_H__
diff --git a/runtime/onert/core/include/exec/DynamicShapeInferer.h b/runtime/onert/core/include/exec/DynamicShapeInferer.h
new file mode 100644
index 000000000..d2eb83159
--- /dev/null
+++ b/runtime/onert/core/include/exec/DynamicShapeInferer.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_DYNAMIC_SHAPE_INFERER_H__
+#define __ONERT_EXEC_DYNAMIC_SHAPE_INFERER_H__
+
+#include "ir/Operands.h"
+#include "ir/OperationVisitor.h"
+#include "ir/Index.h"
+#include "backend/IDynamicTensorManager.h"
+#include "backend/ITensorManager.h"
+#include "backend/ITensorRegistry.h"
+
+#include <map>
+
+namespace onert
+{
+namespace exec
+{
+
+/**
+ * @brief Class to infer shape of output tensor at execution time and
+ * allocate memory fo output tensor if needed
+ */
+class DynamicShapeInferer : public ir::OperationVisitor
+{
+public:
+ DynamicShapeInferer(const ir::Operands &operands,
+ const std::shared_ptr<backend::ITensorRegistry> &tensor_registry)
+ : _operands(operands), _tensor_registry(tensor_registry)
+ {
+ UNUSED_RELEASE(_operands);
+ UNUSED_RELEASE(_tensor_registry);
+ }
+
+public:
+ // TODO Define visitors for operations. List them in alphabetic order.
+ // Remove TODO when any op starting from the alphabet is added
+ void visit(const ir::operation::ArgMax &op) override;
+ void visit(const ir::operation::BatchMatMul &op) override;
+ void visit(const ir::operation::BCQFullyConnected &op) override;
+ void visit(const ir::operation::BCQGather &op) override;
+ void visit(const ir::operation::BinaryArithmetic &op) override;
+ void visit(const ir::operation::BroadcastTo &op) override;
+ void visit(const ir::operation::Comparison &op) override;
+ void visit(const ir::operation::Concat &op) override;
+ void visit(const ir::operation::Conv2D &op) override;
+ void visit(const ir::operation::ElementwiseActivation &op) override;
+ void visit(const ir::operation::ElementwiseBinary &op) override;
+ void visit(const ir::operation::ElementwiseUnary &op) override;
+ void visit(const ir::operation::ExpandDims &op) override;
+ void visit(const ir::operation::Fill &op) override;
+ void visit(const ir::operation::FullyConnected &op) override;
+ void visit(const ir::operation::FusedBatchNorm &op) override;
+ void visit(const ir::operation::Gather &op) override;
+ void visit(const ir::operation::L2Normalization &op) override;
+ void visit(const ir::operation::LSTM &op) override;
+ void visit(const ir::operation::MatrixBandPart &op) override;
+ void visit(const ir::operation::OneHot &op) override;
+ void visit(const ir::operation::Pack &op) override;
+ void visit(const ir::operation::Pad &op) override;
+ void visit(const ir::operation::Permute &op) override;
+ void visit(const ir::operation::Pow &op) override;
+ // TODO write op starting from Q
+ void visit(const ir::operation::Range &op) override;
+ void visit(const ir::operation::Reduce &op) override;
+ void visit(const ir::operation::Reshape &op) override;
+ void visit(const ir::operation::ResizeBilinear &op) override;
+ void visit(const ir::operation::Reverse &op) override;
+ void visit(const ir::operation::Select &op) override;
+ void visit(const ir::operation::Shape &op) override;
+ void visit(const ir::operation::Slice &op) override;
+ void visit(const ir::operation::Softmax &op) override;
+ void visit(const ir::operation::SpaceToBatchND &op) override;
+ void visit(const ir::operation::Split &op) override;
+ void visit(const ir::operation::Squeeze &op) override;
+ void visit(const ir::operation::StridedSlice &op) override;
+ void visit(const ir::operation::SquaredDifference &op) override;
+ void visit(const ir::operation::Tile &op) override;
+ void visit(const ir::operation::Transpose &op) override;
+ void visit(const ir::operation::Unpack &op) override;
+ // TODO write op starting from V
+
+private:
+ /**
+ * @brief Performs shape inference and memory allocation for arithmetic operation
+ */
+ void handleBinaryArithmeticOp(const ir::Operation &op, const ir::OperandIndex lhs_idx,
+ const ir::OperandIndex rhs_idx);
+ /**
+ * @brief Performs shape inference and memory allocation for unary op whose output shape is
+ * always same with input shape
+ */
+ void handleSimpleUnaryOp(const ir::Operation &op, const ir::OperandIndex input_idx);
+
+private:
+ /**
+ * @brief To get operand-level info, e.g., ir::Operand::isConstant()
+ */
+ const ir::Operands &_operands;
+ /**
+ * @brief To get tensor object and access tensor-level info, e.g., ITensor::buffer()
+ */
+ std::shared_ptr<backend::ITensorRegistry> _tensor_registry;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_DYNAMIC_SHAPE_INFERER_H__
diff --git a/runtime/onert/core/include/exec/Execution.h b/runtime/onert/core/include/exec/Execution.h
new file mode 100644
index 000000000..d3c5b6dda
--- /dev/null
+++ b/runtime/onert/core/include/exec/Execution.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Execution.h
+ * @brief This file defines execution
+ */
+#ifndef __ONERT_EXEC_EXECUTION_H__
+#define __ONERT_EXEC_EXECUTION_H__
+
+#include "ir/Layout.h"
+#include "exec/IExecutor.h"
+#include "IODescription.h"
+
+#include <thread>
+
+namespace onert
+{
+namespace exec
+{
+
+/**
+ * @brief Class to define execution instance to collect input/output information for inference
+ * and prepare executor run (TODO)
+ */
+class Execution
+{
+
+public:
+ /**
+ * @brief Construct a new Execution object
+ * @param[in] executor Model executor
+ */
+ Execution(const std::shared_ptr<ExecutorMap> &executors);
+
+public:
+ /**
+ * @brief Returns primary graph object
+ * @return Graph object
+ */
+ const ir::Graph &primary_subgraph() const { return primary_executor()->graph(); }
+
+ /**
+ * @brief Change input shape
+ * @param[in] index Input index
+ * @param[in] new_shape shape to change
+ */
+ void changeInputShape(const ir::IOIndex &index, const ir::Shape &new_shape);
+
+ /**
+ * @brief Set input data's information
+ * @param[in] index Input index
+ * @param[in] buffer Input data's buffer pointer
+ * @param[in] length Input data's length
+ * @param[in] layout Input data's data format
+ */
+ void setInput(const ir::IOIndex &index, const void *buffer, size_t length,
+ ir::Layout layout = ir::Layout::NHWC);
+ /**
+ * @brief Set input data's information, especially to specify unknown dimensions on model
+ * build time.
+ * @param[in] index Input index
+ * @param[in] type Input data's type info
+ * @param[in] shape Input data's shape
+ * @param[in] buffer Input data's buffer pointer
+ * @param[in] length Input data's length
+ * @param[in] layout Input data's data format
+ */
+ void setInput(const ir::IOIndex &index, const ir::TypeInfo &type, const ir::Shape &shape,
+ const void *buffer, size_t length, ir::Layout layout = ir::Layout::NHWC);
+ /**
+ * @brief Set output data's information
+ * @param[in] index Output index
+ * @param[in] buffer Output data's buffer pointer
+ * @param[in] length Output data's length
+ * @param[in] layout Output data's data format
+ */
+ void setOutput(const ir::IOIndex &index, void *buffer, size_t length,
+ ir::Layout layout = ir::Layout::NHWC);
+ /**
+ * @brief Set output data's information, especially to specify unknown dimensions on model
+ * build time.
+ * @param[in] index Output index
+ * @param[in] type Output data's type info
+ * @param[in] shape Output data's shape
+ * @param[in] buffer Output data's buffer pointer
+ * @param[in] length Output data's length
+ * @param[in] layout Output data's data format
+ */
+ void setOutput(const ir::IOIndex &index, const ir::TypeInfo &type, const ir::Shape &shape,
+ void *buffer, size_t length, ir::Layout layout = ir::Layout::NHWC);
+ /**
+ * @brief Set input data's data format
+ * @param[in] index Input index
+ * @param[in] layout Input data's data format
+ */
+ void setInputLayout(const ir::IOIndex &index, ir::Layout layout);
+ /**
+ * @brief Set output data's data format
+ * @param[in] index Output index
+ * @param[in] layout Output data's data format
+ */
+ void setOutputLayout(const ir::IOIndex &index, ir::Layout layout);
+ /**
+ * @brief Execution
+ * @note It should be called after setting input and output buffer
+ */
+ void execute();
+
+ /**
+ * @brief Start asynchronous execution
+ * @note It returns after execution thread is started
+ * It should be called after setting input and output buffer
+ */
+ void startExecute(void);
+
+ /**
+ * @brief Return when execution is finished
+ * @note It waits until execution is finished
+ */
+ void waitFinish(void);
+
+ /**
+ * @brief Check execution is finished
+ * @return @c true if execution is finished, otherwise @c false
+ */
+ bool isFinished(void) const;
+
+ ir::Shape getInputShape(ir::IOIndex ind) const;
+ ir::Shape getOutputShape(ir::IOIndex ind) const;
+
+private:
+ const std::unique_ptr<IExecutor> &primary_executor() const
+ {
+ return _executors->at(ir::SubgraphIndex{0});
+ };
+ std::unique_ptr<IExecutor> &primary_executor() { return _executors->at(ir::SubgraphIndex{0}); };
+
+private:
+ const std::shared_ptr<ExecutorMap> _executors;
+ IODescription _io_desc;
+ std::unique_ptr<std::thread> _exec_thread;
+ bool finished{false};
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_EXECUTION_H__
diff --git a/runtime/onert/core/include/exec/FunctionSequence.h b/runtime/onert/core/include/exec/FunctionSequence.h
new file mode 100644
index 000000000..6ec6e60ad
--- /dev/null
+++ b/runtime/onert/core/include/exec/FunctionSequence.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_FUNCTION_SEQUENCE_H__
+#define __ONERT_EXEC_FUNCTION_SEQUENCE_H__
+
+#include <memory>
+#include <cassert>
+#include <vector>
+#include <functional>
+
+#include "exec/IFunction.h"
+#include "exec/DynamicShapeInferer.h"
+#include "ir/Operations.h"
+#include "backend/ITensorRegistry.h"
+#include "backend/IDynamicTensorManager.h"
+
+namespace onert
+{
+namespace exec
+{
+
+class FunctionSequence : public IFunction
+{
+public:
+ template <typename... Args> FunctionSequence(Args &&... args) { initialize(std::move(args)...); }
+
+private:
+ void initialize()
+ {
+ // Template base case : do nothing
+ }
+
+ template <typename T, typename... Args> void initialize(std::unique_ptr<T> &&fn, Args &&... args)
+ {
+ _functions.emplace_back(std::move(fn));
+ initialize(std::move(args)...);
+ }
+
+public:
+ virtual ~FunctionSequence() = default;
+
+ void run() override;
+ void prepare() override;
+
+ /**
+ * @brief Appends an IFunction object to the function sequence
+ *
+ * @param function IFunction object to be appended
+ */
+ void append(std::unique_ptr<IFunction> &&function);
+
+ void iterate(const std::function<void(IFunction &)> &fn);
+
+ template <typename T, typename... Args> void wrap(Args &&... args)
+ {
+ for (auto &function : _functions)
+ {
+ function = std::make_unique<T>(std::move(function), args...);
+ }
+ }
+
+public: // methods related to dynamic tensor
+ struct DynamicTensorCtx
+ {
+ const ir::OpSequence *op_seq = nullptr;
+ const ir::Operations *operations = nullptr;
+ std::shared_ptr<exec::DynamicShapeInferer> dynamic_shape_inferer = nullptr;
+ backend::IDynamicTensorManager *dynamic_tensor_manager = nullptr;
+ };
+
+ /**
+ * @brief Prepare to run FunctionSequence which "might" handle dynamic tensor
+ * @note Calling this does not mean that run() will handle dynamic tensor.
+ * enableDynamicShapeInferer(true) will make run() will handle dynamic tensor.
+ */
+ void dynamic_tensor_ctx(std::shared_ptr<DynamicTensorCtx> &dynamic_tensor_ctx)
+ {
+ _dynamic_tensor_ctx = dynamic_tensor_ctx;
+ }
+
+ std::shared_ptr<DynamicTensorCtx> &dynamic_tensor_ctx() { return _dynamic_tensor_ctx; }
+
+ /**
+ * @brief Call this function by passing @c true if this FunctionSequence handles dynamic tensors
+ * and should run DynamicShapeInferer. This function can be called multiple times and
+ * if @c false is passed during multiple calls, DynamicShapeInfere will not be run.
+ * @note This must be called before run(). If not called, run() assumes that all tensors are
+ * dynamic and DynamicShapeInferer will be run.
+ */
+ void enableDynamicShapeInferer(bool enable)
+ {
+ _enable_dynamic_shape_inferer = _enable_dynamic_shape_inferer || enable;
+ }
+
+ /**
+ * @brief Call this function to initialize vars before running
+ * @note When we run a model with static tensor input and then run with dynamic tensor input,
+ * _enable_dynamic_shape_inferer is set to @c false at first run.
+ * Once _enable_dynamic_shape_inferer is set to @c true it cannot be changed to @c false
+ * only with calling enableDynamicShapeInferer(). So initializing it to @c false is
+ * necessary.
+ * @todo This is a quick fix. Adding this will increase time for run(). Find way to optimize.
+ */
+ void initRunning() { _enable_dynamic_shape_inferer = false; }
+
+protected:
+ std::vector<std::unique_ptr<IFunction>> _functions;
+
+protected:
+ bool _enable_dynamic_shape_inferer = false;
+
+ std::shared_ptr<DynamicTensorCtx> _dynamic_tensor_ctx = nullptr;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_FUNCTION_SEQUENCE_H__
diff --git a/runtime/onert/core/include/exec/IExecutor.h b/runtime/onert/core/include/exec/IExecutor.h
new file mode 100644
index 000000000..1d2831dd0
--- /dev/null
+++ b/runtime/onert/core/include/exec/IExecutor.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IExecutor.h
+ * @brief This file defines interface of Executor
+ */
+#ifndef __ONERT_EXEC_I_EXECUTOR_H_
+#define __ONERT_EXEC_I_EXECUTOR_H_
+
+#include "ir/Graph.h"
+#include "IFunction.h"
+#include "IODescription.h"
+#include "ir/OperationIndexMap.h"
+#include "backend/IDynamicTensorManager.h"
+
+namespace onert
+{
+namespace exec
+{
+class IExecutionObserver;
+/**
+ * @brief Struct to define interface of Executor
+ */
+struct IExecutor
+{
+ /**
+ * @brief Construct a new IExecutor object
+ */
+ IExecutor() = default;
+ /**
+ * @brief Destroy the IExecutor object
+ */
+ virtual ~IExecutor() = default;
+
+ /**
+ * @brief Returns graph object
+ *
+ * @return Graph object
+ */
+ virtual const ir::Graph &graph() = 0;
+
+ /**
+ * @brief Set an ordering on operations
+ * @param[in] ranks The table encoding the ordering
+ */
+ virtual void setIndexedRanks(std::shared_ptr<ir::OperationIndexMap<int64_t>>) = 0;
+
+ /**
+ * @brief Start execution
+ * @param[in] desc Input and output description
+ * @note This method should be thread-safe
+ */
+ virtual void execute(const IODescription &desc) = 0;
+};
+
+using ExecutorMap = std::unordered_map<ir::SubgraphIndex, std::unique_ptr<IExecutor>>;
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_I_EXECUTOR_H_
diff --git a/runtime/onert/core/include/exec/IFunction.h b/runtime/onert/core/include/exec/IFunction.h
new file mode 100644
index 000000000..18ba2457a
--- /dev/null
+++ b/runtime/onert/core/include/exec/IFunction.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_I_FUNCTION_H__
+#define __ONERT_EXEC_I_FUNCTION_H__
+
+namespace onert
+{
+namespace exec
+{
+
+class IFunction
+{
+public:
+ virtual ~IFunction() = default;
+ virtual void run() = 0;
+ virtual void prepare() {}
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_I_FUNCTION_H__
diff --git a/runtime/onert/core/include/exec/IODescription.h b/runtime/onert/core/include/exec/IODescription.h
new file mode 100644
index 000000000..d1810ec3b
--- /dev/null
+++ b/runtime/onert/core/include/exec/IODescription.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_IO_DESCRIPTION_H__
+#define __ONERT_EXEC_IO_DESCRIPTION_H__
+
+#include <vector>
+#include <unordered_map>
+
+#include "ir/OperandInfo.h"
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace exec
+{
+
+struct InputDesc
+{
+ const ir::OperandInfo info;
+ const void *buffer;
+ const size_t size;
+ const ir::Layout layout;
+
+ InputDesc(void) = delete;
+ InputDesc(const ir::OperandInfo &info, const void *buffer, const size_t size, ir::Layout layout)
+ : info(info), buffer(buffer), size(size), layout(layout)
+ {
+ }
+};
+
+struct OutputDesc
+{
+ // not `const` because shape should be modified after execution in case when output is
+ // a dynamic tensor
+ ir::OperandInfo info;
+ void *buffer;
+ const size_t size;
+ const ir::Layout layout;
+
+ OutputDesc(void) = delete;
+ OutputDesc(const ir::OperandInfo &info, void *buffer, const size_t size, ir::Layout layout)
+ : info(info), buffer(buffer), size(size), layout(layout)
+ {
+ }
+};
+
+struct IODescription
+{
+ std::vector<std::unique_ptr<InputDesc>> inputs;
+ std::vector<std::unique_ptr<OutputDesc>> outputs;
+ // Contains shape of input set by nnfw_set_input_tensorinfo(..)
+ std::unordered_map<ir::IOIndex, ir::Shape> dynamic_input_shapes;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_IO_DESCRIPTION_H__
diff --git a/runtime/onert/core/include/exec/NopFunction.h b/runtime/onert/core/include/exec/NopFunction.h
new file mode 100644
index 000000000..d0ed55921
--- /dev/null
+++ b/runtime/onert/core/include/exec/NopFunction.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file NopFunction.h
+ * @brief This file defines NopFunction
+ */
+#ifndef __ONERT_EXEC_NOP_FUNCTION_H_
+#define __ONERT_EXEC_NOP_FUNCTION_H_
+
+#include "IFunction.h"
+
+namespace onert
+{
+namespace exec
+{
+
+/**
+ * @brief A derivative of IFunction tha does nothing
+ *
+ */
+class NopFunction : public IFunction
+{
+public:
+ NopFunction() = default;
+ void run() override
+ {
+ // DO NOTHING
+ }
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_NOP_FUNCTION_H_
diff --git a/runtime/onert/core/include/ir/Coordinates.h b/runtime/onert/core/include/ir/Coordinates.h
new file mode 100644
index 000000000..9963cab4c
--- /dev/null
+++ b/runtime/onert/core/include/ir/Coordinates.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_COORDINATES_H__
+#define __ONERT_IR_COORDINATES_H__
+
+#include <cassert>
+#include <stdint.h>
+#include <vector>
+
+#include "Layout.h"
+
+namespace onert
+{
+namespace ir
+{
+
+/**
+ * @brief Class to represent position(offset) of tensor.\n
+ * Assume that the front is higher dimensional.
+ * i.g. N: 0, C: 1, H: 2, W: 3 for NCHW layout
+ */
+class Coordinates final
+{
+public:
+ static constexpr size_t num_max_dimensions = 4;
+
+public:
+ /**
+ * @brief Construct a new Coordinates object with zero dimension
+ * @return N/A
+ */
+ Coordinates() = default;
+ /**
+ * @brief Construct a new Coordinates object
+ * @param[in] init The initialzer_list with coordinates
+ * @return
+ */
+ Coordinates(std::initializer_list<int32_t> init) : _coordinates{init}
+ {
+ assert(init.size() <= num_max_dimensions);
+ }
+ /**
+ * @brief Construct a new Coordinates object
+ * @param[in] init The initialzer_list with coordinates
+ * @return
+ */
+ Coordinates(std::initializer_list<uint32_t> init) : _coordinates{init.begin(), init.end()}
+ {
+ assert(init.size() <= num_max_dimensions);
+ }
+ /**
+ * @brief Construct a new Coordinates object with rank
+ * @param[in] rank The rank of coordinates
+ * @return
+ */
+ explicit Coordinates(int rank) : _coordinates(rank, 0) {}
+
+public:
+ /**
+ * @brief Set the coordinate of one of the coordinates.
+ *
+ * @param[in] dimension Dimension for which the coordinate is set.
+ * @param[in] Coordinate Coordinate to be set for the dimension.
+ */
+ void set(size_t dimension, int32_t coordinate)
+ {
+ assert(dimension < num_max_dimensions);
+ if (dimension >= _coordinates.size())
+ {
+ _coordinates.resize(dimension + 1, 0);
+ }
+ _coordinates[dimension] = coordinate;
+ }
+
+public:
+ /**
+ * @brief Return size of coordinates
+ *
+ * @return size of coordinates
+ */
+ size_t size() const { return _coordinates.size(); }
+
+public:
+ int32_t operator[](size_t dimension) const
+ {
+ assert(dimension < _coordinates.size());
+ return _coordinates[dimension];
+ }
+
+public:
+ /**
+ * @brief begin() of const_iterator for this class
+ *
+ * @return The first iterator of the coordinates
+ */
+ std::vector<int32_t>::const_iterator begin() const { return _coordinates.begin(); }
+ /**
+ * @brief end() of const_iterator for this class
+ *
+ * @return The last iterator of the coordinates
+ */
+ std::vector<int32_t>::const_iterator end() const { return _coordinates.end(); }
+
+private:
+ std::vector<int32_t> _coordinates;
+};
+
+Coordinates convertCoordinates(const Coordinates &from_coordinates, Layout from_layout,
+ Layout to_layout);
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_COORDINATES_H__
diff --git a/runtime/onert/core/include/ir/Data.h b/runtime/onert/core/include/ir/Data.h
new file mode 100644
index 000000000..d31191b4f
--- /dev/null
+++ b/runtime/onert/core/include/ir/Data.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_DATA_H__
+#define __ONERT_IR_DATA_H__
+
+#include <algorithm>
+#include <sys/mman.h>
+
+namespace onert
+{
+namespace ir
+{
+
+struct Data
+{
+ virtual ~Data() = default;
+
+ virtual size_t size(void) const = 0;
+ virtual const uint8_t *base(void) const = 0;
+};
+
+class CachedData final : public Data
+{
+public:
+ CachedData(const uint8_t *base, size_t size) : _base{new uint8_t[size]}, _size{size}
+ {
+ std::copy(base, base + size, _base);
+ }
+
+public:
+ ~CachedData() { delete[] _base; }
+
+public:
+ size_t size(void) const override { return _size; }
+ const uint8_t *base(void) const override { return _base; }
+
+private:
+ uint8_t *_base;
+ size_t _size;
+};
+
+class ExternalData : public Data
+{
+public:
+ ExternalData(const uint8_t *base, size_t size) : _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ size_t size(void) const override { return _size; }
+ const uint8_t *base(void) const override { return _base; }
+
+private:
+ const uint8_t *_base;
+ const size_t _size;
+};
+
+class MMapedData final : public ExternalData
+{
+public:
+ MMapedData(int fd, const std::ptrdiff_t mmap_offset, const size_t mmap_size,
+ const std::ptrdiff_t data_offset, const size_t data_size)
+ : ExternalData(nullptr, data_size),
+ _mmap_base(
+ static_cast<uint8_t *>(mmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, mmap_offset))),
+ _mmap_size(mmap_size), _offset(data_offset - mmap_offset)
+ {
+ // DO NOTHING
+ }
+
+public:
+ ~MMapedData()
+ {
+ if (_mmap_size > 0)
+ {
+ munmap(const_cast<uint8_t *>(_mmap_base), _mmap_size);
+ }
+ }
+
+public:
+ const uint8_t *base(void) const override { return _mmap_base + _offset; }
+
+private:
+ const uint8_t *_mmap_base;
+ size_t _mmap_size;
+ std::ptrdiff_t _offset;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_DATA_H__
diff --git a/runtime/onert/core/include/ir/DataType.h b/runtime/onert/core/include/ir/DataType.h
new file mode 100644
index 000000000..9f09de3fb
--- /dev/null
+++ b/runtime/onert/core/include/ir/DataType.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_DATATYPE_H__
+#define __ONERT_IR_DATATYPE_H__
+
+#include <cstdlib>
+
+namespace onert
+{
+namespace ir
+{
+
+enum class DataType
+{
+ FLOAT32 = 0,
+ INT32 = 1,
+ UINT32 = 2,
+ QUANT_UINT8_ASYMM = 3,
+ BOOL8 = 4,
+ UINT8 = 5,
+ QUANT_INT8_SYMM = 6,
+ FLOAT16 = 7,
+ INT64 = 8,
+ QUANT_INT8_ASYMM = 9,
+ QUANT_INT16_ASYMM = 10,
+};
+
+size_t sizeOfDataType(DataType data_type);
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_DATATYPE_H__
diff --git a/runtime/onert/core/include/ir/Graph.h b/runtime/onert/core/include/ir/Graph.h
new file mode 100644
index 000000000..2103e6e64
--- /dev/null
+++ b/runtime/onert/core/include/ir/Graph.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_GRAPH_H__
+#define __ONERT_IR_GRAPH_H__
+
+#include <functional>
+#include <unordered_map>
+
+#include "ir/Operands.h"
+#include "ir/Operations.h"
+#include "ir/OpSequence.h"
+#include "ir/OpSequences.h"
+#include "ir/Subgraphs.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace custom
+{
+class IKernelBuilder;
+} // namespace custom
+} // namespace backend
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+
+class Graph
+{
+private:
+ enum class Phase
+ {
+ BUILDING,
+ MODEL
+ };
+
+public:
+ Graph(void);
+ ~Graph(void);
+
+ // Graph Building
+public:
+ OperandIndex addOperand(const Shape &shape, const TypeInfo &type);
+ OperationIndex addOperation(std::unique_ptr<Operation> &&node);
+ void setOperandValue(const OperandIndex &ind, std::shared_ptr<Data> data);
+ void addInput(const OperandIndex &ind, const std::string &name = "");
+ void addOutput(const OperandIndex &ind, const std::string &name = "");
+ void finishBuilding(void);
+ void removeOperand(const OperandIndex &ind) { _operands.remove(ind); }
+ bool isBuildingPhase(void) const { return _phase == Phase::BUILDING; }
+ void setLayout(Layout layout) { _layout = layout; }
+ void setSubgraphs(const std::shared_ptr<Subgraphs> &subgs) { _subgraphs = subgs; }
+
+private:
+ void initializeUseDef();
+ void sweepGarbageOperands();
+
+ // Custom operations support
+public:
+ void
+ bindKernelBuilder(const std::shared_ptr<onert::backend::custom::IKernelBuilder> &kernel_builder)
+ {
+ _kernel_builder = kernel_builder;
+ }
+
+ const std::shared_ptr<backend::custom::IKernelBuilder> &getKernelBuilder() const
+ {
+ return _kernel_builder;
+ }
+
+private:
+ std::shared_ptr<backend::custom::IKernelBuilder> _kernel_builder;
+
+ // Accessors
+public:
+ const OperandIndexSequence &getInputs() const { return _inputs; }
+ OperandIndexSequence &getInputs() { return _inputs; }
+ const OperandIndexSequence &getOutputs() const { return _outputs; }
+ OperandIndexSequence &getOutputs() { return _outputs; }
+ IOIndex getInputIndex(const std::string &name) const;
+ IOIndex getOutputIndex(const std::string &name) const;
+ const Operands &operands() const { return _operands; }
+ Operands &operands() { return _operands; } // TODO Remove this non-const accessor
+ const Operations &operations() const { return _operations; }
+ Operations &operations() { return _operations; }
+ const std::shared_ptr<Subgraphs> &subgraphs() const { return _subgraphs; }
+ std::shared_ptr<Subgraphs> &subgraphs() { return _subgraphs; }
+ Layout layout() const { return _layout; }
+
+private:
+ Phase _phase{Phase::BUILDING};
+ Operations _operations;
+ Operands _operands;
+ OperandIndexSequence _inputs;
+ OperandIndexSequence _outputs;
+ std::unordered_map<std::string, IOIndex> _name_to_input;
+ std::unordered_map<std::string, IOIndex> _name_to_output;
+ // Child subgraphs
+ std::shared_ptr<Subgraphs> _subgraphs;
+ // TFLite and circle's default layout is NHWC;
+ Layout _layout{Layout::NHWC};
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_GRAPH_H__
diff --git a/runtime/onert/core/include/ir/Index.h b/runtime/onert/core/include/ir/Index.h
new file mode 100644
index 000000000..2538301a4
--- /dev/null
+++ b/runtime/onert/core/include/ir/Index.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_INDEX_H__
+#define __ONERT_IR_INDEX_H__
+
+#include "util/Index.h"
+
+namespace onert
+{
+namespace ir
+{
+
+struct OperationIndexTag;
+using OperationIndex = ::onert::util::Index<uint32_t, OperationIndexTag>;
+
+struct OperandIndexTag;
+using OperandIndex = ::onert::util::Index<uint32_t, OperandIndexTag>;
+
+struct IOIndexTag;
+using IOIndex = ::onert::util::Index<uint32_t, IOIndexTag>;
+
+struct OpSequenceIndexTag;
+using OpSequenceIndex = ::onert::util::Index<uint32_t, OpSequenceIndexTag>;
+
+struct SubgraphIndexTag;
+using SubgraphIndex = ::onert::util::Index<uint32_t, SubgraphIndexTag>;
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_INDEX_H__
diff --git a/runtime/onert/core/include/ir/InternalType.h b/runtime/onert/core/include/ir/InternalType.h
new file mode 100644
index 000000000..50292e812
--- /dev/null
+++ b/runtime/onert/core/include/ir/InternalType.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_INTERNAL_TYPE_H__
+#define __ONERT_IR_INTERNAL_TYPE_H__
+
+#include <cstdint>
+
+namespace onert
+{
+namespace ir
+{
+
+enum class Activation
+{
+ NONE = 0,
+ RELU = 1,
+ RELU1 = 2,
+ RELU6 = 3,
+ TANH = 4,
+ SIGMOID = 5
+};
+
+struct Stride
+{
+ uint32_t vertical;
+ uint32_t horizontal;
+};
+
+struct Dilation
+{
+ uint32_t width_factor;
+ uint32_t height_factor;
+};
+
+enum class FullyConnectedWeightsFormat
+{
+ Default = 0,
+ Shuffled4x16Int8 = 1,
+ Shuffled16x1Float32 = 127
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_INTERNAL_TYPE_H__
diff --git a/runtime/onert/core/include/ir/Layout.h b/runtime/onert/core/include/ir/Layout.h
new file mode 100644
index 000000000..082810172
--- /dev/null
+++ b/runtime/onert/core/include/ir/Layout.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_LAYOUT_H__
+#define __ONERT_IR_LAYOUT_H__
+
+#include <functional>
+#include <string>
+
+namespace onert
+{
+namespace ir
+{
+
+enum class Layout
+{
+ UNKNOWN = 0,
+ NHWC,
+ NCHW
+};
+
+inline std::string to_string(Layout layout)
+{
+ switch (layout)
+ {
+ case Layout::NHWC:
+ return std::string{"NHWC"};
+ case Layout::NCHW:
+ return std::string{"NCHW"};
+ case Layout::UNKNOWN:
+ return std::string{"UNKNOWN"};
+ default:
+ throw std::runtime_error("WRONG LAYOUT");
+ }
+}
+
+} // namespace ir
+} // namespace onert
+
+namespace std
+{
+
+template <> struct hash<onert::ir::Layout>
+{
+ size_t operator()(onert::ir::Layout value) const noexcept
+ {
+ using type = typename std::underlying_type<onert::ir::Layout>::type;
+ return hash<type>()(static_cast<type>(value));
+ }
+};
+
+} // namespace std
+
+#endif // __ONERT_IR_LAYOUT_H__
diff --git a/runtime/onert/core/include/ir/LowerInfoMap.h b/runtime/onert/core/include/ir/LowerInfoMap.h
new file mode 100644
index 000000000..fbabaf39d
--- /dev/null
+++ b/runtime/onert/core/include/ir/LowerInfoMap.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_LOWER_INFO_MAP_H__
+#define __ONERT_IR_LOWER_INFO_MAP_H__
+
+#include <memory>
+#include <unordered_map>
+
+#include "ir/operand/LowerInfo.h"
+#include "ir/operation/LowerInfo.h"
+#include "ir/OperandIndexMap.h"
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace ir
+{
+
+struct LowerInfoMap
+{
+ std::unordered_map<OpSequenceIndex, std::unique_ptr<operation::LowerInfo>> op_seq;
+ OperandIndexMap<std::unique_ptr<operand::LowerInfo>> operand;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_LOWER_INFO_MAP_H__
diff --git a/runtime/onert/core/include/ir/OpCode.h b/runtime/onert/core/include/ir/OpCode.h
new file mode 100644
index 000000000..32e47796e
--- /dev/null
+++ b/runtime/onert/core/include/ir/OpCode.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OP_CODE_H__
+#define __ONERT_IR_OP_CODE_H__
+
+#include <functional>
+#include <stdint.h>
+#include <string>
+
+namespace onert
+{
+namespace ir
+{
+
+enum class OpCode
+{
+ Invalid, //< Unused
+#define OP(Name) Name, //< All operations
+#include "ir/Operations.lst"
+#undef OP
+ COUNT
+};
+
+const char *toString(OpCode opcode);
+OpCode toOpCode(const std::string str);
+
+} // namespace ir
+} // namespace onert
+
+namespace std
+{
+
+template <> struct hash<onert::ir::OpCode>
+{
+ size_t operator()(onert::ir::OpCode value) const noexcept
+ {
+ using type = typename std::underlying_type<onert::ir::OpCode>::type;
+ return hash<type>()(static_cast<type>(value));
+ }
+};
+
+} // namespace std
+
+#endif // __ONERT_IR_OP_CODE_H__
diff --git a/runtime/onert/core/include/ir/OpSequence.h b/runtime/onert/core/include/ir/OpSequence.h
new file mode 100644
index 000000000..754cf3b34
--- /dev/null
+++ b/runtime/onert/core/include/ir/OpSequence.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OP_SEQUENCE_H__
+#define __ONERT_IR_OP_SEQUENCE_H__
+
+#include <vector>
+#include <string>
+#include <memory>
+
+#include "ir/Layout.h"
+#include "ir/Index.h"
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class Operations;
+
+class OpSequence
+{
+public:
+ explicit OpSequence(Layout layout);
+ OpSequence(const OpSequence &) = delete;
+
+public:
+ void accept(OperationVisitor &v) const;
+
+public:
+ const OperandIndexSequence &getInputs() const { return _inputs; }
+ const OperandIndexSequence &getOutputs() const { return _outputs; }
+ void setInputs(const OperandIndexSequence &indexes) { _inputs = indexes; }
+ void setOutputs(const OperandIndexSequence &indexes) { _outputs = indexes; }
+ void replaceInputs(const OperandIndex &from, const OperandIndex &to)
+ {
+ _inputs.replace(from, to);
+ }
+ void replaceOutputs(const OperandIndex &from, const OperandIndex &to)
+ {
+ _outputs.replace(from, to);
+ }
+
+ void appendOperation(const OperationIndex &index) { _operations.emplace_back(index); }
+
+ std::vector<OperationIndex> &operations(void) { return _operations; }
+
+ const std::vector<OperationIndex> &operations(void) const { return _operations; }
+
+ uint32_t size(void) const { return _operations.size(); }
+
+public:
+ void remove(const OperationIndex &index);
+
+ bool exist(const OperationIndex &index) const;
+
+public:
+ Layout getLayout() const { return _layout; }
+
+public:
+ std::vector<OperationIndex>::const_iterator begin() const { return _operations.begin(); }
+ std::vector<OperationIndex>::const_iterator end() const { return _operations.end(); }
+
+public:
+ /**
+ * @brief Set @c true if any operation in this opSequence has dynamic input
+ * or dynamic output;
+ * @c false if all operations' inputs and outputs are static tensors
+ */
+ void has_dynamic_tensor(bool has_dynamic_tensor) { _has_dynamic_tensor = has_dynamic_tensor; }
+ bool has_dynamic_tensor() const { return _has_dynamic_tensor; }
+
+private:
+ OperandIndexSequence _inputs;
+ OperandIndexSequence _outputs;
+ std::vector<OperationIndex> _operations;
+
+private:
+ Layout _layout;
+ bool _has_dynamic_tensor;
+};
+
+std::string getStrFromOpSeq(const OpSequence &op_seq, const Operations &operations);
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OP_SEQUENCE_H__
diff --git a/runtime/onert/core/include/ir/OpSequences.h b/runtime/onert/core/include/ir/OpSequences.h
new file mode 100644
index 000000000..ab258f395
--- /dev/null
+++ b/runtime/onert/core/include/ir/OpSequences.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OP_SEQUENCES_H__
+#define __ONERT_IR_OP_SEQUENCES_H__
+
+#include "ir/Index.h"
+#include "ir/OpSequence.h"
+#include "util/ObjectManager.h"
+
+namespace onert
+{
+namespace ir
+{
+
+/**
+ * @brief Class that manages OpSequence objects
+ */
+class OpSequences : public util::ObjectManager<OpSequenceIndex, OpSequence>
+{
+public:
+ /**
+ * @brief Create an instance of OpSequence with given op and push it to objects
+ *
+ * @param[in] op_idx Operation index that is emplaced
+ * @param[in] layout OpSequence's layout
+ * @return OpSequenceIndex
+ */
+ OpSequenceIndex emplace(const OperationIndex &op_index, Layout layout);
+
+ /**
+ * @brief Push an instance of OpSequence to objects
+ *
+ * @param[in] op_seq An instance of OpSequence
+ * @return OpSequenceIndex
+ */
+ OpSequenceIndex emplace(std::unique_ptr<OpSequence> &&op_seq);
+ /**
+ * @brief Check if an operation does exist in any OpSequences
+ *
+ * @param operation_index Operation index to find
+ * @return true If such operation exists in any OpSequences otherwise false
+ */
+ bool containsOperation(const OperationIndex &operation_index) const;
+ /**
+ * @brief Find an operation from all OpSequences
+ *
+ * @param operation_index Operation index to find
+ * @return OpSequenceIndex Index of OpSequence that contains given operation index
+ */
+ OpSequenceIndex getOperation(const OperationIndex &operation_index) const;
+ /**
+ * @brief Remove an operation from OpSequence
+ *
+ * @param operation_index Operation index to be removed
+ */
+ void removeFromOpSequence(const OperationIndex &operation_index);
+
+private:
+ void cacheSequenceIndex(const OpSequenceIndex &seq_index, const OperationIndex &op_index) const;
+ OpSequenceIndex *findSequenceIndex(const OperationIndex &operation_index) const;
+
+ OpSequenceIndex findOperation(const OperationIndex &operation_index) const;
+ mutable std::unordered_map<OperationIndex, OpSequenceIndex> _seq_indexes;
+};
+
+/**
+ * @brief Dump OpSequences
+ *
+ * @param op_seqs Operation Sequences
+ * @param operations Operation context
+ */
+void dumpOpSequences(const OpSequences &op_seqs, const Operations &operations);
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OP_SEQUENCES_H__
diff --git a/runtime/onert/core/include/ir/Operand.h b/runtime/onert/core/include/ir/Operand.h
new file mode 100644
index 000000000..f149a744b
--- /dev/null
+++ b/runtime/onert/core/include/ir/Operand.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERAND_H__
+#define __ONERT_IR_OPERAND_H__
+
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <algorithm>
+
+#include "ir/Data.h"
+#include "ir/DataType.h"
+#include "ir/OperandInfo.h"
+#include "ir/OperationIndexSet.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class Operand
+{
+public:
+ explicit Operand(const Shape &shape, const TypeInfo &type)
+ : _info{shape, type, MemAllocType::STATIC}
+ {
+ // DO NOTHING
+ }
+ explicit Operand(const Operand &) = default;
+
+public:
+ const Shape &shape(void) const { return _info.shape(); }
+ const TypeInfo &typeInfo(void) const { return _info.typeInfo(); }
+ const OperandInfo &info(void) const { return _info; }
+ OperandInfo &info(void) { return _info; }
+ size_t operandSize(void) const;
+
+ const OperationIndexSet &getUses() const { return _uses; }
+ OperationIndex getDef() const { return _def; }
+ void insertUse(const OperationIndex &idx);
+ void removeUse(const OperationIndex &idx);
+ void setDef(const OperationIndex &idx);
+ void unsetDef();
+
+public:
+ void type(const DataType type) { _info.type(type); };
+
+public:
+ void data(std::shared_ptr<Data> &&data)
+ {
+ _data = std::move(data);
+ _info.setAsConstant();
+ }
+ const Data *data(void) const { return _data.get(); }
+
+ void releaseData(void) { _data.reset(); }
+
+ std::shared_ptr<Data> shareData(void) const { return _data; }
+
+ /**
+ * @brief Get true if Operand is const, otherwise @c false
+ a @return @c true if Operand is const, otherwise @c false
+ */
+ bool isConstant(void) const { return _info.isConstant(); }
+
+public:
+ template <typename T, typename... Args> void data(Args &&... args)
+ {
+ data(std::make_unique<T>(std::forward<Args>(args)...));
+ }
+
+public:
+ template <typename T> T asScalar(void) const
+ {
+ assert((shape().rank() == 0) || ((shape().rank() == 1) && (shape().dim(0) == 1)));
+ assert(_data != nullptr);
+ assert((_data->base() != nullptr) && (_data->size() == sizeof(T)));
+
+ return *(reinterpret_cast<const T *>(_data->base()));
+ }
+
+ template <typename T> std::vector<T> asVector() const
+ {
+ assert(_data != nullptr);
+ assert(_data->size() % sizeof(T) == 0);
+
+ const auto *base = reinterpret_cast<const T *>(_data->base());
+ const std::size_t size = _data->size() / sizeof(T);
+ return std::vector<T>(base, base + size);
+ }
+
+private:
+ OperandInfo _info;
+ std::shared_ptr<Data> _data;
+
+ OperationIndexSet _uses;
+ OperationIndex _def;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERAND_H__
diff --git a/runtime/onert/core/include/ir/OperandConstraint.h b/runtime/onert/core/include/ir/OperandConstraint.h
new file mode 100644
index 000000000..8da922bea
--- /dev/null
+++ b/runtime/onert/core/include/ir/OperandConstraint.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_MODEL_OPERAND_CONSTRAINT_H__
+#define __ONERT_MODEL_OPERAND_CONSTRAINT_H__
+
+#include <stdint.h>
+#include <limits>
+#include <set>
+
+namespace onert
+{
+namespace ir
+{
+
+class OperandConstraint
+{
+private:
+ static const uint32_t INF = std::numeric_limits<uint32_t>::max();
+
+public:
+ static OperandConstraint createAny() { return OperandConstraint{0u, INF}; }
+ static OperandConstraint createExact(uint32_t exact) { return OperandConstraint{exact, exact}; }
+ static OperandConstraint createAtMost(uint32_t end) { return OperandConstraint{0u, end}; }
+ static OperandConstraint createAtLeast(uint32_t begin) { return OperandConstraint{begin, INF}; }
+ static OperandConstraint createInRange(uint32_t begin, uint32_t end)
+ {
+ return OperandConstraint{begin, end};
+ }
+
+private:
+ OperandConstraint(uint32_t begin, uint32_t end) : _begin{begin}, _end{end} {}
+
+public:
+ bool check(uint32_t ind) const { return _begin <= ind && ind <= _end; }
+
+private:
+ uint32_t _begin;
+ uint32_t _end;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_MODEL_OPERAND_CONSTRAINT_H__
diff --git a/runtime/onert/core/include/ir/OperandIndexMap.h b/runtime/onert/core/include/ir/OperandIndexMap.h
new file mode 100644
index 000000000..468162ffb
--- /dev/null
+++ b/runtime/onert/core/include/ir/OperandIndexMap.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERAND_INDEX_MAP_H__
+#define __ONERT_IR_OPERAND_INDEX_MAP_H__
+
+#include <unordered_map>
+
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace ir
+{
+
+template <typename T> using OperandIndexMap = std::unordered_map<OperandIndex, T>;
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERAND_INDEX_MAP_H__
diff --git a/runtime/onert/core/include/ir/OperandIndexSequence.h b/runtime/onert/core/include/ir/OperandIndexSequence.h
new file mode 100644
index 000000000..2f78cc832
--- /dev/null
+++ b/runtime/onert/core/include/ir/OperandIndexSequence.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_MODEL_OPERAND_INDEX_SEQUENCE_H__
+#define __ONERT_MODEL_OPERAND_INDEX_SEQUENCE_H__
+
+#include <initializer_list>
+#include <vector>
+
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace ir
+{
+
+enum class Remove
+{
+ DUPLICATED = 1,
+ UNDEFINED = 2
+};
+
+class OperandIndexSequence
+{
+public:
+ OperandIndexSequence(void) = default;
+ OperandIndexSequence(std::initializer_list<OperandIndex> list);
+ OperandIndexSequence(std::initializer_list<int32_t> list);
+ OperandIndexSequence(std::initializer_list<uint32_t> list);
+
+public:
+ void append(const OperandIndex &index) { _vec.emplace_back(index); }
+ void append(const OperandIndexSequence &l) { _vec.insert(_vec.end(), l.begin(), l.end()); }
+
+public:
+ uint32_t size() const { return static_cast<uint32_t>(_vec.size()); }
+ const OperandIndex &at(IOIndex set_index) const { return _vec.at(set_index.value()); }
+ const OperandIndex &at(uint32_t index) const { return _vec.at(index); }
+ bool contains(const OperandIndex &index) const;
+ void replace(const OperandIndex &from, const OperandIndex &to);
+ OperandIndexSequence operator|(ir::Remove filter) const
+ {
+ switch (filter)
+ {
+ case ir::Remove::DUPLICATED:
+ {
+ ir::OperandIndexSequence seq;
+ for (const auto &ind : _vec)
+ if (!seq.contains(ind))
+ seq.append(ind);
+ return seq;
+ }
+ case ir::Remove::UNDEFINED:
+ {
+ ir::OperandIndexSequence seq;
+ for (const auto &ind : _vec)
+ if (!ind.undefined())
+ seq.append(ind);
+ return seq;
+ }
+ }
+ return *this;
+ }
+
+public:
+ OperandIndexSequence operator+(const OperandIndexSequence &other) const;
+ friend std::ostream &operator<<(std::ostream &o, const OperandIndexSequence &op_seq);
+
+public:
+ std::vector<OperandIndex>::const_iterator begin(void) const { return _vec.begin(); }
+ std::vector<OperandIndex>::const_iterator end(void) const { return _vec.end(); }
+ std::vector<OperandIndex>::iterator begin(void) { return _vec.begin(); }
+ std::vector<OperandIndex>::iterator end(void) { return _vec.end(); }
+
+private:
+ std::vector<OperandIndex> _vec;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_MODEL_OPERAND_INDEX_SET_H__
diff --git a/runtime/onert/core/include/ir/OperandInfo.h b/runtime/onert/core/include/ir/OperandInfo.h
new file mode 100644
index 000000000..dc89f8726
--- /dev/null
+++ b/runtime/onert/core/include/ir/OperandInfo.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file OperandInfo.h
+ * @brief This file contains OperandInfo class
+ */
+#ifndef __ONERT_IR_OPERAND_INFO_H__
+#define __ONERT_IR_OPERAND_INFO_H__
+
+#include "ir/Shape.h"
+#include "ir/TypeInfo.h"
+#include "ir/Layout.h"
+
+namespace onert
+{
+namespace ir
+{
+
+/**
+ * @brief enum class indicating when the memory for a tensor is allocated
+ */
+enum class MemAllocType
+{
+ /**
+ * @brief At compile time, shape for a tensor is known, thus requried memory capacity can be
+ * calculated
+ */
+ STATIC,
+
+ /**
+ * @brief At kernel execution time, shape for a tensor is known, thus requried memory capacity
+ * can be calculated
+ */
+ DYNAMIC
+};
+
+/**
+ * @brief Class to save tensor's shape and type
+ */
+class OperandInfo
+{
+public:
+ /**
+ * @brief Construct a new OperandInfo object (deleted)
+ */
+ OperandInfo() = delete;
+
+ /**
+ * @brief Construct a new OperandInfo object
+ * @param[in] shape Tensor shape
+ * @param[in] typeInfo Tensor data type
+ * @param[in] alloc_type When the thesor needs memory allocation
+ */
+ OperandInfo(const Shape &shape, const TypeInfo &typeInfo, MemAllocType alloc_type,
+ bool is_const = false, bool is_variable = false)
+ : _shape(shape), _typeInfo(typeInfo), _alloc_type(alloc_type), _const(is_const),
+ _variable(is_variable)
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct a new OperandInfo object
+ * @param[in] origin info for copy
+ */
+ OperandInfo(const OperandInfo &origin) = default;
+
+ /**
+ * @brief Create a static OperandInfo object
+ */
+ static OperandInfo createStaticInfo(const Shape &shape, const TypeInfo &typeInfo)
+ {
+ return OperandInfo(shape, typeInfo, MemAllocType::STATIC);
+ }
+
+public:
+ /**
+ * @brief Return tensor shape
+ * @return Tensor shape
+ */
+ const Shape &shape() const { return _shape; }
+ /**
+ * @brief Return mutable tensor shape
+ * @return Tensor shape
+ */
+ Shape &shape() { return _shape; }
+ /**
+ * @brief set shape
+ */
+ void shape(const ir::Shape &new_shape) { _shape = new_shape; }
+ /**
+ * @brief Return tensor data type info
+ * @return Tensor data type
+ */
+ const TypeInfo &typeInfo() const { return _typeInfo; }
+ /**
+ * @brief Set tensor data type
+ */
+ void type(const DataType type) { _typeInfo.type(type); }
+ /**
+ * @brief Return size of tensor (bytes)
+ * @return Tensor size
+ */
+ size_t total_size() const { return _shape.num_elements() * sizeOfDataType(_typeInfo.type()); }
+
+ MemAllocType memAllocType() const { return _alloc_type; }
+ void setAsConstant() { _const = true; }
+ void setAsNonConst() { _const = false; }
+ bool isConstant() const
+ {
+ // Impossible case: constant and dynamic operand
+ assert(!(isDynamic() && _const));
+ return _const;
+ }
+ void setAsVariable()
+ {
+ // Impossible case: constant or dynamic operand
+ // The variable operand with buffer is not supported yet
+ assert(!(isDynamic() || _const));
+ _variable = true;
+ }
+ bool isVariable() const { return _variable; }
+ bool isDynamic() const { return _alloc_type == MemAllocType::DYNAMIC; }
+ void setDynamic() { _alloc_type = MemAllocType::DYNAMIC; }
+
+private:
+ Shape _shape;
+ TypeInfo _typeInfo;
+
+ MemAllocType _alloc_type;
+ bool _const;
+ bool _variable;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERAND_INFO_H__
diff --git a/runtime/onert/core/include/ir/Operands.h b/runtime/onert/core/include/ir/Operands.h
new file mode 100644
index 000000000..be7b7061f
--- /dev/null
+++ b/runtime/onert/core/include/ir/Operands.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERANDS_H__
+#define __ONERT_IR_OPERANDS_H__
+
+#include <memory>
+#include <unordered_map>
+
+#include "ir/Operand.h"
+#include "ir/Index.h"
+#include "util/ObjectManager.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class Operands : public util::ObjectManager<OperandIndex, Operand>
+{
+public:
+ Operands() = default;
+ Operands(const Operands &obj);
+ Operands(Operands &&) = default;
+ Operands &operator=(const Operands &) = delete;
+ Operands &operator=(Operands &&) = default;
+ ~Operands() = default;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_MODEL_OPERAND_SET_H__
diff --git a/runtime/onert/core/include/ir/Operation.h b/runtime/onert/core/include/ir/Operation.h
new file mode 100644
index 000000000..89f7e340d
--- /dev/null
+++ b/runtime/onert/core/include/ir/Operation.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_H__
+#define __ONERT_IR_OPERATION_H__
+
+#include <memory>
+
+#include "ir/OpCode.h"
+#include "ir/Operand.h"
+#include "ir/OperandIndexSequence.h"
+#include "ir/OperandConstraint.h"
+
+namespace onert
+{
+namespace ir
+{
+
+struct OperationVisitor;
+
+class Operation
+{
+public:
+ // TODO Remove default parameter
+ Operation(OperandConstraint input_constr, const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs,
+ OperandConstraint output_constr = OperandConstraint::createAny());
+ explicit Operation(OperandConstraint input_constr,
+ OperandConstraint output_constr = OperandConstraint::createAny());
+
+ Operation(const Operation &) = default;
+ Operation(Operation &&) = default;
+ Operation &operator=(const Operation &) = default;
+ Operation &operator=(Operation &&) = default;
+
+ virtual ~Operation();
+
+public:
+ virtual void accept(OperationVisitor &v) const = 0;
+ virtual std::string name() const { return std::string{toString(opcode())}; }
+ virtual OpCode opcode() const = 0;
+
+public:
+ void replaceInputs(const OperandIndex &from, const OperandIndex &to);
+ void replaceOutputs(const OperandIndex &from, const OperandIndex &to);
+ OperandIndexSequence &getInputs() { return _inputs; }
+ const OperandIndexSequence &getInputs() const { return _inputs; }
+ const OperandIndexSequence &getOutputs() const { return _outputs; }
+ // It's for only input/output tensors but const data.
+ void setInputs(const OperandIndexSequence &indexes);
+ void setOutputs(const OperandIndexSequence &indexes);
+
+private:
+ OperandConstraint _input_constr;
+ OperandConstraint _output_constr;
+ OperandIndexSequence _inputs;
+ OperandIndexSequence _outputs;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_H__
diff --git a/runtime/onert/core/include/ir/OperationIndexMap.h b/runtime/onert/core/include/ir/OperationIndexMap.h
new file mode 100644
index 000000000..50c21c0ab
--- /dev/null
+++ b/runtime/onert/core/include/ir/OperationIndexMap.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_INDEX_MAP_H__
+#define __ONERT_IR_OPERATION_INDEX_MAP_H__
+
+#include <unordered_map>
+
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace ir
+{
+
+template <typename T> using OperationIndexMap = std::unordered_map<OperationIndex, T>;
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_INDEX_MAP_H__
diff --git a/runtime/onert/core/include/ir/OperationIndexSet.h b/runtime/onert/core/include/ir/OperationIndexSet.h
new file mode 100644
index 000000000..067aa19e1
--- /dev/null
+++ b/runtime/onert/core/include/ir/OperationIndexSet.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_MODEL_OPERATION_INDEX_SET_H__
+#define __ONERT_MODEL_OPERATION_INDEX_SET_H__
+
+#include <algorithm>
+#include <cassert>
+#include <initializer_list>
+#include <unordered_set>
+
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class OperationIndexSet
+{
+public:
+ OperationIndexSet(void) = default;
+ OperationIndexSet(std::initializer_list<OperationIndex> list);
+
+public:
+ void insert(const OperationIndex &index) { _set.insert(index); }
+ void clear(void) { _set.clear(); }
+ void remove(const OperationIndex &index)
+ {
+ auto itr = std::find(_set.begin(), _set.end(), index);
+ assert(itr != _set.end());
+ _set.erase(itr);
+ }
+
+public:
+ uint32_t size() const { return static_cast<uint32_t>(_set.size()); }
+ bool contains(const OperationIndex &index) const;
+
+public:
+ std::unordered_set<OperationIndex>::iterator begin(void) { return _set.begin(); }
+ std::unordered_set<OperationIndex>::iterator end(void) { return _set.end(); }
+ std::unordered_set<OperationIndex>::const_iterator begin(void) const { return _set.begin(); }
+ std::unordered_set<OperationIndex>::const_iterator end(void) const { return _set.end(); }
+
+private:
+ std::unordered_set<OperationIndex> _set;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_MODEL_OPERATION_INDEX_SET_H__
diff --git a/runtime/onert/core/include/ir/OperationVisitor.h b/runtime/onert/core/include/ir/OperationVisitor.h
new file mode 100644
index 000000000..a27770744
--- /dev/null
+++ b/runtime/onert/core/include/ir/OperationVisitor.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_VISITOR_H__
+#define __ONERT_IR_OPERATION_VISITOR_H__
+
+#include "ir/Operations.Include.h"
+#include "ir/OpSequence.h"
+
+namespace onert
+{
+namespace ir
+{
+
+struct OperationVisitor
+{
+ virtual ~OperationVisitor() = default;
+
+#define OP(InternalName) \
+ virtual void visit(const operation::InternalName &) {}
+#include "ir/Operations.lst"
+#undef OP
+
+ // This OpSequence node should be handled specially so that
+ // Op.lst doesn't have OpSequence
+ // TODO Remove by pushing it down to derived classes.
+ virtual void visit(const OpSequence &)
+ {
+ throw std::runtime_error{
+ "OperationVisitor: This does not privide visit function in OpSequence"};
+ }
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_VISITOR_H__
diff --git a/runtime/onert/core/include/ir/Operations.Include.h b/runtime/onert/core/include/ir/Operations.Include.h
new file mode 100644
index 000000000..1f20ee665
--- /dev/null
+++ b/runtime/onert/core/include/ir/Operations.Include.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file has no ifdef guard intentionally
+
+#include "ir/operation/AddN.h"
+#include "ir/operation/BatchToSpaceND.h"
+#include "ir/operation/BinaryArithmetic.h"
+#include "ir/operation/BroadcastTo.h"
+#include "ir/operation/Conv2D.h"
+#include "ir/operation/Pool2D.h"
+#include "ir/operation/Concat.h"
+#include "ir/operation/Reshape.h"
+#include "ir/operation/Fill.h"
+#include "ir/operation/FullyConnected.h"
+#include "ir/operation/Softmax.h"
+#include "ir/operation/Transpose.h"
+#include "ir/operation/Permute.h"
+#include "ir/operation/Reduce.h"
+#include "ir/operation/DepthwiseConv2D.h"
+#include "ir/operation/Slice.h"
+#include "ir/operation/StridedSlice.h"
+#include "ir/operation/Squeeze.h"
+#include "ir/operation/ElementwiseActivation.h"
+#include "ir/operation/ElementwiseBinary.h"
+#include "ir/operation/ElementwiseUnary.h"
+#include "ir/operation/ExpandDims.h"
+#include "ir/operation/Comparison.h"
+#include "ir/operation/LSTM.h"
+#include "ir/operation/ResizeBilinear.h"
+#include "ir/operation/ResizeNearestNeighbor.h"
+#include "ir/operation/Reverse.h"
+#include "ir/operation/RNN.h"
+#include "ir/operation/SpaceToBatchND.h"
+#include "ir/operation/SpaceToDepth.h"
+#include "ir/operation/EmbeddingLookup.h"
+#include "ir/operation/L2Normalization.h"
+#include "ir/operation/HashtableLookup.h"
+#include "ir/operation/InstanceNorm.h"
+#include "ir/operation/PReLU.h"
+#include "ir/operation/TransposeConv.h"
+#include "ir/operation/SquaredDifference.h"
+#include "ir/operation/TopKV2.h"
+#include "ir/operation/Gather.h"
+#include "ir/operation/ArgMax.h"
+#include "ir/operation/LocalResponseNormalization.h"
+#include "ir/operation/DepthToSpace.h"
+#include "ir/operation/Pack.h"
+#include "ir/operation/Select.h"
+#include "ir/operation/Split.h"
+#include "ir/operation/SplitV.h"
+#include "ir/operation/Unpack.h"
+#include "ir/operation/Pad.h"
+#include "ir/operation/Custom.h"
+#include "ir/operation/Einsum.h"
+#include "ir/operation/OneHot.h"
+#include "ir/operation/Shape.h"
+#include "ir/operation/ConvertFp32ToFp16.h"
+#include "ir/operation/ConvertFp16ToFp32.h"
+#include "ir/operation/If.h"
+#include "ir/operation/While.h"
+#include "ir/operation/Pow.h"
+#include "ir/operation/Tile.h"
+#include "ir/operation/Range.h"
+#include "ir/operation/Rank.h"
+#include "ir/operation/BCQFullyConnected.h"
+#include "ir/operation/BCQGather.h"
+#include "ir/operation/MatrixBandPart.h"
+#include "ir/operation/BatchMatMul.h"
+#include "ir/operation/FusedBatchNorm.h"
+#include "ir/operation/LogSoftmax.h"
+#include "ir/operation/StatelessRandomUniform.h"
diff --git a/runtime/onert/core/include/ir/Operations.h b/runtime/onert/core/include/ir/Operations.h
new file mode 100644
index 000000000..0b5fbf529
--- /dev/null
+++ b/runtime/onert/core/include/ir/Operations.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATIONS_H__
+#define __ONERT_IR_OPERATIONS_H__
+
+#include "ir/Index.h"
+#include "ir/Operation.h"
+#include "util/ObjectManager.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class Operations : public util::ObjectManager<OperationIndex, Operation>
+{
+public:
+ Operations() = default;
+ Operations(const Operations &obj);
+ Operations(Operations &&) = default;
+ Operations &operator=(const Operations &) = delete;
+ Operations &operator=(Operations &&) = default;
+ ~Operations() = default;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_MODEL_OPERATION_MANAGER_H__
diff --git a/runtime/onert/core/include/ir/Operations.lst b/runtime/onert/core/include/ir/Operations.lst
new file mode 100644
index 000000000..ccde4d179
--- /dev/null
+++ b/runtime/onert/core/include/ir/Operations.lst
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OP
+#error Define OP before including this file
+#endif
+
+// Internal Name
+OP(AddN)
+OP(BatchToSpaceND)
+OP(BinaryArithmetic)
+OP(BroadcastTo)
+OP(Conv2D)
+OP(DepthwiseConv2D)
+OP(Pool2D)
+OP(Concat)
+OP(Fill)
+OP(FullyConnected)
+OP(Reduce)
+OP(Reshape)
+OP(Softmax)
+OP(Squeeze)
+OP(Slice)
+OP(StridedSlice)
+OP(Transpose)
+OP(ElementwiseActivation)
+OP(ElementwiseBinary)
+OP(ElementwiseUnary)
+OP(ExpandDims)
+OP(Comparison)
+OP(LSTM)
+OP(ResizeBilinear)
+OP(ResizeNearestNeighbor)
+OP(Reverse)
+OP(RNN)
+OP(SpaceToBatchND)
+OP(SpaceToDepth)
+OP(EmbeddingLookup)
+OP(L2Normalization)
+OP(HashtableLookup)
+OP(InstanceNorm)
+OP(PReLU)
+OP(TransposeConv)
+OP(SquaredDifference)
+OP(TopKV2)
+OP(Gather)
+OP(ArgMax)
+OP(Einsum)
+OP(LocalResponseNormalization)
+OP(DepthToSpace)
+OP(Pack)
+OP(Select)
+OP(Split)
+OP(SplitV)
+OP(Unpack)
+OP(Pad)
+OP(Custom)
+OP(Permute)
+OP(OneHot)
+OP(Shape)
+OP(ConvertFp32ToFp16)
+OP(ConvertFp16ToFp32)
+OP(If)
+OP(While)
+OP(Pow)
+OP(Tile)
+OP(Range)
+OP(Rank)
+OP(BCQFullyConnected)
+OP(BCQGather)
+OP(MatrixBandPart)
+OP(BatchMatMul)
+OP(FusedBatchNorm)
+OP(LogSoftmax)
+OP(StatelessRandomUniform)
diff --git a/runtime/onert/core/include/ir/Padding.h b/runtime/onert/core/include/ir/Padding.h
new file mode 100644
index 000000000..8a7bcdbeb
--- /dev/null
+++ b/runtime/onert/core/include/ir/Padding.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_PADDIGN_H__
+#define __ONERT_IR_PADDIGN_H__
+
+#include "Shape.h"
+#include "InternalType.h"
+
+#include <cstdint>
+#include <string>
+
+namespace onert
+{
+namespace ir
+{
+
+enum class PaddingType
+{
+ EXPLICIT = 0,
+ SAME = 1,
+ VALID = 2
+};
+
+/**
+ * @brief Converts a internal padding type to const char*
+ * @param[in] type Padding type to be converted
+ * @return A string holding the converted value
+ */
+inline std::string to_string(const PaddingType type);
+
+struct ExplicitPadding
+{
+ uint32_t left;
+ uint32_t right;
+ uint32_t top;
+ uint32_t bottom;
+};
+
+// TODO Resolve explicit padding param at frontend and save in value field
+struct Padding
+{
+ Padding(void);
+ Padding(PaddingType paddingType);
+ Padding(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom);
+
+ // TODO Change to private field
+ PaddingType type;
+ ExplicitPadding param;
+};
+
+// TODO Change to Padding struct's method
+const ExplicitPadding calculatePadding(const Padding &padding, const FeatureShape &ifm_shape,
+ const FeatureShape &ofm_shape, const Stride &stride,
+ uint32_t kw, uint32_t kh, uint32_t dwf = 1,
+ uint32_t dhf = 1);
+
+} // namespace ir
+} // namespace onert
+
+#endif
diff --git a/runtime/onert/core/include/ir/Shape.h b/runtime/onert/core/include/ir/Shape.h
new file mode 100644
index 000000000..a0b4bb196
--- /dev/null
+++ b/runtime/onert/core/include/ir/Shape.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef __ONERT_IR_SHAPE_H__
+#define __ONERT_IR_SHAPE_H__
+
+#include "ir/Layout.h"
+
+#include <cassert>
+#include <cstdint>
+#include <vector>
+#include <algorithm>
+
+namespace onert
+{
+namespace ir
+{
+
+/**
+ * @brief Structure to have values of dimensions for feature
+ */
+struct FeatureShape
+{
+ int32_t N; /**< The batch value */
+ int32_t C; /**< The depth value */
+ int32_t H; /**< The height value */
+ int32_t W; /**< The width value */
+
+ /**
+ * @brief Construct FeatureShape object using default constrcutor
+ */
+ FeatureShape() = default;
+ /**
+ * @brief Construct FeatureShape object with three values of dimensions
+ * @param[in] depth The depth value
+ * @param[in] height The height value
+ * @param[in] width The width value
+ */
+ FeatureShape(int32_t depth, int32_t height, int32_t width) : N{1}, C{depth}, H{height}, W{width}
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct FeatureShape object with four values of dimensions
+ * @param[in] batch The batch value
+ * @param[in] depth The depth value
+ * @param[in] height The height value
+ * @param[in] width The width value
+ */
+ FeatureShape(int32_t batch, int32_t depth, int32_t height, int32_t width)
+ : N{batch}, C{depth}, H{height}, W{width}
+ {
+ // DO NOTHING
+ }
+};
+
+struct Shape
+{
+public:
+ static int32_t const UNSPECIFIED_DIM;
+ static int32_t const MAX_RANK;
+
+ Shape() = default;
+
+ explicit Shape(int rank) : _dimensions(rank) {}
+
+ Shape(std::initializer_list<int32_t> dimensions) : _dimensions(dimensions) {}
+
+ int rank() const { return _dimensions.size(); }
+
+ const std::vector<int32_t> &dims() const { return _dimensions; }
+
+ int32_t dim(int i) const
+ {
+ assert(rank() != 0 || i == 0);
+ return rank() == 0 ? 1 : _dimensions.at(i);
+ }
+
+ int32_t &dim(int i) { return _dimensions.at(i); }
+
+ /**
+ * @brief Returns number of elements when rank or dim is specified
+ */
+ uint64_t num_elements() const;
+
+public:
+ FeatureShape asFeature(Layout layout) const;
+
+ /**
+ * @brief Add dimension to the beginning
+ * @param[in] d dimension to add to the beginning
+ */
+ void prepend(int32_t d) { _dimensions.insert(_dimensions.cbegin(), d); }
+
+ /**
+ * @brief Add dimension to the end
+ * @param[in] d dimension to add to the end
+ */
+ void append(int32_t d) { _dimensions.emplace_back(d); }
+
+ /**
+ * @brief Extend rank of Shape object for operand with param.
+ * @param[in] to_rank The rank value to be extended to
+ */
+ void extendRank(int to_rank);
+
+ /**
+ * @brief Find out if any dimension is unspecified. If the rank is not specified, it returns
+ * false.
+ * \see https://developer.android.com/ndk/reference/struct/a-neural-networks-operand-type
+ * @note base_loader set dim to -1 when there is unknown dim in input tensor
+ */
+ bool hasUnspecifiedDims() const
+ {
+ return (std::find(_dimensions.begin(), _dimensions.end(), UNSPECIFIED_DIM) !=
+ _dimensions.end());
+ }
+
+private:
+ std::vector<int32_t> _dimensions;
+};
+
+inline bool operator==(const Shape &lhs, const Shape &rhs) { return lhs.dims() == rhs.dims(); }
+inline bool operator!=(const Shape &lhs, const Shape &rhs) { return lhs.dims() != rhs.dims(); }
+
+Shape permuteShape(const Shape &shape, Layout frontend_layout, Layout backend_layout);
+
+/**
+* @brief Find out if tha rank in this shape is "maybe" unspecified.
+* Note that when rank == 0, shape could represent scalar or unspecified rank
+* \see https://developer.android.com/ndk/reference/struct/a-neural-networks-operand-type
+*/
+inline bool rankMaybeUnspecified(const ir::Shape &shape) { return (shape.rank() == 0); }
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_SHAPE_H__
diff --git a/runtime/onert/core/include/ir/Sparsity.h b/runtime/onert/core/include/ir/Sparsity.h
new file mode 100644
index 000000000..ad4d8259b
--- /dev/null
+++ b/runtime/onert/core/include/ir/Sparsity.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef __ONERT_IR_SPARSITY_H__
+#define __ONERT_IR_SPARSITY_H__
+
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+namespace onert
+{
+namespace ir
+{
+
+/**
+ * @brief Structure for Sparse Tensor
+ */
+struct Sparsity
+{
+public:
+ Sparsity() = default;
+ Sparsity(std::vector<uint16_t> &&w1_segments, std::vector<uint16_t> &&w1_indices,
+ std::vector<int32_t> &&block_size)
+ : _w1_segments(w1_segments), _w1_indices(w1_indices), _block_size(block_size)
+ {
+ }
+
+ /**
+ * @brief Returns segments array. See compressed sparse row format.
+ */
+ const uint16_t *w1_segments() const { return _w1_segments.data(); }
+ /**
+ * @brief Returns indices array. See compressed sparse row format.
+ */
+ const uint16_t *w1_indices() const { return _w1_indices.data(); }
+ /**
+ * @brief Returns block size which is used for block sparsity
+ */
+ const std::vector<int32_t> &block_size() const { return _block_size; }
+
+private:
+ std::vector<uint16_t> _w1_segments;
+ std::vector<uint16_t> _w1_indices;
+ std::vector<int32_t> _block_size;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_SPARSITY_H__
diff --git a/runtime/onert/core/include/ir/Subgraphs.h b/runtime/onert/core/include/ir/Subgraphs.h
new file mode 100644
index 000000000..7b4c33b76
--- /dev/null
+++ b/runtime/onert/core/include/ir/Subgraphs.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_SUBGRAPHS_H__
+#define __ONERT_IR_SUBGRAPHS_H__
+
+#include <memory>
+#include <unordered_map>
+
+#include "ir/Index.h"
+#include "util/ObjectManager.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class Graph;
+
+class Subgraphs
+{
+public:
+ Subgraphs() = default;
+ Subgraphs(const Subgraphs &obj) = default;
+ Subgraphs(Subgraphs &&) = default;
+ Subgraphs &operator=(const Subgraphs &) = default;
+ Subgraphs &operator=(Subgraphs &&) = default;
+ ~Subgraphs() = default;
+
+ /**
+ * @brief Put subgraph in the container with a new Index for that
+ *
+ * @param[in] subg Subgraph to be pushed
+ * @param[in] index Index of subgraph to be pushed
+ * @return Created
+ */
+ void push(SubgraphIndex index, const std::shared_ptr<Graph> &subg) { _subgraphs[index] = subg; }
+
+ /**
+ * @brief Remove the subgraph that is associated with the given index
+ *
+ * @param[in] index Index of the subgraph to be removed
+ * @return N/A
+ */
+ void remove(const SubgraphIndex &index) { _subgraphs.erase(index); }
+
+ /**
+ * @brief Get the subgraph that is associated with the given index
+ *
+ * @param[in] index Index of the subgraph to be returned
+ * @return Graph
+ */
+ const std::shared_ptr<Graph> &at(const SubgraphIndex &index) const
+ {
+ return _subgraphs.at(index);
+ }
+ /**
+ * @brief Get the subgraph that is associated with the given index
+ *
+ * @param[in] index Index of the subgraph to be returned
+ * @return Graph
+ */
+ std::shared_ptr<Graph> &at(const SubgraphIndex &index) { return _subgraphs.at(index); }
+
+ /**
+ * @brief Get the subgraph that is associated with the given index
+ *
+ * @param[in] index Index of the subgraph to be returned
+ * @return true if such entry exists otherwise false
+ */
+ bool exist(const SubgraphIndex &index) const
+ {
+ auto it = _subgraphs.find(index);
+ return it != _subgraphs.end();
+ }
+
+ /**
+ * @brief Iterate over the container with given function
+ *
+ * @param[in] fn Function to be run for every container entry
+ * @return N/A
+ */
+ void iterate(const std::function<void(const SubgraphIndex &, const Graph &)> &fn) const
+ {
+ for (const auto &e : _subgraphs)
+ {
+ fn(e.first, *e.second);
+ }
+ }
+
+ /**
+ * @brief Iterate over the container with given function
+ *
+ * @param[in] fn Function to be run for every container entry
+ * @return N/A
+ */
+ void iterate(const std::function<void(const SubgraphIndex &, Graph &)> &fn)
+ {
+ for (const auto &e : _subgraphs)
+ {
+ fn(e.first, *e.second);
+ }
+ }
+
+ /**
+ * @brief Get count of Subgraphs
+ *
+ * @return count of Subgraphs
+ */
+ size_t count() { return _subgraphs.size(); }
+
+ /**
+ * @brief Return the primary subgraph
+ *
+ * @return std::shared_ptr<Graph> Primary sugraph
+ */
+ std::shared_ptr<Graph> primary() const { return _subgraphs.at(SubgraphIndex{0}); }
+
+private:
+ std::unordered_map<SubgraphIndex, std::shared_ptr<Graph>> _subgraphs;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_SUBGRAPHS_H__
diff --git a/runtime/onert/core/include/ir/TypeInfo.h b/runtime/onert/core/include/ir/TypeInfo.h
new file mode 100644
index 000000000..a1ae4d2e4
--- /dev/null
+++ b/runtime/onert/core/include/ir/TypeInfo.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_TYPEINFO_H__
+#define __ONERT_IR_TYPEINFO_H__
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "ir/DataType.h"
+#include "ir/Sparsity.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class TypeInfo
+{
+public:
+ TypeInfo() = delete;
+
+ explicit TypeInfo(DataType type, float scale = 0, int32_t offset = 0)
+ : _type(type), _scale(scale), _offset(offset), _sparsity(nullptr)
+ {
+ }
+
+public:
+ DataType type() const { return _type; }
+ float scale() const { return _scale; }
+ int32_t offset() const { return _offset; }
+ const ir::Sparsity *sparsity() const { return _sparsity.get(); }
+ void sparsity(std::shared_ptr<ir::Sparsity> sparsity) { _sparsity = sparsity; }
+
+public:
+ void type(const DataType type) { _type = type; }
+
+private:
+ DataType _type;
+ // for quantization
+ float _scale;
+ int32_t _offset;
+ // for sparsity
+ std::shared_ptr<ir::Sparsity> _sparsity;
+};
+
+bool operator==(const TypeInfo &lhs, const TypeInfo &rhs);
+bool operator!=(const TypeInfo &lhs, const TypeInfo &rhs);
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_TYPEINFO_H__
diff --git a/runtime/onert/core/include/ir/operand/LowerInfo.h b/runtime/onert/core/include/ir/operand/LowerInfo.h
new file mode 100644
index 000000000..b7f032b02
--- /dev/null
+++ b/runtime/onert/core/include/ir/operand/LowerInfo.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERAND_LOWER_INFO_H__
+#define __ONERT_IR_OPERAND_LOWER_INFO_H__
+
+#include <functional>
+#include <stdint.h>
+
+#include "ir/operand/PermuteFactor.h"
+#include "util/Set.h"
+
+namespace onert
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+namespace operand
+{
+using PermuteFactorSet = util::Set<PermuteFactor>;
+
+class LowerInfo
+{
+public:
+ LowerInfo()
+ {
+ // DO NOTHING
+ }
+
+public:
+ const PermuteFactorSet &def_factors(void) const { return _def_factors; }
+ const PermuteFactorSet &use_factors(void) const { return _use_factors; }
+
+public:
+ void addDefPermuteFactor(const PermuteFactor &factor) { _def_factors.add(factor); }
+ void addUsePermuteFactor(const PermuteFactor &factor) { _use_factors.add(factor); }
+ void removeDefPermuteFactor(const PermuteFactor &factor) { _def_factors.remove(factor); }
+ void removeUsePermuteFactor(const PermuteFactor &factor) { _use_factors.remove(factor); }
+
+private:
+ PermuteFactorSet _def_factors;
+ PermuteFactorSet _use_factors;
+};
+
+} // namespace operand
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERAND_LOWER_INFO_H__
diff --git a/runtime/onert/core/include/ir/operand/PermuteFactor.h b/runtime/onert/core/include/ir/operand/PermuteFactor.h
new file mode 100644
index 000000000..d0bfed337
--- /dev/null
+++ b/runtime/onert/core/include/ir/operand/PermuteFactor.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file PermuteFactor.h
+ * @brief This file contains onert::ir::operand::PermuteFactor class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __ONERT_IR_OPERAND_PERMUTE_FACTOR_H__
+#define __ONERT_IR_OPERAND_PERMUTE_FACTOR_H__
+
+#include <functional>
+
+#include "ir/Layout.h"
+
+namespace onert
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+namespace operand
+{
+
+/**
+ * @brief Class that has factors of permutation
+ */
+class PermuteFactor
+{
+public:
+ /**
+ * @brief Construct PermuteFactor object.
+ * @param backend The backend factor
+ * @param layout The layout factor
+ */
+ PermuteFactor(const backend::Backend *backend, Layout layout) : _backend{backend}, _layout{layout}
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct PermuteFactor object by copy semantics.
+ */
+ PermuteFactor(const PermuteFactor &f) : _backend{f._backend}, _layout{f._layout}
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct PermuteFactor object by move semantics.
+ */
+ PermuteFactor(PermuteFactor &&) = default;
+
+public:
+ /**
+ * @brief Get backend
+ *
+ * @return Backend factor
+ */
+ const backend::Backend *backend() const { return _backend; }
+ /**
+ * @brief Get layout
+ *
+ * @return Layout factor
+ */
+ Layout layout() const { return _layout; }
+
+public:
+ /**
+ * @brief operator overloading function for `==`
+ *
+ * @return Whether two PermuteFactor are the same
+ */
+ bool operator==(const PermuteFactor &other) const
+ {
+ return _backend == other.backend() && _layout == other.layout();
+ }
+ /**
+ * @brief operator overloading function for `!=`
+ *
+ * @return Whether two PermuteFactor are differenct
+ */
+ bool operator!=(const PermuteFactor &other) const { return !(*this == other); }
+
+private:
+ const backend::Backend *_backend{nullptr};
+ Layout _layout{Layout::UNKNOWN};
+};
+
+} // namespace operand
+} // namespace ir
+} // namespace onert
+
+namespace std
+{
+
+/**
+ * @brief Structure that provides hash value of PermuteFactor
+ */
+template <> struct hash<onert::ir::operand::PermuteFactor>
+{
+ size_t operator()(const onert::ir::operand::PermuteFactor &factor) const noexcept
+ {
+ hash<const onert::backend::Backend *> b_hash{};
+ hash<onert::ir::Layout> l_hash{};
+ return b_hash(factor.backend()) ^ (l_hash(factor.layout()) << 1);
+ }
+};
+
+} // namespace std
+
+#endif // __ONERT_IR_OPERAND_PERMUTE_FACTOR_H__
diff --git a/runtime/onert/core/include/ir/operation/AddN.h b/runtime/onert/core/include/ir/operation/AddN.h
new file mode 100644
index 000000000..7a307efa5
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/AddN.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_ADDN_H__
+#define __ONERT_IR_OPERATION_ADDN_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class AddN : public Operation
+{
+public:
+ AddN(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::AddN; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_ADDN_H__
diff --git a/runtime/onert/core/include/ir/operation/ArgMax.h b/runtime/onert/core/include/ir/operation/ArgMax.h
new file mode 100644
index 000000000..ea7eabb83
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ArgMax.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_ARG_MAX_H__
+#define __ONERT_IR_OPERATION_ARG_MAX_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ArgMax : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ AXIS = 1
+ };
+
+ struct Param
+ {
+ DataType output_type;
+ };
+
+public:
+ ArgMax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ArgMax; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_ARG_MAX_H__
diff --git a/runtime/onert/core/include/ir/operation/BCQFullyConnected.h b/runtime/onert/core/include/ir/operation/BCQFullyConnected.h
new file mode 100644
index 000000000..4bf3a0bdb
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/BCQFullyConnected.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_BCQFULLYCONNECTED_H__
+#define __ONERT_IR_OPERATION_BCQFULLYCONNECTED_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class BCQFullyConnected : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ WEIGHTS_SCALES,
+ WEIGHTS_BINARY,
+ BIAS,
+ WEIGHTS_CLUSTERS,
+ };
+
+ struct Param
+ {
+ uint32_t weights_hidden_size;
+ Activation activation;
+ };
+
+public:
+ BCQFullyConnected(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::BCQFullyConnected; }
+
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_BCQFULLYCONNECTED_H__
diff --git a/runtime/onert/core/include/ir/operation/BCQGather.h b/runtime/onert/core/include/ir/operation/BCQGather.h
new file mode 100644
index 000000000..1349b8c6d
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/BCQGather.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_BCQGATHER_H__
+#define __ONERT_IR_OPERATION_BCQGATHER_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class BCQGather : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT_SCALES = 0,
+ INPUT_BINARY,
+ INDICES,
+ INPUT_CLUSTERS,
+ };
+
+ struct Param
+ {
+ uint32_t input_hidden_size;
+ uint32_t axis;
+ };
+
+public:
+ BCQGather(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::BCQGather; }
+
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_BCQGATHER_H__
diff --git a/runtime/onert/core/include/ir/operation/BatchMatMul.h b/runtime/onert/core/include/ir/operation/BatchMatMul.h
new file mode 100644
index 000000000..183f60abe
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/BatchMatMul.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_BATCH_MATMUL_H__
+#define __ONERT_IR_OPERATION_BATCH_MATMUL_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class BatchMatMul : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+ struct Param
+ {
+ bool adj_x;
+ bool adj_y;
+ };
+
+public:
+ BatchMatMul(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::BatchMatMul; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_BATCH_MATMUL_H__
diff --git a/runtime/onert/core/include/ir/operation/BatchToSpaceND.h b/runtime/onert/core/include/ir/operation/BatchToSpaceND.h
new file mode 100644
index 000000000..3e69b42c7
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/BatchToSpaceND.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_BATCH_TO_SPACE_ND_H__
+#define __ONERT_IR_OPERATION_BATCH_TO_SPACE_ND_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class BatchToSpaceND : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ BLOCK_SIZE = 1,
+ CROPS_DATA = 2
+ };
+
+public:
+ BatchToSpaceND(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::BatchToSpaceND; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_BATCH_TO_SPACE_ND_H__
diff --git a/runtime/onert/core/include/ir/operation/BinaryArithmetic.h b/runtime/onert/core/include/ir/operation/BinaryArithmetic.h
new file mode 100644
index 000000000..110fff565
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/BinaryArithmetic.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_BINARY_ARITHMETIC_H__
+#define __ONERT_IR_OPERATION_BINARY_ARITHMETIC_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class BinaryArithmetic final : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+ enum class ArithmeticType
+ {
+ ADD,
+ SUB,
+ MUL,
+ DIV
+ };
+
+ struct Param
+ {
+ ArithmeticType arithmetic_type;
+ Activation activation;
+ };
+
+public:
+ BinaryArithmetic(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ std::string name() const override;
+ OpCode opcode() const final { return OpCode::BinaryArithmetic; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_BINARY_ARITHMETIC_H__
diff --git a/runtime/onert/core/include/ir/operation/BroadcastTo.h b/runtime/onert/core/include/ir/operation/BroadcastTo.h
new file mode 100644
index 000000000..06c033497
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/BroadcastTo.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_BROADCAST_TO_H__
+#define __ONERT_IR_OPERATION_BROADCAST_TO_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class BroadcastTo : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ SHAPE = 1
+ };
+
+public:
+ BroadcastTo(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::BroadcastTo; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_BROADCAST_TO_H__
diff --git a/runtime/onert/core/include/ir/operation/Comparison.h b/runtime/onert/core/include/ir/operation/Comparison.h
new file mode 100644
index 000000000..8b53f163b
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Comparison.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_COMPARISON_H__
+#define __ONERT_IR_OPERATION_COMPARISON_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Comparison : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT0 = 0,
+ INPUT1
+ };
+
+ enum class ComparisonType
+ {
+ Equal,
+ NotEqual,
+ Greater,
+ GreaterEqual,
+ Less,
+ LessEqual
+ };
+
+ struct Param
+ {
+ ComparisonType comparison_type;
+ };
+
+public:
+ Comparison(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Comparison; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_COMPARISON_H__
diff --git a/runtime/onert/core/include/ir/operation/Concat.h b/runtime/onert/core/include/ir/operation/Concat.h
new file mode 100644
index 000000000..2dff04e93
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Concat.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_CONCAT_H__
+#define __ONERT_IR_OPERATION_CONCAT_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Concat : public Operation
+{
+public:
+ struct Param
+ {
+ int32_t axis;
+ };
+
+public:
+ Concat(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Concat; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_CONCAT_H__
diff --git a/runtime/onert/core/include/ir/operation/Conv2D.h b/runtime/onert/core/include/ir/operation/Conv2D.h
new file mode 100644
index 000000000..d8c7b671b
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Conv2D.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_CONV2D_H__
+#define __ONERT_IR_OPERATION_CONV2D_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+#include "ir/Padding.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Conv2D : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ KERNEL,
+ BIAS
+ };
+
+ struct Param
+ {
+ Stride stride;
+ Padding padding;
+ Activation activation;
+ Dilation dilation;
+ };
+
+public:
+ Conv2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Conv2D; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_CONV2D_H__
diff --git a/runtime/onert/core/include/ir/operation/ConvertFp16ToFp32.h b/runtime/onert/core/include/ir/operation/ConvertFp16ToFp32.h
new file mode 100644
index 000000000..15c48357f
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ConvertFp16ToFp32.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_CONVERT_FP16_TO_FP32_H__
+#define __ONERT_IR_OPERATION_CONVERT_FP16_TO_FP32_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ConvertFp16ToFp32 : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ ConvertFp16ToFp32(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ConvertFp16ToFp32; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_CONVERT_FP16_TO_FP32_H__
diff --git a/runtime/onert/core/include/ir/operation/ConvertFp32ToFp16.h b/runtime/onert/core/include/ir/operation/ConvertFp32ToFp16.h
new file mode 100644
index 000000000..983ce4891
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ConvertFp32ToFp16.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_CONVERT_FP32_TO_FP16_H__
+#define __ONERT_IR_OPERATION_CONVERT_FP32_TO_FP16_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ConvertFp32ToFp16 : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ ConvertFp32ToFp16(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ConvertFp32ToFp16; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_CONVERT_FP32_TO_FP16_H__
diff --git a/runtime/onert/core/include/ir/operation/Custom.h b/runtime/onert/core/include/ir/operation/Custom.h
new file mode 100644
index 000000000..c2a4b354a
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Custom.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __ONERT_IR_OPERATION_CUSTOM_H__
+#define __ONERT_IR_OPERATION_CUSTOM_H__
+
+#include "ir/Operation.h"
+
+#include <cstring>
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Custom : public Operation
+{
+public:
+ struct Userdata
+ {
+ char *data;
+ size_t size;
+
+ Userdata() : data{nullptr}, size{0} {}
+ Userdata(const Userdata &o)
+ {
+ size = o.size;
+ data = new char[size];
+ std::memcpy(data, o.data, size);
+ }
+ ~Userdata() { delete[] data; }
+ };
+
+ Custom(OperandConstraint input_constr, const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, std::string id, const Userdata &userdata);
+
+ void accept(OperationVisitor &v) const override;
+
+public:
+ /**
+ * @return unique operation identifier
+ */
+ const std::string &id() const;
+
+ std::string name() const override;
+ OpCode opcode() const final { return OpCode::Custom; }
+
+ /**
+ * @return user-provided data
+ */
+ const Userdata &userdata() const;
+
+private:
+ std::string _id;
+ Userdata _userdata;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+#endif // __ONERT_IR_OPERATION_CUSTOM_H__
diff --git a/runtime/onert/core/include/ir/operation/DepthToSpace.h b/runtime/onert/core/include/ir/operation/DepthToSpace.h
new file mode 100644
index 000000000..a5315051d
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/DepthToSpace.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_DEPTH_TO_SPACE_H__
+#define __ONERT_IR_OPERATION_DEPTH_TO_SPACE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class DepthToSpace : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ std::int32_t block_size;
+ };
+
+public:
+ DepthToSpace(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::DepthToSpace; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_DEPTH_TO_SPACE_H__
diff --git a/runtime/onert/core/include/ir/operation/DepthwiseConv2D.h b/runtime/onert/core/include/ir/operation/DepthwiseConv2D.h
new file mode 100644
index 000000000..38e2b5cd6
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/DepthwiseConv2D.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_DEPTHWISECONV2D_H__
+#define __ONERT_IR_OPERATION_DEPTHWISECONV2D_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+#include "ir/Padding.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class DepthwiseConv2D : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ KERNEL,
+ BIAS
+ };
+
+ struct Param
+ {
+ Stride stride;
+ Padding padding;
+ uint32_t multiplier;
+ Activation activation;
+ Dilation dilation;
+ };
+
+public:
+ DepthwiseConv2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::DepthwiseConv2D; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_DEPTHWISECONV2D_H__
diff --git a/runtime/onert/core/include/ir/operation/Einsum.h b/runtime/onert/core/include/ir/operation/Einsum.h
new file mode 100644
index 000000000..9892c24b8
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Einsum.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_EINSUM_H__
+#define __ONERT_IR_OPERATION_EINSUM_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Einsum : public Operation
+{
+public:
+ struct Param
+ {
+ std::string equation;
+ };
+
+public:
+ Einsum(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Einsum; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_EINSUM_H__
diff --git a/runtime/onert/core/include/ir/operation/ElementwiseActivation.h b/runtime/onert/core/include/ir/operation/ElementwiseActivation.h
new file mode 100644
index 000000000..b2a1d3d2d
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ElementwiseActivation.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_ELEMENTWISE_ACTIVATION_H__
+#define __ONERT_IR_OPERATION_ELEMENTWISE_ACTIVATION_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ElementwiseActivation : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ enum class Type
+ {
+ ELU,
+ LOGISTIC,
+ RELU,
+ TANH,
+ LEAKY_RELU
+ };
+
+ struct Param
+ {
+ Type op_type;
+ float alpha;
+ float beta;
+ Param() : op_type(Type::ELU), alpha(0.0f), beta(0.0f) {}
+ };
+
+public:
+ ElementwiseActivation(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ std::string name() const override;
+ OpCode opcode() const final { return OpCode::ElementwiseActivation; }
+
+public:
+ const Param &param() const { return _param; }
+
+public:
+ static float infinity;
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_ELEMENTWISE_ACTIVATION_H__
diff --git a/runtime/onert/core/include/ir/operation/ElementwiseBinary.h b/runtime/onert/core/include/ir/operation/ElementwiseBinary.h
new file mode 100644
index 000000000..dd07f6058
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ElementwiseBinary.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_ELEMENTWISEBINARY_H__
+#define __ONERT_IR_OPERATION_ELEMENTWISEBINARY_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ElementwiseBinary : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+ enum class ElementwiseBinaryType
+ {
+ LOGICAL_AND,
+ LOGICAL_OR,
+ MAX,
+ MIN
+ };
+
+ struct Param
+ {
+ ElementwiseBinaryType op_type;
+ };
+
+public:
+ ElementwiseBinary(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ std::string name() const override;
+ OpCode opcode() const final { return OpCode::ElementwiseBinary; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_ELEMENTWISEBINARY_H__
diff --git a/runtime/onert/core/include/ir/operation/ElementwiseUnary.h b/runtime/onert/core/include/ir/operation/ElementwiseUnary.h
new file mode 100644
index 000000000..c40778a56
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ElementwiseUnary.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_ELEMENTWISEUNARY_H__
+#define __ONERT_IR_OPERATION_ELEMENTWISEUNARY_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ElementwiseUnary : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ enum class Type
+ {
+ ABS,
+ CAST,
+ COS,
+ DEQUANTIZE,
+ ERF,
+ EXP,
+ FLOOR,
+ LOG,
+ LOGICAL_NOT,
+ NEG,
+ QUANTIZE,
+ ROUND,
+ RSQRT,
+ SIN,
+ SQRT,
+ SQURE,
+ ZEROS_LIKE
+ };
+
+ struct Param
+ {
+ Type op_type;
+ };
+
+public:
+ ElementwiseUnary(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ std::string name() const override;
+ OpCode opcode() const final { return OpCode::ElementwiseUnary; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_ELEMENTWISEUNARY_H__
diff --git a/runtime/onert/core/include/ir/operation/EmbeddingLookup.h b/runtime/onert/core/include/ir/operation/EmbeddingLookup.h
new file mode 100644
index 000000000..54064faf0
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/EmbeddingLookup.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_EMBEDDING_LOOKUP_H__
+#define __ONERT_IR_OPERATION_EMBEDDING_LOOKUP_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class EmbeddingLookup : public Operation
+{
+public:
+ enum Input
+ {
+ LOOKUPS = 0,
+ VALUES = 1
+ };
+
+public:
+ EmbeddingLookup(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::EmbeddingLookup; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_EMBEDDING_LOOKUP_H__
diff --git a/runtime/onert/core/include/ir/operation/ExpandDims.h b/runtime/onert/core/include/ir/operation/ExpandDims.h
new file mode 100644
index 000000000..09669a40b
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ExpandDims.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_EXPANDDIMS_H__
+#define __ONERT_IR_OPERATION_EXPANDDIMS_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ExpandDims : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ AXIS = 1
+ };
+
+public:
+ ExpandDims(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ExpandDims; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_EXPANDDIMS_H__
diff --git a/runtime/onert/core/include/ir/operation/Fill.h b/runtime/onert/core/include/ir/operation/Fill.h
new file mode 100644
index 000000000..524e41385
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Fill.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_FILL_H__
+#define __ONERT_IR_OPERATION_FILL_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Fill : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ VALUE,
+ };
+
+public:
+ Fill(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Fill; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_FILL_H__
diff --git a/runtime/onert/core/include/ir/operation/FullyConnected.h b/runtime/onert/core/include/ir/operation/FullyConnected.h
new file mode 100644
index 000000000..f83a64557
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/FullyConnected.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_FULLYCONNECTED_H__
+#define __ONERT_IR_OPERATION_FULLYCONNECTED_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class FullyConnected : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ WEIGHT,
+ BIAS
+ };
+
+ struct Param
+ {
+ Activation activation;
+ FullyConnectedWeightsFormat weights_format;
+ };
+
+public:
+ FullyConnected(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::FullyConnected; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_FULLYCONNECTED_H__
diff --git a/runtime/onert/core/include/ir/operation/FusedBatchNorm.h b/runtime/onert/core/include/ir/operation/FusedBatchNorm.h
new file mode 100644
index 000000000..989ee2b98
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/FusedBatchNorm.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_FUSEDBATCHNORM_H__
+#define __ONERT_IR_OPERATION_FUSEDBATCHNORM_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class FusedBatchNorm : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ SCALE,
+ OFFSET,
+ MEAN,
+ VARIANCE
+ };
+
+ struct Param
+ {
+ bool is_training;
+ std::string data_format;
+ float epsilon;
+ };
+
+public:
+ FusedBatchNorm(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::FusedBatchNorm; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_FUSEDBATCHNORM_H__
diff --git a/runtime/onert/core/include/ir/operation/Gather.h b/runtime/onert/core/include/ir/operation/Gather.h
new file mode 100644
index 000000000..544eb3b19
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Gather.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_GATHER_H__
+#define __ONERT_IR_OPERATION_GATHER_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Gather : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ INDICES,
+ };
+
+ struct Param
+ {
+ int32_t axis;
+ };
+
+public:
+ Gather(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Gather; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_GATHER_H__
diff --git a/runtime/onert/core/include/ir/operation/HashtableLookup.h b/runtime/onert/core/include/ir/operation/HashtableLookup.h
new file mode 100644
index 000000000..4b6cf9362
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/HashtableLookup.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_HASHTABLE_LOOKUP_H__
+#define __ONERT_IR_OPERATION_HASHTABLE_LOOKUP_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class HashtableLookup : public Operation
+{
+public:
+ enum Input
+ {
+ LOOKUPS = 0,
+ KEYS = 1,
+ VALUES = 2
+ };
+
+ enum Output
+ {
+ OUTPUT = 0,
+ HITS = 1
+ };
+
+public:
+ HashtableLookup(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::HashtableLookup; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_HASHTABLE_LOOKUP_H__
diff --git a/runtime/onert/core/include/ir/operation/If.h b/runtime/onert/core/include/ir/operation/If.h
new file mode 100644
index 000000000..41cd4e239
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/If.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_IF_H__
+#define __ONERT_IR_OPERATION_IF_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class If : public Operation
+{
+public:
+ struct Param
+ {
+ SubgraphIndex then_subg_index;
+ SubgraphIndex else_subg_index;
+ };
+
+public:
+ If(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::If; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_IF_H__
diff --git a/runtime/onert/core/include/ir/operation/InstanceNorm.h b/runtime/onert/core/include/ir/operation/InstanceNorm.h
new file mode 100644
index 000000000..6a3bb5189
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/InstanceNorm.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_INSTANCE_NORM_H__
+#define __ONERT_IR_OPERATION_INSTANCE_NORM_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class InstanceNorm : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ GAMMA,
+ BETA
+ };
+
+ struct Param
+ {
+ Activation activation;
+ float epsilon;
+ };
+
+public:
+ InstanceNorm(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::InstanceNorm; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_INSTANCE_NORM_H__
diff --git a/runtime/onert/core/include/ir/operation/L2Normalization.h b/runtime/onert/core/include/ir/operation/L2Normalization.h
new file mode 100644
index 000000000..abbd68c97
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/L2Normalization.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_L2_NORMALIZATION_H__
+#define __ONERT_IR_OPERATION_L2_NORMALIZATION_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class L2Normalization : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ L2Normalization(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::L2Normalization; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_L2_NORMALIZATION_H__
diff --git a/runtime/onert/core/include/ir/operation/LSTM.h b/runtime/onert/core/include/ir/operation/LSTM.h
new file mode 100644
index 000000000..027bc6b42
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/LSTM.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __ONERT_IR_OPERATION_LSTM_H__
+#define __ONERT_IR_OPERATION_LSTM_H__
+
+#include "ir/InternalType.h"
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+// This operation supports only unidirectional sequence lstm
+class LSTM : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ INPUT_TO_INPUT_WEIGHTS = 1,
+ INPUT_TO_FORGET_WEIGHTS = 2,
+ INPUT_TO_CELL_WEIGHTS = 3,
+ INPUT_TO_OUTPUT_WEIGHTS = 4,
+ RECURRENT_TO_INPUT_WEIGHTS = 5,
+ RECURRENT_TO_FORGET_WEIGHTS = 6,
+ RECURRENT_TO_CELL_WEIGHTS = 7,
+ RECURRENT_TO_OUTPUT_WEIGHTS = 8,
+ CELL_TO_INPUT_WEIGHTS = 9,
+ CELL_TO_FORGET_WEIGHTS = 10,
+ CELL_TO_OUTPUT_WEIGHTS = 11,
+ INPUT_GATE_BIAS = 12,
+ FORGET_GATE_BIAS = 13,
+ CELL_BIAS = 14,
+ OUTPUT_GATE_BIAS = 15,
+ PROJECTION_WEIGHTS = 16,
+ PROJECTION_BIAS = 17,
+ OUTPUT_STATE_IN = 18,
+ CELL_STATE_IN = 19,
+ INPUT_LAYER_NORMALIZATION_WEIGHTS = 20,
+ FORGET_LAYER_NORMALIZATION_WEIGHTS = 21,
+ CELL_LAYER_NORMALIZATION_WEIGHTS = 22,
+ OUTPUT_LAYER_NORMALIZATION_WEIGHTS = 23,
+ };
+
+ enum Output
+ {
+ SCRATCH_BUFFER = 0,
+ OUTPUT_STATE_OUT = 1,
+ CELL_STATE_OUT = 2,
+ OUTPUT = 3
+ };
+
+ struct Param
+ {
+ Activation activation;
+ float cell_threshold;
+ float projection_threshold;
+ bool time_major;
+ };
+
+public:
+ LSTM(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ std::string name() const override;
+ OpCode opcode() const final { return OpCode::LSTM; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_LSTM_H__
diff --git a/runtime/onert/core/include/ir/operation/LocalResponseNormalization.h b/runtime/onert/core/include/ir/operation/LocalResponseNormalization.h
new file mode 100644
index 000000000..2946cfbad
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/LocalResponseNormalization.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__
+#define __ONERT_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class LocalResponseNormalization : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ int radius;
+ float bias;
+ float alpha;
+ float beta;
+ };
+
+public:
+ LocalResponseNormalization(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::LocalResponseNormalization; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__
diff --git a/runtime/onert/core/include/ir/operation/LogSoftmax.h b/runtime/onert/core/include/ir/operation/LogSoftmax.h
new file mode 100644
index 000000000..391b4ba4a
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/LogSoftmax.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_LOGSOFTMAX_H__
+#define __ONERT_IR_OPERATION_LOGSOFTMAX_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class LogSoftmax : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ float beta;
+ int axis;
+ };
+
+public:
+ LogSoftmax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::LogSoftmax; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_LOGSOFTMAX_H__
diff --git a/runtime/onert/core/include/ir/operation/LowerInfo.h b/runtime/onert/core/include/ir/operation/LowerInfo.h
new file mode 100644
index 000000000..7ef53b8c7
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/LowerInfo.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_LOWER_INFO_H__
+#define __ONERT_IR_OPERATION_LOWER_INFO_H__
+
+#include <string>
+
+#include <ir/operand/PermuteFactor.h>
+
+namespace onert
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class LowerInfo
+{
+public:
+ LowerInfo(const backend::Backend *backend, Layout layout);
+ const backend::Backend *backend() const { return _permute_factor.backend(); }
+ Layout layout() const { return _permute_factor.layout(); }
+
+private:
+ operand::PermuteFactor _permute_factor;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_LOWER_INFO_H__
diff --git a/runtime/onert/core/include/ir/operation/MatrixBandPart.h b/runtime/onert/core/include/ir/operation/MatrixBandPart.h
new file mode 100644
index 000000000..291826635
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/MatrixBandPart.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_MATRIX_BAND_PART_H__
+#define __ONERT_IR_OPERATION_MATRIX_BAND_PART_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class MatrixBandPart : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ NUM_LOWER_DIAG,
+ NUM_UPPER_DIAG,
+ };
+
+public:
+ MatrixBandPart(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::MatrixBandPart; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_MATRIX_BAND_PART_H__
diff --git a/runtime/onert/core/include/ir/operation/OneHot.h b/runtime/onert/core/include/ir/operation/OneHot.h
new file mode 100644
index 000000000..6264cd15e
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/OneHot.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_ONEHOT_H__
+#define __ONERT_IR_OPERATION_ONEHOT_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class OneHot : public Operation
+{
+public:
+ enum Input
+ {
+ INDICES = 0,
+ DEPTH = 1,
+ ON_VALUE = 2,
+ OFF_VALUE = 3,
+ };
+
+ struct Param
+ {
+ int axis;
+ };
+
+public:
+ OneHot(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::OneHot; }
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_ONEHOT_H__
diff --git a/runtime/onert/core/include/ir/operation/PReLU.h b/runtime/onert/core/include/ir/operation/PReLU.h
new file mode 100644
index 000000000..2981ffc6a
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/PReLU.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_PRELU_H__
+#define __ONERT_IR_OPERATION_PRELU_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class PReLU : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ ALPHA = 1
+ };
+
+public:
+ PReLU(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::PReLU; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_PRELU_H__
diff --git a/runtime/onert/core/include/ir/operation/Pack.h b/runtime/onert/core/include/ir/operation/Pack.h
new file mode 100644
index 000000000..cf07541e0
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Pack.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __ONERT_IR_OPERATION_PACK_H__
+#define __ONERT_IR_OPERATION_PACK_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+class Pack : public Operation
+{
+public:
+ struct Param
+ {
+ int32_t num;
+ int32_t axis;
+ };
+
+public:
+ Pack(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Pack; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+} // namespace operation
+} // namespace ir
+} // namespace onert
+#endif // __ONERT_IR_OPERATION_PACK_H__
diff --git a/runtime/onert/core/include/ir/operation/Pad.h b/runtime/onert/core/include/ir/operation/Pad.h
new file mode 100644
index 000000000..00481cd50
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Pad.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_PAD_H__
+#define __ONERT_IR_OPERATION_PAD_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Pad : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ PAD = 1,
+ VALUE = 2
+ };
+
+public:
+ Pad(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Pad; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_PAD_H__
diff --git a/runtime/onert/core/include/ir/operation/Permute.h b/runtime/onert/core/include/ir/operation/Permute.h
new file mode 100644
index 000000000..10f09b9a0
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Permute.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_PERMUTE_H__
+#define __ONERT_IR_OPERATION_PERMUTE_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace backend
+{
+class BackendContext;
+} // namespace backend
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Permute : public Operation
+{
+public:
+ enum class Type
+ {
+ NHWC_TO_NCHW,
+ NCHW_TO_NHWC,
+ COPY
+ };
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Permute; }
+
+public:
+ Permute(const OperandIndex &input, const OperandIndex &output, Type type);
+
+public:
+ Type getPermuteType() const { return _type; }
+
+private:
+ Type _type;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_PERMUTE_H__
diff --git a/runtime/onert/core/include/ir/operation/Pool2D.h b/runtime/onert/core/include/ir/operation/Pool2D.h
new file mode 100644
index 000000000..22425b4c2
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Pool2D.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_POOL2D_H__
+#define __ONERT_IR_OPERATION_POOL2D_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+#include "ir/Padding.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Pool2D : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ enum class PoolType
+ {
+ AVG,
+ L2,
+ MAX,
+ };
+
+ struct Param
+ {
+ PoolType op_type;
+ uint32_t kh;
+ uint32_t kw;
+ Stride stride;
+ Padding padding;
+ Activation activation;
+ };
+
+public:
+ Pool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ std::string name() const override;
+ OpCode opcode() const final { return OpCode::Pool2D; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_POOL2D_H__
diff --git a/runtime/onert/core/include/ir/operation/Pow.h b/runtime/onert/core/include/ir/operation/Pow.h
new file mode 100644
index 000000000..ca28ddfe7
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Pow.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_POW_H__
+#define __ONERT_IR_OPERATION_POW_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Pow : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+public:
+ Pow(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Pow; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_POW_H__
diff --git a/runtime/onert/core/include/ir/operation/RNN.h b/runtime/onert/core/include/ir/operation/RNN.h
new file mode 100644
index 000000000..087075da2
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/RNN.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __ONERT_IR_OPERATION_RNN_H__
+#define __ONERT_IR_OPERATION_RNN_H__
+
+#include "ir/InternalType.h"
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class RNN : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ WEIGHTS = 1,
+ RECURRENT_WEIGHTS = 2,
+ BIAS = 3,
+ HIDDEN_STATE_IN = 4
+ };
+
+ enum Output
+ {
+ OUTPUT = 0,
+ HIDDEN_STATE_OUT = 1
+ };
+
+ struct Param
+ {
+ Activation activation;
+ };
+
+public:
+ RNN(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::RNN; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_RNN_H__
diff --git a/runtime/onert/core/include/ir/operation/Range.h b/runtime/onert/core/include/ir/operation/Range.h
new file mode 100644
index 000000000..81e170be9
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Range.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_RANGE_H__
+#define __ONERT_IR_OPERATION_RANGE_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Range : public Operation
+{
+public:
+ enum Input
+ {
+ START = 0,
+ LIMIT = 1,
+ DELTA = 2
+ };
+
+public:
+ Range(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Range; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_RANGE_H__
diff --git a/runtime/onert/core/include/ir/operation/Rank.h b/runtime/onert/core/include/ir/operation/Rank.h
new file mode 100644
index 000000000..2fd24ce23
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Rank.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_RANK_H__
+#define __ONERT_IR_OPERATION_RANK_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Rank : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Rank(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Rank; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_RANK_H__
diff --git a/runtime/onert/core/include/ir/operation/Reduce.h b/runtime/onert/core/include/ir/operation/Reduce.h
new file mode 100644
index 000000000..26bcf5ec9
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Reduce.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_REDUCE_H__
+#define __ONERT_IR_OPERATION_REDUCE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Reduce : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ AXES = 1
+ };
+
+ enum class ReduceType
+ {
+ ALL,
+ ANY,
+ MAX,
+ MEAN,
+ MIN,
+ PROD,
+ SUM
+ };
+
+ struct Param
+ {
+ ReduceType reduce_type;
+ bool keep_dims;
+ };
+
+public:
+ Reduce(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ std::string name() const override;
+ OpCode opcode() const final { return OpCode::Reduce; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_REDUCE_ALL_H__
diff --git a/runtime/onert/core/include/ir/operation/Reshape.h b/runtime/onert/core/include/ir/operation/Reshape.h
new file mode 100644
index 000000000..c2c0e8c99
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Reshape.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_RESHAPE_H__
+#define __ONERT_IR_OPERATION_RESHAPE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Reshape : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ SHAPE = 1
+ };
+
+ struct Param
+ {
+ std::vector<int32_t> new_shape;
+ };
+
+public:
+ Reshape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Reshape; }
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_RESHAPE_H__
diff --git a/runtime/onert/core/include/ir/operation/ResizeBilinear.h b/runtime/onert/core/include/ir/operation/ResizeBilinear.h
new file mode 100644
index 000000000..ab330c826
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ResizeBilinear.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_RESIZE_BILINEAR_H__
+#define __ONERT_IR_OPERATION_RESIZE_BILINEAR_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ResizeBilinear : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ SIZE = 1,
+ };
+
+ struct Param
+ {
+ // If the input SIZE exists in inputs, height_out and width_out are not set. Ignore these params
+ int32_t height_out;
+ int32_t width_out;
+ bool align_corners;
+ bool half_pixel_centers;
+ };
+
+public:
+ ResizeBilinear(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ResizeBilinear; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_RESIZE_BILINEAR_H__
diff --git a/runtime/onert/core/include/ir/operation/ResizeNearestNeighbor.h b/runtime/onert/core/include/ir/operation/ResizeNearestNeighbor.h
new file mode 100644
index 000000000..10827803e
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/ResizeNearestNeighbor.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_RESIZE_NEAREST_NEIGHBOR_H__
+#define __ONERT_IR_OPERATION_RESIZE_NEAREST_NEIGHBOR_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class ResizeNearestNeighbor : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ SIZE = 1,
+ };
+
+ struct Param
+ {
+ // If the input SIZE exists in inputs, Be height_out and width_out not set. Ignore these params
+ int32_t height_out;
+ int32_t width_out;
+ bool align_corners;
+ };
+
+public:
+ ResizeNearestNeighbor(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ResizeNearestNeighbor; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_RESIZE_NEAREST_NEIGHBOR_H__
diff --git a/runtime/onert/core/include/ir/operation/Reverse.h b/runtime/onert/core/include/ir/operation/Reverse.h
new file mode 100644
index 000000000..3d7f3fc89
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Reverse.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_REVERSE_H__
+#define __ONERT_IR_OPERATION_REVERSE_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Reverse : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ AXIS = 1
+ };
+
+public:
+ Reverse(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Reverse; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_REVERSE_H__
diff --git a/runtime/onert/core/include/ir/operation/Select.h b/runtime/onert/core/include/ir/operation/Select.h
new file mode 100644
index 000000000..33bf67886
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Select.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_SELECT_H__
+#define __ONERT_IR_OPERATION_SELECT_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Select : public Operation
+{
+public:
+ enum Input
+ {
+ CONDITION = 0,
+ INPUT_TRUE = 1,
+ INPUT_FALSE = 2
+ };
+
+public:
+ Select(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Select; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_SELECT_H__
diff --git a/runtime/onert/core/include/ir/operation/Shape.h b/runtime/onert/core/include/ir/operation/Shape.h
new file mode 100644
index 000000000..4dea7e424
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Shape.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_SHAPE_H__
+#define __ONERT_IR_OPERATION_SHAPE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Shape : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Shape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Shape; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_SHAPE_H__
diff --git a/runtime/onert/core/include/ir/operation/Slice.h b/runtime/onert/core/include/ir/operation/Slice.h
new file mode 100644
index 000000000..c86a9893a
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Slice.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_SLICE_H__
+#define __ONERT_IR_OPERATION_SLICE_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Slice : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ BEGINS = 1,
+ SIZES = 2,
+ };
+
+public:
+ Slice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Slice; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_SLICE_H__
diff --git a/runtime/onert/core/include/ir/operation/Softmax.h b/runtime/onert/core/include/ir/operation/Softmax.h
new file mode 100644
index 000000000..db7ae910e
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Softmax.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_SOFTMAX_H__
+#define __ONERT_IR_OPERATION_SOFTMAX_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Softmax : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ float beta;
+ };
+
+public:
+ Softmax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Softmax; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_SOFTMAX_H__
diff --git a/runtime/onert/core/include/ir/operation/SpaceToBatchND.h b/runtime/onert/core/include/ir/operation/SpaceToBatchND.h
new file mode 100644
index 000000000..99928ff24
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/SpaceToBatchND.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_SPACE_TO_BATCH_ND_H__
+#define __ONERT_IR_OPERATION_SPACE_TO_BATCH_ND_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class SpaceToBatchND : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ BLOCK_SIZE = 1,
+ PADDINGS = 2
+ };
+
+public:
+ SpaceToBatchND(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::SpaceToBatchND; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_SPACE_TO_BATCH_ND_H__
diff --git a/runtime/onert/core/include/ir/operation/SpaceToDepth.h b/runtime/onert/core/include/ir/operation/SpaceToDepth.h
new file mode 100644
index 000000000..6c8b09130
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/SpaceToDepth.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_SPACE_TO_DEPTH_H__
+#define __ONERT_IR_OPERATION_SPACE_TO_DEPTH_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class SpaceToDepth : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ std::int32_t block_size;
+ };
+
+public:
+ SpaceToDepth(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::SpaceToDepth; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_SPACE_TO_DEPTH_H__
diff --git a/runtime/onert/core/include/ir/operation/Split.h b/runtime/onert/core/include/ir/operation/Split.h
new file mode 100644
index 000000000..c415941a4
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Split.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __ONERT_IR_OPERATION_SPLIT_H__
+#define __ONERT_IR_OPERATION_SPLIT_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+class Split : public Operation
+{
+public:
+ enum Input
+ {
+ AXIS = 0,
+ INPUT = 1,
+ };
+
+ struct Param
+ {
+ int num_splits;
+ };
+
+public:
+ Split(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Split; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+} // namespace operation
+} // namespace ir
+} // namespace onert
+#endif // __ONERT_IR_OPERATION_SPLIT_H__
diff --git a/runtime/onert/core/include/ir/operation/SplitV.h b/runtime/onert/core/include/ir/operation/SplitV.h
new file mode 100644
index 000000000..99a06ee7f
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/SplitV.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __ONERT_IR_OPERATION_SPLIT_V_H__
+#define __ONERT_IR_OPERATION_SPLIT_V_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+class SplitV : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ SIZE_SPLITS = 1,
+ SPLIT_DIM = 2
+ };
+
+ struct Param
+ {
+ int num_splits;
+ };
+
+public:
+ SplitV(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::SplitV; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+} // namespace operation
+} // namespace ir
+} // namespace onert
+#endif // __ONERT_IR_OPERATION_SPLIT_V_H__
diff --git a/runtime/onert/core/include/ir/operation/SquaredDifference.h b/runtime/onert/core/include/ir/operation/SquaredDifference.h
new file mode 100644
index 000000000..392b11448
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/SquaredDifference.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_SQUARED_DIFFERENCE_H__
+#define __ONERT_IR_OPERATION_SQUARED_DIFFERENCE_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class SquaredDifference : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+public:
+ SquaredDifference(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::SquaredDifference; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_SQUARED_DIFFERENCE_H__
diff --git a/runtime/onert/core/include/ir/operation/Squeeze.h b/runtime/onert/core/include/ir/operation/Squeeze.h
new file mode 100644
index 000000000..c370472b7
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Squeeze.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_SQUEEZE_H__
+#define __ONERT_IR_OPERATION_SQUEEZE_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Squeeze : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ // Please see tensorflow/lite/c/builtin_op_data.h and squeeze.cc.
+ // tensorflow lite supports only for ndim <= 8.
+ int dims[8];
+ int ndim;
+ };
+
+public:
+ Squeeze(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Squeeze; }
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_SQUEEZE_H__
diff --git a/runtime/onert/core/include/ir/operation/StatelessRandomUniform.h b/runtime/onert/core/include/ir/operation/StatelessRandomUniform.h
new file mode 100644
index 000000000..112a748fd
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/StatelessRandomUniform.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_STATELESS_RANDOM_UNIFORM_H__
+#define __ONERT_IR_OPERATION_STATELESS_RANDOM_UNIFORM_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class StatelessRandomUniform : public Operation
+{
+public:
+ enum Input
+ {
+ SHAPE = 0,
+ SEED = 1
+ };
+
+public:
+ StatelessRandomUniform(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::StatelessRandomUniform; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_STATELESS_RANDOM_UNIFORM_H__
diff --git a/runtime/onert/core/include/ir/operation/StridedSlice.h b/runtime/onert/core/include/ir/operation/StridedSlice.h
new file mode 100644
index 000000000..4a5e06410
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/StridedSlice.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_STRIDED_SLICE_H__
+#define __ONERT_IR_OPERATION_STRIDED_SLICE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class StridedSlice : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ STARTS = 1,
+ ENDS = 2,
+ STRIDES = 3
+ };
+
+ struct Param
+ {
+ int32_t begin_mask;
+ int32_t end_mask;
+ int32_t shrink_axis_mask;
+ };
+
+public:
+ StridedSlice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::StridedSlice; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_STRIDED_SLICE_H__
diff --git a/runtime/onert/core/include/ir/operation/Tile.h b/runtime/onert/core/include/ir/operation/Tile.h
new file mode 100644
index 000000000..388c452c8
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Tile.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_TILE_H__
+#define __ONERT_IR_OPERATION_TILE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Tile : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ MULTIPLES,
+ };
+
+public:
+ Tile(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Tile; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_TILE_H__
diff --git a/runtime/onert/core/include/ir/operation/TopKV2.h b/runtime/onert/core/include/ir/operation/TopKV2.h
new file mode 100644
index 000000000..179a599ca
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/TopKV2.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_TOPK_V2_H__
+#define __ONERT_IR_OPERATION_TOPK_V2_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class TopKV2 : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT
+ };
+
+ enum Output
+ {
+ OUTPUT_VALUES = 0,
+ OUTPUT_INDICES,
+ };
+
+ struct Param
+ {
+ std::int32_t k;
+ };
+
+public:
+ TopKV2(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::TopKV2; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_TOPK_V2_H__
diff --git a/runtime/onert/core/include/ir/operation/Transpose.h b/runtime/onert/core/include/ir/operation/Transpose.h
new file mode 100644
index 000000000..665c9bbce
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Transpose.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_TRANSPOSE_H__
+#define __ONERT_IR_OPERATION_TRANSPOSE_H__
+
+#include "ir/Operation.h"
+
+#include <utility>
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class Transpose : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0, // for an n-D tensor, specifying the tensor to be transposed.
+ PERMUTATION = 1,
+ };
+
+public:
+ Transpose(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Transpose; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_TRANSPOSE_H__
diff --git a/runtime/onert/core/include/ir/operation/TransposeConv.h b/runtime/onert/core/include/ir/operation/TransposeConv.h
new file mode 100644
index 000000000..05137ccf8
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/TransposeConv.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_TRANSPOSE_CONV_H__
+#define __ONERT_IR_OPERATION_TRANSPOSE_CONV_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+#include "ir/Padding.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class TransposeConv : public Operation
+{
+public:
+ enum Input
+ {
+ OUTPUT_SHAPE = 0,
+ KERNEL,
+ INPUT
+ };
+
+ struct Param
+ {
+ Padding padding;
+ Stride stride;
+ };
+
+public:
+ TransposeConv(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::TransposeConv; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_TRANSPOSE_CONV_H__
diff --git a/runtime/onert/core/include/ir/operation/Unpack.h b/runtime/onert/core/include/ir/operation/Unpack.h
new file mode 100644
index 000000000..092583a97
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/Unpack.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __ONERT_IR_OPERATION_UNPACK_H__
+#define __ONERT_IR_OPERATION_UNPACK_H__
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+class Unpack : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ int32_t num;
+ int32_t axis;
+ };
+
+public:
+ Unpack(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Unpack; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+} // namespace operation
+} // namespace ir
+} // namespace onert
+#endif // __ONERT_IR_OPERATION_UNPACK_H__
diff --git a/runtime/onert/core/include/ir/operation/While.h b/runtime/onert/core/include/ir/operation/While.h
new file mode 100644
index 000000000..cf310d596
--- /dev/null
+++ b/runtime/onert/core/include/ir/operation/While.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_WHILE_H__
+#define __ONERT_IR_OPERATION_WHILE_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+class While : public Operation
+{
+public:
+ struct Param
+ {
+ SubgraphIndex cond_subg_index;
+ SubgraphIndex body_subg_index;
+ };
+
+public:
+ While(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::While; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_WHILE_H__
diff --git a/runtime/onert/core/include/util/Config.lst b/runtime/onert/core/include/util/Config.lst
new file mode 100644
index 000000000..30f211011
--- /dev/null
+++ b/runtime/onert/core/include/util/Config.lst
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONFIG
+#error Define CONFIG before including this file
+#endif
+
+// Name | Type | Default
+CONFIG(GRAPH_DOT_DUMP , int , "0")
+CONFIG(BACKENDS , std::string , "cpu;acl_cl;acl_neon;bcq") // FIXME Remove bcq
+CONFIG(OP_BACKEND_ALLOPS , std::string , "")
+CONFIG(OP_BACKEND_MAP , std::string , "")
+CONFIG(DISABLE_COMPILE , bool , "0")
+CONFIG(ONERT_LOG_ENABLE , bool , "0")
+CONFIG(CPU_MEMORY_PLANNER , std::string , "WIC")
+CONFIG(EXECUTOR , std::string , "Linear")
+CONFIG(ACL_LAYOUT , std::string , "none")
+CONFIG(NCNN_LAYOUT , std::string , "NCHW")
+CONFIG(PROFILING_MODE , bool , "0")
+CONFIG(USE_SCHEDULER , bool , "0")
+CONFIG(OP_SEQ_MAX_NODE , int , "0")
+CONFIG(TRACE_FILEPATH , std::string , "")
+CONFIG(FP16_ENABLE , bool , "0")
+CONFIG(RUY_THREADS , int , "-1")
+CONFIG(USE_MMAPED_DATA , bool , "0")
+
+// Auto-generate all operations
+
+#define OP(InternalName) \
+ CONFIG(OP_BACKEND_ ## InternalName, std::string, "")
+#include "ir/Operations.lst"
+#undef OP
+
diff --git a/runtime/onert/core/include/util/ConfigSource.h b/runtime/onert/core/include/util/ConfigSource.h
new file mode 100644
index 000000000..b6a8144fd
--- /dev/null
+++ b/runtime/onert/core/include/util/ConfigSource.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_CONFIG_SOURCE_H__
+#define __ONERT_UTIL_CONFIG_SOURCE_H__
+
+#include <memory>
+
+#include "IConfigSource.h"
+
+namespace onert
+{
+namespace util
+{
+
+void config_source(std::unique_ptr<IConfigSource> &&source);
+
+bool toBool(const std::string &val);
+int toInt(const std::string &val);
+
+bool getConfigBool(const std::string &key);
+int getConfigInt(const std::string &key);
+std::string getConfigString(const std::string &key);
+
+} // namespace util
+} // namespace onert
+
+namespace onert
+{
+namespace util
+{
+namespace config
+{
+
+#define CONFIG(Name, Type, Default) extern const char *Name;
+
+#include "Config.lst"
+
+#undef CONFIG
+
+} // namespace config
+} // namespace util
+} // namespace onert
+
+#endif // __ONERT_UTIL_CONFIG_SOURCE_H__
diff --git a/runtime/onert/core/include/util/EnvConfigSource.h b/runtime/onert/core/include/util/EnvConfigSource.h
new file mode 100644
index 000000000..8c5d0e8e9
--- /dev/null
+++ b/runtime/onert/core/include/util/EnvConfigSource.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_ENV_CONFIG_SOURCE_H__
+#define __ONERT_UTIL_ENV_CONFIG_SOURCE_H__
+
+#include <unordered_map>
+
+#include "util/GeneralConfigSource.h"
+
+namespace onert
+{
+namespace util
+{
+
+class EnvConfigSource final : public GeneralConfigSource
+{
+public:
+ std::string get(const std::string &key) const override;
+
+private:
+ std::unordered_map<std::string, std::string> _default_attributes;
+};
+
+} // namespace util
+} // namespace onert
+
+#endif // __ONERT_UTIL_ENV_CONFIG_SOURCE_H__
diff --git a/runtime/onert/core/include/util/Exceptions.h b/runtime/onert/core/include/util/Exceptions.h
new file mode 100644
index 000000000..fc3fa0f64
--- /dev/null
+++ b/runtime/onert/core/include/util/Exceptions.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_ONERTEXCEPTION_H__
+#define __ONERT_UTIL_ONERTEXCEPTION_H__
+
+#include <string>
+
+namespace onert
+{
+
+class OnertException : public std::exception
+{
+public:
+ OnertException(const std::string &msg) : _msg{msg} {}
+ OnertException(const std::string &tag, const std::string &msg) : _msg{tag + " : " + msg} {}
+
+ const char *what() const noexcept override { return _msg.c_str(); }
+
+private:
+ std::string _msg;
+};
+
+class InsufficientBufferSizeException : public OnertException
+{
+public:
+ InsufficientBufferSizeException(const std::string &msg)
+ : OnertException{"InsufficientBufferSize", msg}
+ {
+ }
+};
+
+} // namespace onert
+
+#endif // __ONERT_UTIL_ONERTEXCEPTION_H__
diff --git a/runtime/onert/core/include/util/GeneralConfigSource.h b/runtime/onert/core/include/util/GeneralConfigSource.h
new file mode 100644
index 000000000..dedc820ec
--- /dev/null
+++ b/runtime/onert/core/include/util/GeneralConfigSource.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_GLOBAL_CONFIG_SOURCE_H__
+#define __ONERT_UTIL_GLOBAL_CONFIG_SOURCE_H__
+
+#include <unordered_map>
+
+#include "util/IConfigSource.h"
+
+namespace onert
+{
+namespace util
+{
+
+class GeneralConfigSource : public IConfigSource
+{
+public:
+ GeneralConfigSource() = default;
+
+ std::string get(const std::string &key) const override;
+ void set(const std::string &key, const std::string &val);
+
+private:
+ std::unordered_map<std::string, std::string> _map;
+};
+
+} // namespace util
+} // namespace onert
+
+#endif // __ONERT_UTIL_GLOBAL_CONFIG_SOURCE_H__
diff --git a/runtime/onert/core/include/util/IConfigSource.h b/runtime/onert/core/include/util/IConfigSource.h
new file mode 100644
index 000000000..07b09848a
--- /dev/null
+++ b/runtime/onert/core/include/util/IConfigSource.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_I_CONFIG_SOURCE_H__
+#define __ONERT_UTIL_I_CONFIG_SOURCE_H__
+
+#include <string>
+
+namespace onert
+{
+namespace util
+{
+
+struct IConfigSource
+{
+ /**
+ * @brief Destroy the IConfigSource object
+ */
+ virtual ~IConfigSource() = default;
+
+ /**
+ * @brief get the value for the matching key
+ *
+ * @param key string key to search
+ * @return string value associated with the key
+ */
+ virtual std::string get(const std::string &key) const = 0;
+};
+
+} // namespace util
+} // namespace onert
+
+#endif // __ONERT_UTIL_I_CONFIG_SOURCE_H__
diff --git a/runtime/onert/core/include/util/ITimer.h b/runtime/onert/core/include/util/ITimer.h
new file mode 100644
index 000000000..d5a4e1eb0
--- /dev/null
+++ b/runtime/onert/core/include/util/ITimer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_ITIMER_H__
+#define __ONERT_UTIL_ITIMER_H__
+
+#include <chrono>
+
+namespace onert
+{
+namespace util
+{
+
+class ITimer
+{
+public:
+ virtual void handleBegin() = 0;
+ virtual void handleEnd() = 0;
+ int getTime() { return _timer_res; };
+
+ virtual ~ITimer() = default;
+
+protected:
+ int _timer_res{0};
+};
+
+class CPUTimer : public ITimer
+{
+public:
+ void handleBegin() override { _start_time = std::chrono::steady_clock::now(); };
+
+ void handleEnd() override
+ {
+ const auto end_time = std::chrono::steady_clock::now();
+ _timer_res =
+ std::chrono::duration_cast<std::chrono::microseconds>(end_time - _start_time).count();
+ };
+
+private:
+ std::chrono::steady_clock::time_point _start_time; // in microseconds
+};
+
+} // namespace util
+} // namespace onert
+
+#endif // __ONERT_UTIL_ITIMER_H__
diff --git a/runtime/onert/core/include/util/Index.h b/runtime/onert/core/include/util/Index.h
new file mode 100644
index 000000000..e8f59282d
--- /dev/null
+++ b/runtime/onert/core/include/util/Index.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_INDEX_H__
+#define __ONERT_UTIL_INDEX_H__
+
+#include <functional>
+#include <limits>
+#include <stdint.h>
+#include <string>
+
+namespace onert
+{
+namespace util
+{
+
+/**
+ * @brief A wrapper class for unsigned integral Index
+ * NOTE : Max value of the underlying type is used as the invalid value
+ *
+ * @tparam T Underlying type. Must be unsigned integral type otherwise its behavior is undefined.
+ * @tparam DummyTag Dummy type to distinguish types with a same underlying type. Using an opaque
+ * type is recommended.
+ */
+template <typename T, typename DummyTag> class Index
+{
+private:
+ static const T UNDEFINED = std::numeric_limits<T>::max();
+
+public:
+ /**
+ * @brief Construct a new Index object
+ */
+ explicit Index(void) : _index{UNDEFINED} {}
+ /**
+ * @brief Construct a new Index object with a value in the underlying type
+ *
+ * @param o Value in the underlying type
+ */
+ explicit Index(const T o) : _index{o} {}
+ /**
+ * @brief Copy Constructor
+ *
+ * @param o Object to be copied
+ */
+ Index(const Index &o) = default;
+
+ /**
+ * @brief Assign a value in the underlying time
+ *
+ * @param o Value in the underlying type
+ * @return Index& Reference of this pointer
+ */
+ Index &operator=(const T o)
+ {
+ _index = o;
+ return *this;
+ }
+
+ /**
+ * @brief Copy assignment operator
+ *
+ * @param o Object to be copied
+ * @return Index& Reference of this pointer
+ */
+ Index &operator=(const Index &o) = default;
+
+ /**
+ * @brief Equality operator
+ *
+ * @param o The other value in the underlying type to compare
+ * @return true if underlying value is the same, false otherwise
+ */
+ bool operator==(T o) const { return _index == o; }
+ /**
+ * @brief Equality operator
+ *
+ * @param o The other object to compare
+ * @return true if underlying value is the same, false otherwise
+ */
+ bool operator==(const Index &o) const { return _index == o._index; }
+ /**
+ * @brief Inquality operator
+ *
+ * @param o The other value in the underlying type to compare
+ * @return true if underlying value is different, false otherwise
+ */
+ bool operator!=(T o) const { return !(*this == o); }
+ /**
+ * @brief Inquality operator
+ *
+ * @param o The other object to compare
+ * @return true if underlying value is different, false otherwise
+ */
+ bool operator!=(const Index &o) const { return !(*this == o); }
+
+ /**
+ * @brief Post increment operator
+ *
+ * @return Index Index before increment
+ */
+ Index operator++(int)
+ {
+ Index temp = *this;
+ _index++;
+ return temp;
+ }
+
+ /**
+ * @brief Check whether the value is valid or not
+ *
+ * @return true if valid, false otherwise
+ */
+ bool valid() const { return _index != UNDEFINED; }
+ /**
+ * @brief Check whether the value is undefined
+ *
+ * @return true if undefined, false otherwise
+ */
+ bool undefined() const { return _index == UNDEFINED; }
+ /**
+ * @brief Return underlying value
+ *
+ * @return T Underlying value
+ */
+ T value() const { return _index; }
+
+ friend std::ostream &operator<<(std::ostream &o, const Index &t)
+ {
+ if (t.undefined())
+ return o << std::string("undefined");
+ else
+ return o << t.value();
+ }
+
+private:
+ T _index;
+};
+
+} // namespace util
+} // namespace onert
+
+namespace std
+{
+
+template <typename T, typename Tag> struct hash<::onert::util::Index<T, Tag>>
+{
+ size_t operator()(const ::onert::util::Index<T, Tag> &index) const noexcept
+ {
+ return hash<T>()(index.value());
+ }
+};
+
+} // namespace std
+
+#endif // __ONERT_UTIL_INDEX_H__
diff --git a/runtime/onert/core/include/util/ObjectManager.h b/runtime/onert/core/include/util/ObjectManager.h
new file mode 100644
index 000000000..d2dd881a8
--- /dev/null
+++ b/runtime/onert/core/include/util/ObjectManager.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_OBJECT_MANAGER_H__
+#define __ONERT_UTIL_OBJECT_MANAGER_H__
+
+#include <unordered_map>
+#include <memory>
+#include <list>
+#include <functional>
+
+#include <memory>
+
+namespace onert
+{
+namespace util
+{
+
+/**
+ * @brief Class that owns objects and maps them with indices as a handle for them
+ *
+ */
+template <typename Index, typename Object> class ObjectManager
+{
+public:
+ ObjectManager() : _index_count{0u} {}
+
+public:
+ /**
+ * @brief Create an object with args and put it in the container with a new Index for that
+ *
+ * @param[in] args Arguments for creating Operand object
+ * @return Created index that is associated to the object
+ */
+ template <class... Args> Index emplace(Args &&... args)
+ {
+ auto index = generateIndex();
+ _objects.emplace(index, std::make_unique<Object>(std::forward<Args>(args)...));
+ return index;
+ }
+
+ /**
+ * @brief Put object in the container with a new Index for that
+ *
+ * @param[in] object Object to be pushed
+ * @return Created index that is associated to the object
+ */
+ Index push(std::unique_ptr<Object> &&object)
+ {
+ auto index = generateIndex();
+ _objects.emplace(index, std::move(object));
+ return index;
+ }
+
+ /**
+ * @brief Remove the object that is associated with the given index
+ *
+ * @param[in] index Index of the object to be removed
+ * @return N/A
+ */
+ void remove(const Index &index) { _objects.erase(index); }
+
+ /**
+ * @brief Get the object that is associated with the given index
+ *
+ * @param[in] index Index of the object to be returned
+ * @return Object
+ */
+ const Object &at(const Index &index) const { return *(_objects.at(index)); }
+ /**
+ * @brief Get the object that is associated with the given index
+ *
+ * @param[in] index Index of the object to be returned
+ * @return Object
+ */
+ Object &at(const Index &index) { return *(_objects.at(index)); }
+ /**
+ * @brief Get the object that is associated with the given index
+ *
+ * @param[in] index Index of the object to be returned
+ * @return true if such entry exists otherwise false
+ */
+ bool exist(const Index &index) const
+ {
+ auto it = _objects.find(index);
+ return it != _objects.end();
+ }
+ /**
+ * @brief Iterate over the container with given function
+ *
+ * @param[in] fn Function to be run for every container entry
+ * @return N/A
+ */
+ void iterate(const std::function<void(const Index &, const Object &)> &fn) const
+ {
+ for (const auto &e : _objects)
+ {
+ fn(e.first, *e.second);
+ }
+ }
+ /**
+ * @brief Iterate over the container with given function
+ *
+ * @param[in] fn Function to be run for every container entry
+ * @return N/A
+ */
+ void iterate(const std::function<void(const Index &, Object &)> &fn)
+ {
+ // TODO Remove this workaround
+ // This implementation is a workaround in case of adding operands while iteration
+ std::list<Index> l;
+
+ for (auto &e : _objects)
+ {
+ l.push_back(e.first);
+ }
+
+ for (auto index : l)
+ {
+ fn(index, *_objects[index]);
+ }
+ }
+
+private:
+ Index generateIndex() { return Index{_index_count++}; }
+
+protected:
+ std::unordered_map<Index, std::unique_ptr<Object>> _objects;
+ uint32_t _index_count;
+};
+
+} // namespace util
+} // namespace onert
+
+#endif // __ONERT_UTIL_OBJECT_MANAGER_H__
diff --git a/runtime/onert/core/include/util/Set.h b/runtime/onert/core/include/util/Set.h
new file mode 100644
index 000000000..ee4062d25
--- /dev/null
+++ b/runtime/onert/core/include/util/Set.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Set.h
+ * @brief This file contains onert::util::Set class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __ONERT_UTIL_SET_H__
+#define __ONERT_UTIL_SET_H__
+
+#include <cassert>
+#include <unordered_set>
+
+namespace onert
+{
+namespace util
+{
+
+/**
+ * @brief Class for set of custom element
+ & @tparam Element Key type of Set
+ */
+template <typename Element> class Set
+{
+public:
+ /**
+ * @brief Construct default Set object.
+ */
+ Set() = default;
+ /**
+ * @brief Construct Set object by copy semantics.
+ */
+ Set(const Set<Element> &) = default;
+ /**
+ * @brief Construct move Set object by move semantics.
+ */
+ Set(Set<Element> &&) = default;
+
+public:
+ /**
+ * @brief Add a given element to the set
+ *
+ * @param e Element added
+ */
+ void add(const Element &e) { _set.insert(e); }
+ /**
+ * @brief remove a given element from the set
+ *
+ * @param e Element removed
+ */
+ void remove(const Element &e) { _set.erase(e); }
+ /**
+ * @brief Get size of the set
+ *
+ * @return The size of the set
+ */
+ uint32_t size() const { return static_cast<uint32_t>(_set.size()); }
+ /**
+ * @brief Get whether the set is empty
+ *
+ * @return Whether the set is empty
+ */
+ bool empty() const { return _set.empty(); }
+ /**
+ * @brief Get whether a given element exists in the set
+ *
+ * @param e A given element
+ *
+ * @return Whether a given element exists in the set
+ */
+ bool contains(const Element &e) const { return _set.find(e) != _set.end(); }
+ /**
+ * @brief Get first element of the set
+ *
+ * @return first element of the set
+ */
+ const Element &getOnlyElement() const
+ {
+ assert(_set.size() == 1u);
+ return *_set.begin();
+ }
+
+public:
+ /**
+ * @brief operator overloading function for `|`
+ *
+ * @return A set with two sets combined
+ */
+ Set<Element> operator|(const Set<Element> &other) const // Union
+ {
+ auto ret = *this;
+ for (auto e : other)
+ {
+ ret.add(e);
+ }
+ return ret;
+ }
+ /**
+ * @brief operator overloading function for `&`
+ *
+ * @return A set of elements that overlap in two sets
+ */
+ Set<Element> operator&(const Set<Element> &other) const // Intersect
+ {
+ Set<Element> ret;
+ for (auto e : other)
+ {
+ if (contains(e))
+ {
+ ret.add(e);
+ }
+ }
+ return ret;
+ }
+ /**
+ * @brief operator overloading function for `-`
+ *
+ * @return A set of subtracted from another set
+ */
+ Set<Element> operator-(const Set<Element> &other) const // Minus
+ {
+ auto ret = *this;
+ for (auto e : other)
+ {
+ ret.remove(e);
+ }
+ return ret;
+ }
+
+public:
+ /**
+ * @brief begin() of const_iterator for this class
+ *
+ * @return The first iterator of the set
+ */
+ typename std::unordered_set<Element>::const_iterator begin() const { return _set.begin(); }
+ /**
+ * @brief end() of const_iterator for this class
+ *
+ * @return The last iterator of the set
+ */
+ typename std::unordered_set<Element>::const_iterator end() const { return _set.end(); }
+
+private:
+ std::unordered_set<Element> _set;
+};
+
+} // namespace util
+} // namespace onert
+
+#endif // __ONERT_UTIL_SET_H__
diff --git a/runtime/onert/core/include/util/ShapeInference.h b/runtime/onert/core/include/util/ShapeInference.h
new file mode 100644
index 000000000..701b835d2
--- /dev/null
+++ b/runtime/onert/core/include/util/ShapeInference.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_GRAPH_SHAPE_INFERENCE_H__
+#define __ONERT_GRAPH_SHAPE_INFERENCE_H__
+
+#include "Utils.h"
+
+#include "ir/operation/Concat.h"
+#include "ir/operation/Conv2D.h"
+#include "ir/operation/DepthwiseConv2D.h"
+#include "ir/operation/Pool2D.h"
+#include "ir/operation/Reshape.h"
+#include "ir/operation/StridedSlice.h"
+#include "compiler/LoweredGraph.h"
+#include "ir/Index.h"
+#include "ir/Layout.h"
+#include "ir/OperationVisitor.h"
+#include "backend/IDynamicTensorManager.h"
+#include "backend/ITensor.h"
+#include "backend/ITensorRegistry.h"
+
+namespace onert
+{
+namespace shape_inference
+{
+
+using Shapes = std::vector<ir::Shape>;
+
+// Define shape calculation for operations. List them in alphabetic order.
+
+ir::Shape inferArgMaxShape(const ir::Shape &input_shape, int axis, int rank);
+
+ir::Shape inferBatchMatMulShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape,
+ const ir::operation::BatchMatMul::Param &param);
+
+ir::Shape inferBCQFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &cluster_shape,
+ const int32_t *cluster_buf);
+
+ir::Shape inferBCQGatherShape(const ir::Shape &indices_shape, const ir::Shape &cluster_shape,
+ const int32_t *cluster_buf, int rank,
+ const ir::operation::BCQGather::Param &param);
+
+ir::Shape inferBroadcastToShape(const ir::Shape shp_shape, const int32_t *shp_buf);
+
+ir::Shape inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param &param);
+
+ir::Shape inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::Conv2D::Param &param,
+ ir::Layout layout = ir::Layout::NHWC);
+
+ir::Shape inferDepthwiseConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::DepthwiseConv2D::Param &param,
+ ir::Layout layout = ir::Layout::NHWC);
+
+ir::Shape inferEltwiseShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape);
+
+ir::Shape inferExpandDimsShape(const ir::Shape &in_shape, int32_t axis);
+
+ir::Shape inferFillShape(const ir::Shape &in_shape, const int32_t *in_buf);
+
+ir::Shape inferFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &ker_shape);
+
+ir::Shape inferGatherShape(const ir::Shape &input_shape, const ir::Shape &indices_shape, int axis,
+ int rank);
+
+ir::Shape inferOnehotShape(const ir::Shape &input_shape, const int depth, int axis);
+
+ir::Shape inferPackShape(const ir::Shape &input_shape, int axis, int rank, int num);
+
+ir::Shape inferPadShape(const ir::Shape &in_shape, const int32_t *pad_buf, const size_t num_pads);
+
+ir::Shape inferPoolShape(const ir::Shape &in_shape, const ir::operation::Pool2D::Param &param,
+ ir::Layout layout = ir::Layout::NHWC);
+
+template <typename T> ir::Shape inferRangeShape(T start_val, T limit_val, T delta_val);
+
+ir::Shape inferReshapeShape(const int32_t *shape_buf, const int32_t shape_num_elements,
+ const size_t total_num_elements);
+
+ir::Shape inferReduceShape(const ir::Shape &input_shape, const std::vector<int> &axes,
+ bool keep_dims);
+
+template <float *> ir::Shape inferRangeShape(float *start_val, float *limit_val, float *delta_val);
+
+template <typename T> ir::Shape inferRangeShape(T start_val, T limit_val, T delta_val);
+
+ir::Shape inferResizeBilinearShape(const ir::Shape &in_shape, const int32_t output_height,
+ const int32_t output_width);
+
+ir::Shape inferSelectShape(const ir::Shape &input_cond_shape, const ir::Shape &input_true_shape,
+ const ir::Shape &input_false_shape);
+
+ir::Shape inferSliceShape(const ir::Shape &input_shape, const int32_t *begins_buf,
+ const int32_t *sizes_buf);
+
+ir::Shape inferSpaceToBatchNDShape(const ir::Shape &input_shape, const ir::Shape &block_shape_shape,
+ const ir::Shape &padding_shape, const int32_t *block_shape_buf,
+ const int32_t *padding_buf);
+
+ir::Shape inferSplitShape(const ir::Shape input_shape, int axis_value, int num_splits);
+
+ir::Shape inferSqueezeShape(const ir::Shape &in_shape, const ir::operation::Squeeze::Param &param);
+
+struct StridedSliceParams
+{
+ int8_t start_indices_count;
+ int16_t start_indices[4];
+ int8_t stop_indices_count;
+ int16_t stop_indices[4];
+ int8_t strides_count;
+ int16_t strides[4];
+
+ int16_t begin_mask;
+ int16_t ellipsis_mask;
+ int16_t end_mask;
+ int16_t new_axis_mask;
+ int16_t shrink_axis_mask;
+};
+
+template <typename T>
+StridedSliceParams buildStridedSliceParams(const T *begin, const T *end, const T *strides,
+ const uint32_t begin_mask, const uint32_t end_mask,
+ const uint32_t shrink_axis_mask, const uint8_t rank);
+
+ir::Shape inferStridedSliceShape(const ir::Shape &input_shape, const StridedSliceParams &op_params,
+ uint32_t rank);
+
+ir::Shape inferTileShape(const ir::Shape &in_shape, const int32_t *multiplier_buf,
+ const int32_t multiplier_size);
+
+ir::Shape inferTransposeShape(const ir::Shape &in_shape, const int32_t *perm_buf,
+ const int32_t rank);
+
+ir::Shape inferUnpackShape(const ir::Shape &input_shape, int axis, int rank);
+
+} // namespace shape_inference
+} // namespace onert
+
+#endif // __ONERT_GRAPH_SHAPE_INFERENCE_H__
diff --git a/runtime/onert/core/include/util/Utils.h b/runtime/onert/core/include/util/Utils.h
new file mode 100644
index 000000000..8a4eea32b
--- /dev/null
+++ b/runtime/onert/core/include/util/Utils.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Utils.h
+ * @brief This file contains utility macro
+ */
+
+#ifndef __ONERT_UTIL_UTILS_H__
+#define __ONERT_UTIL_UTILS_H__
+
+#include "ir/Coordinates.h"
+#include "ir/Shape.h"
+
+#define UNUSED_RELEASE(a) (void)(a)
+
+template <size_t from, size_t to, typename Enable = void> struct ForEachDimension
+{
+ template <typename L, typename... Args>
+ static void unroll(const onert::ir::Shape &shape, onert::ir::Coordinates &coords,
+ L &&lambda_function, Args &&... args)
+ {
+ static_assert(from < to, "from must not be less than to");
+ assert(static_cast<int>(to) <= shape.rank());
+ const auto &d = shape.dim(from);
+
+ for (auto v = 0; v < d; v++)
+ {
+ coords.set(from, v);
+ ForEachDimension<from + 1, to>::unroll(shape, coords, std::forward<L>(lambda_function),
+ std::forward<Args>(args)...);
+ }
+ }
+};
+
+template <size_t from, size_t to>
+struct ForEachDimension<from, to, typename std::enable_if<from == to>::type>
+{
+ template <typename L, typename... Args>
+ static void unroll(const onert::ir::Shape &shape, onert::ir::Coordinates &coords,
+ L &&lambda_function, Args &&... args)
+ {
+ UNUSED_RELEASE(shape);
+ assert(static_cast<int>(to) <= shape.rank());
+ lambda_function(coords, std::forward<Args>(args)...);
+ }
+};
+
+template <typename L, typename... Args>
+inline void ShapeLoop(const onert::ir::Shape &shape, L &&lambda_function, Args &&... args)
+{
+ assert(shape.rank() > 0);
+ for (auto i = 0; i < shape.rank(); ++i)
+ {
+ assert(shape.dim(i) > 0);
+ }
+
+ onert::ir::Coordinates coords;
+ switch (shape.rank())
+ {
+ case 0:
+ coords.set(0, 0);
+ ForEachDimension<0, 0>::unroll(shape, coords, std::forward<L>(lambda_function),
+ std::forward<Args>(args)...);
+ break;
+ case 1:
+ ForEachDimension<0, 1>::unroll(shape, coords, std::forward<L>(lambda_function),
+ std::forward<Args>(args)...);
+ break;
+ case 2:
+ ForEachDimension<0, 2>::unroll(shape, coords, std::forward<L>(lambda_function),
+ std::forward<Args>(args)...);
+ break;
+ case 3:
+ ForEachDimension<0, 3>::unroll(shape, coords, std::forward<L>(lambda_function),
+ std::forward<Args>(args)...);
+ break;
+ case 4:
+ ForEachDimension<0, 4>::unroll(shape, coords, std::forward<L>(lambda_function),
+ std::forward<Args>(args)...);
+ break;
+ case 5:
+ ForEachDimension<0, 5>::unroll(shape, coords, std::forward<L>(lambda_function),
+ std::forward<Args>(args)...);
+ break;
+ case 6:
+ ForEachDimension<0, 6>::unroll(shape, coords, std::forward<L>(lambda_function),
+ std::forward<Args>(args)...);
+ break;
+ default:
+ assert(false && "ShapeLoop, 1 <= Shape'rank <= 6");
+ break;
+ }
+}
+#endif // __ONERT_UTIL_UTILS_H__
diff --git a/runtime/onert/core/include/util/logging.h b/runtime/onert/core/include/util/logging.h
new file mode 100644
index 000000000..76cfb8d60
--- /dev/null
+++ b/runtime/onert/core/include/util/logging.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_LOGGING_H__
+#define __ONERT_UTIL_LOGGING_H__
+
+#include <iostream>
+
+#include "util/ConfigSource.h"
+
+namespace onert
+{
+namespace util
+{
+namespace logging
+{
+
+class Context
+{
+public:
+ Context() noexcept : _enabled{false}
+ {
+ const auto env = util::getConfigBool(util::config::ONERT_LOG_ENABLE);
+
+ if (env)
+ {
+ _enabled = true;
+ }
+ }
+
+ static Context &get() noexcept;
+
+public:
+ bool enabled(void) const { return _enabled; }
+
+private:
+ bool _enabled;
+};
+
+static Context &ctx = Context::get();
+
+} // namespace logging
+} // namespace util
+} // namespace onert
+
+#define VERBOSE(name) \
+ if (::onert::util::logging::ctx.enabled()) \
+ std::cout << "[" << #name << "] "
+
+#define VERBOSE_F() \
+ if (::onert::util::logging::ctx.enabled()) \
+ std::cout << "[" << __func__ << "] "
+
+#endif // __ONERT_UTIL_LOGGING_H__
diff --git a/runtime/onert/core/src/backend/BackendContext.cc b/runtime/onert/core/src/backend/BackendContext.cc
new file mode 100644
index 000000000..bafa36d28
--- /dev/null
+++ b/runtime/onert/core/src/backend/BackendContext.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/BackendContext.h"
+
+#include "ir/Operation.h"
+#include "backend/IConstantInitializer.h"
+
+namespace onert
+{
+namespace backend
+{
+
+void BackendContext::initialize(const std::vector<OperationInfo> &operation_list,
+ const std::vector<ir::OperandIndex> &operand_list)
+{
+ _operation_list = operation_list;
+ _operand_list = operand_list;
+}
+
+void BackendContext::initConsts()
+{
+ for (auto &op : _operation_list)
+ {
+ constant_initializer->setLayout(op.layout);
+ _graph->operations().at(op.index).accept(*constant_initializer);
+ }
+
+ for (auto ind : _operand_list)
+ {
+ const auto &obj = _graph->operands().at(ind);
+ if (obj.isConstant() && !constant_initializer->exist(ind))
+ {
+ constant_initializer->registerDefaultInitializer(ind, obj);
+ }
+ }
+
+ constant_initializer->run();
+}
+
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/IConstantInitializer.cc b/runtime/onert/core/src/backend/IConstantInitializer.cc
new file mode 100644
index 000000000..6fb9757e0
--- /dev/null
+++ b/runtime/onert/core/src/backend/IConstantInitializer.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/IConstantInitializer.h"
+
+#include <Half.h>
+
+using float16 = Half;
+
+namespace onert
+{
+namespace backend
+{
+
+void IConstantInitializer::registerCopyInitializer(const ir::OperandIndex &index,
+ const ir::Operand &obj)
+{
+ // For only CONSTANTS
+ // TODO Add to check if tensor has been allocated
+ if (!obj.isConstant())
+ return;
+
+ const auto type = obj.typeInfo().type();
+ using ir::DataType;
+
+ switch (type)
+ {
+ case DataType::FLOAT32:
+ _init_map[index] = copyInit<float>;
+ break;
+ case DataType::INT32:
+ _init_map[index] = copyInit<int32_t>;
+ break;
+ case DataType::UINT32:
+ _init_map[index] = copyInit<uint32_t>;
+ break;
+ case DataType::BOOL8:
+ case DataType::QUANT_UINT8_ASYMM:
+ _init_map[index] = copyInit<uint8_t>;
+ break;
+ case DataType::QUANT_INT8_SYMM:
+ case DataType::QUANT_INT8_ASYMM:
+ _init_map[index] = copyInit<int8_t>;
+ break;
+ case DataType::FLOAT16:
+ _init_map[index] = copyInit<float16>;
+ break;
+ case DataType::INT64:
+ _init_map[index] = copyInit<int64_t>;
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+void IConstantInitializer::registerPermuteInitializer(const ir::OperandIndex &index,
+ const ir::Operand &obj)
+{
+ // For only CONSTANTS
+ // TODO Add to check if tensor has been allocated
+ if (!obj.isConstant())
+ return;
+
+ const auto type = obj.typeInfo().type();
+ using ir::DataType;
+ using namespace std::placeholders;
+
+ switch (type)
+ {
+ case DataType::FLOAT32:
+ _init_map[index] = std::bind(permuteInit<float>, _1, _2, _current_op_seq_layout);
+ break;
+ case DataType::INT32:
+ _init_map[index] = std::bind(permuteInit<int32_t>, _1, _2, _current_op_seq_layout);
+ break;
+ case DataType::UINT32:
+ _init_map[index] = std::bind(permuteInit<uint32_t>, _1, _2, _current_op_seq_layout);
+ break;
+ case DataType::BOOL8:
+ case DataType::QUANT_UINT8_ASYMM:
+ _init_map[index] = std::bind(permuteInit<uint8_t>, _1, _2, _current_op_seq_layout);
+ break;
+ case DataType::QUANT_INT8_SYMM:
+ case DataType::QUANT_INT8_ASYMM:
+ _init_map[index] = std::bind(permuteInit<int8_t>, _1, _2, _current_op_seq_layout);
+ break;
+ case DataType::FLOAT16:
+ _init_map[index] = std::bind(permuteInit<float16>, _1, _2, _current_op_seq_layout);
+ break;
+ case DataType::INT64:
+ _init_map[index] = std::bind(permuteInit<int64_t>, _1, _2, _current_op_seq_layout);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/IPortableTensor.cc b/runtime/onert/core/src/backend/IPortableTensor.cc
new file mode 100644
index 000000000..cec34e780
--- /dev/null
+++ b/runtime/onert/core/src/backend/IPortableTensor.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/IPortableTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+
+// `dynamic_cast` not working across library boundaries on NDK
+// With this as a key function, `dynamic_cast` works across dl
+IPortableTensor::~IPortableTensor() {}
+
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/ITensor.cc b/runtime/onert/core/src/backend/ITensor.cc
new file mode 100644
index 000000000..7127ed93d
--- /dev/null
+++ b/runtime/onert/core/src/backend/ITensor.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/ITensor.h"
+
+namespace onert
+{
+namespace backend
+{
+
+ir::Shape ITensor::getShape() const
+{
+ onert::ir::Shape shape(num_dimensions());
+ for (uint32_t d = 0; d < num_dimensions(); d++)
+ shape.dim(d) = dimension(d);
+
+ return shape;
+}
+
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/controlflow/Backend.h b/runtime/onert/core/src/backend/controlflow/Backend.h
new file mode 100644
index 000000000..cc8346e6b
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/Backend.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_BACKEND_H__
+#define __ONERT_BACKEND_CONTROLFLOW_BACKEND_H__
+
+#include "BackendContext.h"
+#include "Config.h"
+#include "ConstantInitializer.h"
+#include "KernelGenerator.h"
+#include "TensorBuilder.h"
+#include "Tensor.h"
+
+#include <backend/Backend.h>
+
+#include <memory>
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+class Backend : public ::onert::backend::Backend
+{
+public:
+ Backend() : _config{std::make_shared<Config>()} {}
+
+ std::shared_ptr<IConfig> config() const override { return _config; }
+
+ std::unique_ptr<onert::backend::BackendContext>
+ newContext(const ir::Graph &graph, const std::shared_ptr<custom::IKernelBuilder> &,
+ bool) const override
+ {
+ const auto &operands = graph.operands();
+ auto context = std::make_unique<BackendContext>(this, &graph);
+ // ControlFlow backend may not build tensors for itself because the backend's operation uses
+ // tensors of other baceknd instead
+ // But the backend builds tensors in case of that the controlflow operation may have constant
+ // input or that consecutive controflow operations exist. We have to make them not to be built
+ // later
+ // 1. Constant input
+ // These tensors cannot be dynamic tensor, so let's do it as follows:
+ // - always skip copying
+ // - if it is operation's input in child subgraph: register "use" as constant input of the
+ // operations in child subgraph
+ // - if it is child subgraph's output: register "use" as constant input of the operations
+ // using it
+ // 2. Consecutive controflow operation's intermediate tensor
+ // These tensors can be dynamic tensor and this is complicated to support without copying. But
+ // there is no such case until now, let's support it later
+ // TODO Remove TensorBuilder and ConstantInitializer
+ // TODO Support Consecutive controflow operation's intermediate tensor
+ auto tr = std::make_shared<TensorRegistry>();
+ auto tb = std::make_shared<TensorBuilder>(tr);
+ context->tensor_registry = tr;
+ context->tensor_builder = tb;
+ context->constant_initializer = std::make_shared<ConstantInitializer>(operands, tr);
+ context->kernel_gen = std::make_shared<KernelGenerator>(graph, tb->dynamicTensorManager(), tr,
+ context->external_context());
+ context->tensor_register = nullptr;
+ context->optimizer = nullptr;
+ return context;
+ }
+
+private:
+ std::shared_ptr<IConfig> _config;
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_BACKEND_H__
diff --git a/runtime/onert/core/src/backend/controlflow/BackendContext.h b/runtime/onert/core/src/backend/controlflow/BackendContext.h
new file mode 100644
index 000000000..3647338a0
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/BackendContext.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_BACKEND_CONTEXT_H__
+#define __ONERT_BACKEND_CONTROLFLOW_BACKEND_CONTEXT_H__
+
+#include <backend/BackendContext.h>
+#include "ExternalContext.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+class BackendContext : public onert::backend::BackendContext
+{
+public:
+ BackendContext(const Backend *backend, const ir::Graph *graph,
+ std::shared_ptr<ITensorRegistry> tensor_registry = nullptr,
+ std::shared_ptr<ITensorBuilder> tensor_builder = nullptr,
+ std::shared_ptr<IConstantInitializer> constant_initializer = nullptr,
+ std::shared_ptr<IKernelGenerator> kernel_gen = nullptr,
+ std::shared_ptr<ITensorRegister> tensor_register = nullptr,
+ std::shared_ptr<IOptimizer> optimizer = nullptr)
+ : onert::backend::BackendContext(backend, graph, tensor_registry, tensor_builder,
+ constant_initializer, kernel_gen, tensor_register,
+ optimizer),
+ _external_context(std::make_shared<ExternalContext>())
+ {
+ }
+
+ std::shared_ptr<ExternalContext> external_context() { return _external_context; }
+
+private:
+ // NOTE ruy context has a thread pool, and when multiple ruy contexts are created,
+ // the thread pool is also created in duplicate
+ // TODO Create one ruy context for session
+ std::shared_ptr<ExternalContext> _external_context;
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_BACKEND_CONTEXT_H__
diff --git a/runtime/onert/core/src/backend/controlflow/Config.cc b/runtime/onert/core/src/backend/controlflow/Config.cc
new file mode 100644
index 000000000..5ec01fe11
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/Config.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Config.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+std::string Config::ID = "controlflow";
+
+bool Config::initialize() { return true; }
+
+ir::Layout Config::supportLayout(const ir::Operation &, ir::Layout frontend_layout)
+{
+ return frontend_layout;
+}
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/controlflow/Config.h b/runtime/onert/core/src/backend/controlflow/Config.h
new file mode 100644
index 000000000..6645ed59d
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/Config.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_CONFIG_H__
+#define __ONERT_BACKEND_CONTROLFLOW_CONFIG_H__
+
+#include <backend/IConfig.h>
+#include <memory>
+#include <util/ITimer.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+class Config : public IConfig
+{
+public:
+ static std::string ID;
+ std::string id() override { return ID; }
+ bool initialize() override;
+ ir::Layout supportLayout(const ir::Operation &node, ir::Layout frontend_layout) override;
+ bool supportPermutation() override { return false; }
+ bool supportDynamicTensor() override
+ {
+ // TODO Make this backend to support dynamic tensor or not to build non-constant tensor
+ return true;
+ }
+ bool supportFP16() override { return false; }
+
+ std::unique_ptr<util::ITimer> timer() override { return std::make_unique<util::CPUTimer>(); }
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_CONFIG_H__
diff --git a/runtime/onert/core/src/backend/controlflow/ConstantInitializer.h b/runtime/onert/core/src/backend/controlflow/ConstantInitializer.h
new file mode 100644
index 000000000..e21a8f357
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/ConstantInitializer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_CONTROLFLOW_CONSTANT_INITIALIZER_H__
+#define __ONERT_COMPILER_CONTROLFLOW_CONSTANT_INITIALIZER_H__
+
+#include "TensorRegistry.h"
+
+#include <backend/IConstantInitializer.h>
+#include <ir/Operands.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+class ConstantInitializer : public IConstantInitializer
+{
+public:
+ ConstantInitializer(const ir::Operands &operands,
+ const std::shared_ptr<ITensorRegistry> &tensor_reg)
+ : IConstantInitializer{operands}, _tensor_reg{tensor_reg}
+ {
+ }
+
+private:
+ std::shared_ptr<ITensorRegistry> tensor_registry() const override { return _tensor_reg; }
+
+private:
+ std::shared_ptr<ITensorRegistry> _tensor_reg;
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_COMPILER_CONTROLFLOW_CONSTANT_INITIALIZER_H__
diff --git a/runtime/onert/core/src/backend/controlflow/DynamicTensorManager.h b/runtime/onert/core/src/backend/controlflow/DynamicTensorManager.h
new file mode 100644
index 000000000..c962d6ef1
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/DynamicTensorManager.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_DYNAMICTENSOR_MANAGER_H__
+#define __ONERT_BACKEND_CONTROLFLOW_DYNAMICTENSOR_MANAGER_H__
+
+#include "TensorRegistry.h"
+#include "Tensor.h"
+
+#include <backend/cpu_common/DynamicTensorManager.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+using DynamicTensorManager = cpu_common::DynamicTensorManager;
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_DYNAMICTENSOR_MANAGER_H__
diff --git a/runtime/onert/core/src/backend/controlflow/ExternalContext.h b/runtime/onert/core/src/backend/controlflow/ExternalContext.h
new file mode 100644
index 000000000..3db6829a9
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/ExternalContext.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_EXTERNAL_CONTEXT_H__
+#define __ONERT_BACKEND_CONTROLFLOW_EXTERNAL_CONTEXT_H__
+
+#include <backend/IExternalContext.h>
+#include <util/ConfigSource.h>
+
+#include <ruy/context.h>
+#include <ruy/context_get_ctx.h>
+#include <ruy/ctx.h>
+#include <ruy/tune.h>
+
+namespace
+{
+const int kDefaultNumThreadpoolThreads = 1;
+}
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+// TODO Unify this with cpu::ExternalContext
+class ExternalContext : public IExternalContext
+{
+public:
+ ExternalContext() : _ruy_context(std::make_unique<ruy::Context>())
+ {
+ setMaxNumThreads(onert::util::getConfigInt(onert::util::config::RUY_THREADS));
+ initPerThreadState();
+ }
+
+ void setMaxNumThreads(int max_num_threads)
+ {
+ const int target_num_threads =
+ max_num_threads > -1 ? max_num_threads : kDefaultNumThreadpoolThreads;
+ _ruy_context->set_max_num_threads(target_num_threads);
+ }
+
+ ruy::Context *ruy_context() const { return _ruy_context.get(); }
+
+private:
+ void initPerThreadState()
+ {
+ // Initialize per-thread state.
+ const int thread_count = _ruy_context->max_num_threads();
+ auto ctx = ruy::get_ctx(_ruy_context.get());
+ ctx->EnsureThreadSpecificResources(thread_count);
+ for (int i = 0; i < thread_count; i++)
+ {
+ ctx->GetThreadSpecificTuningResolver(i)->SetTuning(ctx->explicit_tuning());
+ }
+ }
+
+private:
+ const std::unique_ptr<ruy::Context> _ruy_context;
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_EXTERNAL_CONTEXT_H__
diff --git a/runtime/onert/core/src/backend/controlflow/KernelGenerator.cc b/runtime/onert/core/src/backend/controlflow/KernelGenerator.cc
new file mode 100644
index 000000000..8e39ee527
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/KernelGenerator.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KernelGenerator.h"
+
+#include <backend/BackendContext.h>
+#include <util/Utils.h>
+#include "kernel/IfLayer.h"
+#include "kernel/WhileLayer.h"
+#include "kernel/PermuteLayer.h"
+#include "exec/ExecutorBase.h"
+#include "exec/FunctionSequence.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+KernelGenerator::KernelGenerator(const ir::Graph &graph, IDynamicTensorManager *dyn_tensor_manager,
+ const std::shared_ptr<TensorRegistry> &tensor_reg,
+ const std::shared_ptr<ExternalContext> &external_context)
+ : _graph{graph}, _dyn_tensor_manager{dyn_tensor_manager}, _tensor_reg{tensor_reg},
+ _tensor_registries{}, _executor_map{nullptr}, _external_context{external_context}
+{
+ UNUSED_RELEASE(_graph);
+ UNUSED_RELEASE(_tensor_registries);
+ UNUSED_RELEASE(_executor_map);
+}
+
+void KernelGenerator::visit(const ir::OpSequence &op_seq)
+{
+ assert(!_return_fn_seq);
+ assert(_dyn_tensor_manager);
+ assert(_tensor_reg);
+
+ auto dyn_shape_inferer =
+ std::make_unique<exec::DynamicShapeInferer>(_graph.operands(), _tensor_reg);
+
+ _return_fn_seq = std::make_unique<exec::FunctionSequence>();
+
+ // Prepare to handle dynamic tensors later
+ auto dyn_ctx = std::make_shared<exec::FunctionSequence::DynamicTensorCtx>();
+ {
+ dyn_ctx->op_seq = &op_seq;
+ dyn_ctx->operations = &_graph.operations();
+ dyn_ctx->dynamic_shape_inferer = std::move(dyn_shape_inferer);
+ dyn_ctx->dynamic_tensor_manager = _dyn_tensor_manager;
+
+ _return_fn_seq->dynamic_tensor_ctx(dyn_ctx);
+ }
+
+ for (const auto &op_idx : op_seq.operations())
+ {
+ const auto &node = _graph.operations().at(op_idx);
+ node.accept(*this);
+ _return_fn_seq->append(releaseFunction());
+ }
+}
+
+void KernelGenerator::visit(const ir::operation::If &node)
+{
+ const auto then_subg_index = node.param().then_subg_index;
+ const auto else_subg_index = node.param().else_subg_index;
+
+ std::vector<backend::ITensor *> input_tensors;
+ for (const auto input_index : node.getInputs())
+ {
+ auto input_tensor = getTensor(input_index);
+
+ input_tensors.emplace_back(input_tensor);
+ }
+
+ std::vector<backend::ITensor *> output_tensors;
+ for (const auto output_index : node.getOutputs())
+ {
+ auto output_tensor = getTensor(output_index);
+ output_tensors.emplace_back(output_tensor);
+ }
+
+ // IfLayer just set ExecutorMap instead of then and else executor to avoid complexity of
+ // creating executor recusively
+ const auto cond_tensor = input_tensors.front();
+ input_tensors.erase(input_tensors.begin());
+ auto fn = std::make_unique<::onert::backend::controlflow::kernel::IfLayer>(
+ cond_tensor, input_tensors, output_tensors, node.getOutputs(), _graph, then_subg_index,
+ else_subg_index, _executor_map, _external_context);
+
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::Permute &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ // Add PermuteLayer
+ std::vector<ITensor *> output_tensors{getTensor(output_index)};
+ std::vector<ITensor *> input_tensors{getTensor(input_index)};
+
+ auto fn =
+ std::make_unique<kernel::PermuteLayer>(input_tensors, output_tensors, _external_context);
+ _return_fn = std::move(fn);
+}
+
+void KernelGenerator::visit(const ir::operation::While &node)
+{
+ const auto cond_subg_index = node.param().cond_subg_index;
+ const auto body_subg_index = node.param().body_subg_index;
+
+ // This op does not support input as a constant, because controlflow backend does not have
+ // TensorBuilder
+ std::vector<backend::ITensor *> input_tensors;
+ for (const auto input_index : node.getInputs())
+ {
+ auto input_tensor = getTensor(input_index);
+
+ input_tensors.emplace_back(input_tensor);
+ }
+
+ std::vector<backend::ITensor *> output_tensors;
+ for (const auto output_index : node.getOutputs())
+ {
+ auto output_tensor = getTensor(output_index);
+ output_tensors.emplace_back(output_tensor);
+ }
+
+ // WhileLayer just set ExecutorMap instead of cond and body executor to avoid complexity of
+ // creating executor recusively
+ auto fn = std::make_unique<::onert::backend::controlflow::kernel::WhileLayer>(
+ input_tensors, output_tensors, node.getOutputs(), _graph, cond_subg_index, body_subg_index,
+ _executor_map, _external_context);
+
+ _return_fn = std::move(fn);
+}
+
+backend::ITensor *KernelGenerator::getTensor(const ir::OperandIndex &index)
+{
+ backend::ITensor *ret = _tensor_registries.getITensor(index);
+ assert(ret != nullptr);
+ return ret;
+}
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/controlflow/KernelGenerator.h b/runtime/onert/core/src/backend/controlflow/KernelGenerator.h
new file mode 100644
index 000000000..c2c124339
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/KernelGenerator.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_KERNEL_GENERATOR_H__
+#define __ONERT_BACKEND_CONTROLFLOW_KERNEL_GENERATOR_H__
+
+#include <backend/IKernelGenerator.h>
+#include <backend/ITensorBuilder.h>
+#include <exec/IExecutor.h>
+#include "ExternalContext.h"
+#include <ir/Graph.h>
+#include "TensorBuilder.h"
+#include "compiler/TensorRegistries.h"
+#include "TensorRegistry.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+class KernelGenerator : public IKernelGenerator
+{
+public:
+ KernelGenerator(const ir::Graph &graph, IDynamicTensorManager *dyn_tensor_manager,
+ const std::shared_ptr<TensorRegistry> &tensor_reg,
+ const std::shared_ptr<ExternalContext> &external_context);
+
+ void setTensorRegistries(const compiler::TensorRegistries &tensor_registries)
+ {
+ _tensor_registries = tensor_registries;
+ }
+ void setExecutorMap(const std::shared_ptr<exec::ExecutorMap> &executor_map)
+ {
+ // FIXME Using shared_ptr's raw pointer!
+ _executor_map = executor_map.get();
+ }
+
+ using IKernelGenerator::visit;
+
+ void visit(const ir::OpSequence &) override;
+ void visit(const ir::operation::If &) override;
+ void visit(const ir::operation::Permute &) override;
+ void visit(const ir::operation::While &) override;
+
+private:
+ backend::ITensor *getTensor(const ir::OperandIndex &index);
+
+private:
+ const ir::Graph &_graph;
+ IDynamicTensorManager *_dyn_tensor_manager;
+ std::shared_ptr<TensorRegistry> _tensor_reg;
+ compiler::TensorRegistries _tensor_registries;
+ exec::ExecutorMap *_executor_map;
+ const std::shared_ptr<ExternalContext> _external_context;
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_KERNEL_GENERATOR_H__
diff --git a/runtime/onert/core/src/backend/controlflow/Tensor.h b/runtime/onert/core/src/backend/controlflow/Tensor.h
new file mode 100644
index 000000000..ba5bafd75
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/Tensor.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_TENSOR_H__
+#define __ONERT_BACKEND_CONTROLFLOW_TENSOR_H__
+
+#include <backend/cpu_common/Tensor.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+using Tensor = cpu_common::Tensor;
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_TENSOR_H__
diff --git a/runtime/onert/core/src/backend/controlflow/TensorBuilder.cc b/runtime/onert/core/src/backend/controlflow/TensorBuilder.cc
new file mode 100644
index 000000000..e4b0388f9
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/TensorBuilder.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TensorBuilder.h"
+
+#include <util/logging.h>
+
+#include <cassert>
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+TensorBuilder::TensorBuilder(const std::shared_ptr<TensorRegistry> &tensor_reg)
+ : _tensor_reg{tensor_reg},
+ _dynamic_tensor_mgr{new DynamicTensorManager(_tensor_reg->base_reg())},
+ _static_tensor_mgr{new cpu_common::StaticTensorManager(
+ _tensor_reg->base_reg(), _dynamic_tensor_mgr->dynamic_mem_mgr().get())}
+{
+ /* empty */
+}
+
+void TensorBuilder::registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
+ ir::Layout backend_layout)
+{
+ _tensor_info_map.emplace(ind, info);
+
+ _tensor_layout_map.insert({ind, backend_layout});
+
+ if (info.isDynamic())
+ {
+ _dynamic_tensor_mgr->buildTensor(ind, info, _tensor_layout_map[ind]);
+ }
+ else
+ {
+ _static_tensor_mgr->buildTensor(ind, info, _tensor_layout_map[ind], info.isConstant());
+ }
+}
+
+void TensorBuilder::notifyFirstUse(const ir::OperandIndex &ind)
+{
+ // TODO Enhance the way of checking user tensors
+ if (_tensor_info_map.find(ind) == _tensor_info_map.end()) // Do not proceed for user tensors
+ return;
+
+ const auto tensor_info = _tensor_info_map.at(ind);
+
+ if (!nativeOwnTensorAt(ind)->is_dynamic())
+ {
+ const auto size = tensor_info.total_size();
+ _static_tensor_mgr->claimPlan(ind, size);
+ }
+}
+
+void TensorBuilder::notifyLastUse(const ir::OperandIndex &ind)
+{
+ // TODO Enhance the way of checking user tensors
+ if (_tensor_info_map.find(ind) == _tensor_info_map.end()) // Do not proceed for user tensors
+ return;
+
+ if (!nativeOwnTensorAt(ind)->is_dynamic())
+ {
+ _static_tensor_mgr->releasePlan(ind);
+ }
+}
+
+bool TensorBuilder::isRegistered(const ir::OperandIndex &ind) const
+{
+ // User tensors are not registered in _tensor_info_map but objects for them are exist
+ // in the tensor registry.
+ // TODO Enhance the way of checking user tensors
+ if (_tensor_reg->getITensor(ind))
+ return true;
+ return _tensor_info_map.find(ind) != _tensor_info_map.end();
+}
+
+void TensorBuilder::prepare(void)
+{
+ _static_tensor_mgr->allocateConsts();
+ _static_tensor_mgr->allocateNonconsts();
+}
+
+void TensorBuilder::allocate()
+{
+ // NOTE For now nothing to do. Allocation is done in prepare stage, which is not appropriate
+ // This is because CPU kernels require `ITensor`s to be allocated before Kernel Generation.
+}
+
+IDynamicTensorManager *TensorBuilder::dynamicTensorManager(void)
+{
+ return _dynamic_tensor_mgr.get();
+}
+
+cpu_common::Tensor *TensorBuilder::nativeOwnTensorAt(const ir::OperandIndex &ind)
+{
+ return _tensor_reg->getNativeOwnTensor(ind);
+}
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/controlflow/TensorBuilder.h b/runtime/onert/core/src/backend/controlflow/TensorBuilder.h
new file mode 100644
index 000000000..695994761
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/TensorBuilder.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_TENSOR_BUILDER_H__
+#define __ONERT_BACKEND_CONTROLFLOW_TENSOR_BUILDER_H__
+
+#include <backend/cpu_common/StaticTensorManager.h>
+#include <backend/cpu_common/TensorRegistry.h>
+#include <backend/cpu_common/Tensor.h>
+
+#include <backend/ITensorBuilder.h>
+#include <ir/OperandIndexMap.h>
+
+#include <unordered_map>
+
+#include "DynamicTensorManager.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+class TensorBuilder : public ITensorBuilder
+{
+public:
+ TensorBuilder(const std::shared_ptr<TensorRegistry> &tensor_reg);
+
+ /**
+ * @brief Register tensor information to allocate on CPU backend
+ * @param[in] ind Operand index
+ * @param[in] info Operand information
+ * @param[in] layout Operand data layout
+ */
+ void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
+ ir::Layout backend_layout) override;
+
+ void notifyFirstUse(const ir::OperandIndex &) override;
+ void notifyLastUse(const ir::OperandIndex &) override;
+
+ bool isRegistered(const ir::OperandIndex &) const override;
+
+ void prepare(void) override;
+ void allocate() override;
+ void postFunctionPrepare() override { /* DO NOTHING */}
+
+ IDynamicTensorManager *dynamicTensorManager(void) override;
+
+ /**
+ * @brief Get tensor with a specific OperandIndex.
+ * @param ind OperandIndex for the tensor. There must exist a tensor with this ind.
+ * If not, program will crash with assert or exception.
+ * @return operand::Tensor *
+ */
+ cpu_common::Tensor *nativeOwnTensorAt(const ir::OperandIndex &ind);
+
+private:
+ const std::shared_ptr<TensorRegistry> _tensor_reg;
+ std::unique_ptr<DynamicTensorManager> _dynamic_tensor_mgr;
+ std::unique_ptr<cpu_common::StaticTensorManager> _static_tensor_mgr;
+ ir::OperandIndexMap<ir::OperandInfo> _tensor_info_map;
+ ir::OperandIndexMap<ir::Layout> _tensor_layout_map;
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_TENSOR_BUILDER_H__
diff --git a/runtime/onert/core/src/backend/controlflow/TensorRegistry.h b/runtime/onert/core/src/backend/controlflow/TensorRegistry.h
new file mode 100644
index 000000000..94f71bb9c
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/TensorRegistry.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_TENSOR_REGISTRY_H__
+#define __ONERT_BACKEND_CONTROLFLOW_TENSOR_REGISTRY_H__
+
+#include "backend/cpu_common/TensorRegistry.h"
+#include "backend/ITensorRegistry.h"
+#include "Tensor.h"
+#include "UserTensor.h"
+#include <assert.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+/**
+ * @brief Tensor registry class for controlflow backend
+ *
+ * This class contains three types of tensors. Two native tensors(tensors that are managed by this
+ * backend) and the other is migrant tensor.
+ *
+ * - NativeUserTensor - @c UserTensor managed by this backend, buffer is user-given
+ * - NativeOwnTensor - @c cpu_common::Tensor managed by this backend ( in @c _base_reg )
+ * - MigrantTensor - @c IPortableTensor managed by other backends ( in @c _base_reg )
+ *
+ * @note @c _base_reg is used in implementation to reuse @c cpu_common::StaticTensorManager
+ *
+ */
+class TensorRegistry : public ITensorRegistry
+{
+public:
+ TensorRegistry() : _base_reg{new cpu_common::TensorRegistry} {}
+
+ ITensor *getITensor(const ir::OperandIndex &ind) override
+ {
+ auto base_tensor = _base_reg->getITensor(ind);
+ if (base_tensor)
+ return base_tensor;
+ return getNativeUserTensor(ind);
+ }
+
+ ITensor *getNativeITensor(const ir::OperandIndex &ind) override
+ {
+ auto base_tensor = _base_reg->getNativeITensor(ind);
+ if (base_tensor)
+ return base_tensor;
+ return getNativeUserTensor(ind);
+ }
+
+ IPortableTensor *getPortableTensor(const ir::OperandIndex &ind)
+ {
+ auto base_tensor = _base_reg->getPortableTensor(ind);
+ if (base_tensor)
+ return base_tensor;
+ return getNativeUserTensor(ind);
+ }
+
+ IPortableTensor *getNativeTensor(const ir::OperandIndex &ind)
+ {
+ auto base_tensor = _base_reg->getNativeTensor(ind);
+ if (base_tensor)
+ return base_tensor;
+ return getNativeUserTensor(ind);
+ }
+
+ Tensor *getNativeOwnTensor(const ir::OperandIndex &ind)
+ {
+ return _base_reg->getNativeTensor(ind);
+ }
+
+ UserTensor *getNativeUserTensor(const ir::OperandIndex &ind)
+ {
+ auto tensor = _native_user_tensors.find(ind);
+ if (tensor != _native_user_tensors.end())
+ return tensor->second.get();
+ return nullptr;
+ }
+
+ bool setMigrantTensor(const ir::OperandIndex &ind, IPortableTensor *tensor) override
+ {
+ assert(tensor);
+ assert(!getITensor(ind)); // For the ind, tensor is not registered yet
+ _base_reg->setMigrantTensor(ind, tensor);
+ return true;
+ }
+
+ void setNativeOwnTensor(ir::OperandIndex ind, std::unique_ptr<Tensor> &&tensor)
+ {
+ assert(tensor);
+ assert(!getITensor(ind)); // For the ind, tensor is not registered yet
+ _base_reg->setNativeTensor(ind, std::move(tensor));
+ }
+
+ void setNativeUserTensor(ir::OperandIndex ind, std::unique_ptr<UserTensor> &&tensor)
+ {
+ assert(tensor);
+ assert(!getITensor(ind)); // For the ind, tensor is not registered yet
+ _native_user_tensors[ind] = std::move(tensor);
+ }
+
+ const ir::OperandIndexMap<std::unique_ptr<UserTensor>> &native_user_tensors()
+ {
+ return _native_user_tensors;
+ }
+ std::shared_ptr<cpu_common::TensorRegistry> base_reg() { return _base_reg; }
+
+private:
+ std::shared_ptr<cpu_common::TensorRegistry> _base_reg;
+ ir::OperandIndexMap<std::unique_ptr<UserTensor>> _native_user_tensors;
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // ifndef __ONERT_BACKEND_CONTROLFLOW_TENSOR_REGISTRY_H__
diff --git a/runtime/onert/core/src/backend/controlflow/UserTensor.cc b/runtime/onert/core/src/backend/controlflow/UserTensor.cc
new file mode 100644
index 000000000..5081a90ea
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/UserTensor.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UserTensor.h"
+
+#include "util/Exceptions.h"
+#include "ir/DataType.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+size_t UserTensor::calcOffset(const ir::Coordinates &coords) const
+{
+ size_t rank = num_dimensions();
+ size_t offset = 0;
+ for (size_t i = 0; i < rank; ++i)
+ {
+ offset = offset * dimension(i) + coords[i];
+ }
+ offset *= sizeOfDataType(data_type());
+ return offset;
+}
+
+bool UserTensor::applyShape(const ir::Shape &new_shape)
+{
+ // User tensors cannot be reallocated.
+ auto new_size = new_shape.num_elements() * ir::sizeOfDataType(data_type());
+ if (total_size() < new_size)
+ throw InsufficientBufferSizeException{"User given buffer size is too small."};
+ setShape(new_shape);
+ return true;
+}
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/controlflow/UserTensor.h b/runtime/onert/core/src/backend/controlflow/UserTensor.h
new file mode 100644
index 000000000..7aa62a8a9
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/UserTensor.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_USER_TENSOR_H__
+#define __ONERT_BACKEND_CONTROLFLOW_USER_TENSOR_H__
+
+#include "ir/OperandInfo.h"
+#include "backend/IPortableTensor.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+
+/**
+ * @brief Tensor object that is for Input and Output tensors from the user.
+ *
+ * This class is a wrapped buffer that is allocated by the user. So it does not have resposibility
+ * on allocation nor deallocation. All the model input/output tensors are wrapped with this class
+ * for execution.
+ *
+ */
+class UserTensor : public IPortableTensor
+{
+public:
+ UserTensor(const ir::OperandInfo &info, ir::Layout layout, uint8_t *buffer, size_t size)
+ : IPortableTensor{info}, _layout{layout}, _buffer{buffer}, _size{size}, _dynamic{false}
+ {
+ }
+
+ UserTensor(const ir::OperandInfo &info, ir::Layout layout) : UserTensor{info, layout, nullptr, 0}
+ {
+ }
+
+public:
+ void setBuffer(uint8_t *buffer, size_t size)
+ {
+ _buffer = buffer;
+ _size = size;
+ }
+
+public:
+ uint8_t *buffer() const override { return _buffer; }
+ size_t total_size() const override { return _size; }
+ size_t dimension(size_t index) const override { return _info.shape().dim(index); }
+ size_t num_dimensions() const override { return _info.shape().rank(); }
+ size_t calcOffset(const ir::Coordinates &coords) const override;
+ ir::Layout layout() const override { return _layout; }
+ ir::DataType data_type() const override { return _info.typeInfo().type(); }
+ float data_scale() const override { return _info.typeInfo().scale(); }
+ int32_t data_offset() const override { return _info.typeInfo().offset(); }
+ bool is_dynamic() const override { return _dynamic; }
+ void set_dynamic() override { _dynamic = true; }
+ ir::Shape getShape() const override { return _info.shape(); }
+ void setShape(const ir::Shape &new_shape) override { _info.shape(new_shape); }
+ bool is_constant() const override { return false; }
+ bool applyShape(const ir::Shape &) override;
+
+private:
+ ir::Layout _layout;
+ uint8_t *_buffer;
+ size_t _size;
+ bool _dynamic;
+};
+
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_USER_TENSOR_H__
diff --git a/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.cc b/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.cc
new file mode 100644
index 000000000..de91b850a
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "IfLayer.h"
+
+#include <backend/ITensor.h>
+#include "exec/ExecutorBase.h"
+#include <misc/polymorphic_downcast.h>
+#include "PermuteLayer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+namespace kernel
+{
+
+IfLayer::IfLayer(backend::ITensor *cond_tensor, const std::vector<backend::ITensor *> input_tensors,
+ const std::vector<backend::ITensor *> output_tensors,
+ const ir::OperandIndexSequence &output_indices, const ir::Graph &graph,
+ const ir::SubgraphIndex &then_subg_index, const ir::SubgraphIndex &else_subg_index,
+ exec::ExecutorMap *executor_map,
+ const std::shared_ptr<ExternalContext> &external_context)
+ : _cond_tensor{cond_tensor}, _input_tensors{input_tensors}, _output_tensors{output_tensors},
+ _output_indices{output_indices}, _graph{graph}, _then_subg_index{then_subg_index},
+ _else_subg_index{else_subg_index}, _executor_map{executor_map},
+ _external_context{external_context}
+{
+ // At this point, executor_map may not have executors of then subg and else subg
+}
+
+void IfLayer::run()
+{
+ // Check condition
+ // // If true
+ // // // Copy _input_tensors -> then subg's inputs
+ // // // Run then subg
+ // // // Copy outputs of then subg -> _output_tensors
+ // // Else
+ // // // Copy _input_tensors -> else subg's inputs if false
+ // // // Run else subg
+ // // // Copy outputs of else subg -> _output_tensors
+ auto getResultCond = [](backend::ITensor *tensor) -> bool {
+ bool ret = false;
+ tensor->access([&](ITensor &tensor) { ret = *reinterpret_cast<bool *>(tensor.buffer()); });
+ return ret;
+ };
+
+ exec::ExecutorBase *subg_exec = nullptr;
+ bool cond_result = getResultCond(_cond_tensor);
+ if (cond_result)
+ {
+ VERBOSE(If) << "Call to $" << _then_subg_index << " (then)" << std::endl;
+ subg_exec = nnfw::misc::polymorphic_downcast<exec::ExecutorBase *>(
+ _executor_map->at(_then_subg_index).get());
+ }
+ else
+ {
+ VERBOSE(If) << "Call to $" << _else_subg_index << " (else)" << std::endl;
+ subg_exec = nnfw::misc::polymorphic_downcast<exec::ExecutorBase *>(
+ _executor_map->at(_else_subg_index).get());
+ }
+
+ const auto &subg_graph = subg_exec->graph();
+
+ std::vector<backend::ITensor *> src_tensors;
+ std::vector<backend::ITensor *> dst_tensors;
+ // Add tensors used in subgraph or contained in outputs of subgraph
+ assert(subg_graph.getInputs().size() == _input_tensors.size());
+ assert(subg_graph.getInputs().size() == subg_exec->getInputTensors().size());
+ for (uint32_t i = 0; i < subg_graph.getInputs().size(); ++i)
+ {
+ const auto &subg_input_index = subg_graph.getInputs().at(i);
+ const auto &subg_input = subg_graph.operands().at(subg_input_index);
+ if (subg_input.getUses().size() > 0 || subg_graph.getOutputs().contains(subg_input_index))
+ {
+ src_tensors.emplace_back(_input_tensors.at(i));
+ dst_tensors.emplace_back(subg_exec->getInputTensors().at(i));
+ }
+ }
+ const auto permute_op_input_to_subg_input =
+ std::make_shared<PermuteLayer>(src_tensors, dst_tensors, _external_context);
+
+ // Add tensors used as output of operation or contained in outputs of operation
+ src_tensors.clear();
+ dst_tensors.clear();
+ assert(_output_indices.size() == subg_exec->getOutputTensors().size());
+ assert(_output_indices.size() == _output_tensors.size());
+ for (uint32_t i = 0; i < _output_indices.size(); ++i)
+ {
+ const auto &output_index = _output_indices.at(i);
+ const auto &output = _graph.operands().at(output_index);
+ if (output.getUses().size() > 0 || _graph.getOutputs().contains(output_index))
+ {
+ src_tensors.emplace_back(subg_exec->getOutputTensors().at(i));
+ dst_tensors.emplace_back(_output_tensors.at(i));
+ }
+ }
+ const auto permute_subg_output_to_op_output =
+ std::make_shared<PermuteLayer>(src_tensors, dst_tensors, _external_context);
+
+ // Remove copying of unused tensor
+ permute_op_input_to_subg_input->prepare();
+ permute_subg_output_to_op_output->prepare();
+
+ // Copy & run
+ subg_exec->execute(_input_tensors, permute_op_input_to_subg_input);
+ permute_subg_output_to_op_output->run();
+ VERBOSE(If) << "Return from $" << (cond_result ? _then_subg_index : _else_subg_index)
+ << std::endl;
+}
+
+} // namespace kernel
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.h b/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.h
new file mode 100644
index 000000000..9e944bccc
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/kernel/IfLayer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_KERNEL_IF_LAYER_H__
+#define __ONERT_BACKEND_CONTROLFLOW_KERNEL_IF_LAYER_H__
+
+#include <backend/ITensor.h>
+#include <exec/IExecutor.h>
+#include "../ExternalContext.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+namespace kernel
+{
+
+class IfLayer : public ::onert::exec::IFunction
+{
+public:
+ IfLayer(backend::ITensor *cond_tensor, const std::vector<backend::ITensor *> input_tensors,
+ const std::vector<backend::ITensor *> output_tensors,
+ const ir::OperandIndexSequence &output_indices, const ir::Graph &graph,
+ const ir::SubgraphIndex &then_subg_index, const ir::SubgraphIndex &else_subg_index,
+ exec::ExecutorMap *executor_map,
+ const std::shared_ptr<ExternalContext> &external_context);
+
+public:
+ void run() override;
+
+private:
+ backend::ITensor *_cond_tensor;
+ const std::vector<backend::ITensor *> _input_tensors;
+ const std::vector<backend::ITensor *> _output_tensors;
+ const ir::OperandIndexSequence &_output_indices;
+ const ir::Graph &_graph;
+ const ir::SubgraphIndex _then_subg_index;
+ const ir::SubgraphIndex _else_subg_index;
+ exec::ExecutorMap *_executor_map;
+ const std::shared_ptr<ExternalContext> _external_context;
+};
+
+} // namespace kernel
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_KERNEL_IF_LAYER_H__
diff --git a/runtime/onert/core/src/backend/controlflow/kernel/PermuteLayer.cc b/runtime/onert/core/src/backend/controlflow/kernel/PermuteLayer.cc
new file mode 100644
index 000000000..8b79ea070
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/kernel/PermuteLayer.cc
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PermuteLayer.h"
+
+#include "exec/ShapeConverter.h"
+
+#include "ruy/context.h" // from @ruy
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+namespace kernel
+{
+
+PermuteLayer::PermuteLayer(const std::vector<ITensor *> &src_tensors,
+ const std::vector<ITensor *> &dst_tensors,
+ const std::shared_ptr<ExternalContext> &external_context)
+ : _external_context{external_context}, _tasks_map{}
+{
+ assert(src_tensors.size() == dst_tensors.size());
+ _src_tensors = src_tensors;
+ _dst_tensors = dst_tensors;
+ _src_tensors_offsets.resize(src_tensors.size());
+ _dst_tensors_offsets.resize(dst_tensors.size());
+}
+
+void PermuteLayer::optimize()
+{
+ // Remove copying of tensor as nullptr
+ auto src_it = _src_tensors.begin();
+ auto dst_it = _dst_tensors.begin();
+ auto src_offsets_it = _src_tensors_offsets.begin();
+ auto dst_offsets_it = _dst_tensors_offsets.begin();
+ while (src_it != _src_tensors.end())
+ {
+ if ((*src_it == *dst_it) || (*src_it == nullptr || *dst_it == nullptr))
+ {
+ src_it = _src_tensors.erase(src_it);
+ dst_it = _dst_tensors.erase(dst_it);
+ src_offsets_it = _src_tensors_offsets.erase(src_offsets_it);
+ dst_offsets_it = _dst_tensors_offsets.erase(dst_offsets_it);
+ }
+ else
+ {
+ auto src = *src_it;
+ auto dst = *dst_it;
+ src_offsets_it->resize(0);
+ dst_offsets_it->resize(0);
+ if (underlying_type(src->data_type()) != underlying_type(dst->data_type()))
+ throw std::runtime_error("data type does not match");
+ const auto permute_type = [&]() -> PermuteType {
+ if (src->num_dimensions() == 4 && src->layout() == ir::Layout::NHWC &&
+ dst->layout() == ir::Layout::NCHW)
+ {
+ return PermuteType::NHWC_TO_NCHW;
+ }
+ else if (src->num_dimensions() == 4 && src->layout() == ir::Layout::NCHW &&
+ dst->layout() == ir::Layout::NHWC)
+ {
+ return PermuteType::NCHW_TO_NHWC;
+ }
+ else
+ {
+ return PermuteType::COPY;
+ }
+ }();
+ auto fn = [&](backend::ITensor &src_tensor) {
+ dst->access([&](backend::ITensor &dst_tensor) {
+ // NOTE The buffer of both tensor can be nullptr in this step
+ const auto data_size = ir::sizeOfDataType(src_tensor.data_type());
+
+ if (permute_type == PermuteType::COPY)
+ {
+ if ((!src_tensor.has_padding() && !dst_tensor.has_padding()))
+ {
+ const auto num_elements = src_tensor.getShape().num_elements();
+ const int thread_count = _external_context->ruy_context()->max_num_threads() <
+ static_cast<int>(num_elements)
+ ? _external_context->ruy_context()->max_num_threads()
+ : num_elements;
+
+ std::vector<PermuteWorkerTask> tasks;
+ auto start = 0;
+ for (auto i = 0; i < thread_count; ++i)
+ {
+ int end = start + (num_elements - start) / (thread_count - i);
+ tasks.emplace_back(src_tensor.buffer(), dst_tensor.buffer(), start * data_size,
+ start * data_size, (end - start) * data_size);
+ start = end;
+ }
+ assert(tasks.size() >= 1);
+ _tasks_map[src] = std::move(tasks);
+ }
+ else
+ {
+ auto loop_shape = src_tensor.getShape();
+
+ auto copy_axis = loop_shape.rank() - 1;
+ copy_axis = copy_axis < 0 ? 1 : copy_axis;
+ const auto copy_len = loop_shape.dim(copy_axis) * data_size;
+ loop_shape.dim(copy_axis) = 1;
+
+ appendPermuteTasks(src, dst, loop_shape, copy_len);
+ }
+ }
+ else
+ {
+ assert(src_tensor.num_dimensions() == 4 && (permute_type == PermuteType::NHWC_TO_NCHW ||
+ permute_type == PermuteType::NCHW_TO_NHWC));
+ const auto loop_shape = src_tensor.getShape();
+ const auto copy_len = data_size;
+
+ appendPermuteTasks(src, dst, loop_shape, copy_len);
+ }
+ });
+ };
+ src->access(fn);
+ src_it++;
+ dst_it++;
+ src_offsets_it++;
+ dst_offsets_it++;
+ }
+ }
+}
+
+void PermuteLayer::appendPermuteTasks(const ITensor *src_tensor, ITensor *dst_tensor,
+ const ir::Shape &loop_shape, size_t size)
+{
+ size_t distributed_dim = 0;
+ if (src_tensor->layout() == dst_tensor->layout())
+ {
+ for (size_t i = 1; i < src_tensor->num_dimensions() - 1; ++i)
+ {
+ distributed_dim =
+ src_tensor->dimension(distributed_dim) < src_tensor->dimension(i) ? i : distributed_dim;
+ }
+ }
+ const auto distributed_dim_val = src_tensor->dimension(distributed_dim);
+ const int thread_count =
+ _external_context->ruy_context()->max_num_threads() < static_cast<int>(distributed_dim_val)
+ ? _external_context->ruy_context()->max_num_threads()
+ : distributed_dim_val;
+ // NOTE Do not remove this assertion. It would cause performance degradation by new threads to be
+ // created in the context's thread pool
+ assert(thread_count <= _external_context->ruy_context()->max_num_threads());
+
+ std::vector<PermuteWorkerTask> tasks;
+ int start = 0;
+ auto one_thread_loop_shape = loop_shape;
+ for (auto i = 0; i < thread_count; ++i)
+ {
+ ir::Coordinates start_coords(one_thread_loop_shape.rank());
+ start_coords.set(distributed_dim, start);
+ int end = start + (distributed_dim_val - start) / (thread_count - i);
+ one_thread_loop_shape.dim(distributed_dim) = end - start;
+ tasks.emplace_back(*src_tensor, *dst_tensor, start_coords, one_thread_loop_shape, size);
+ start = end;
+ }
+ assert(tasks.size() >= 1);
+ _tasks_map[src_tensor] = std::move(tasks);
+}
+
+void PermuteLayer::runPermuteTasks(backend::ITensor *src, uint8_t *dst_buffer)
+{
+ assert(src->getShape().num_elements() * ir::sizeOfDataType(src->data_type()) <=
+ src->total_size());
+ std::vector<PermuteWorkerTask> &tasks = _tasks_map.at(src);
+ for (size_t i = 0; i < tasks.size(); ++i)
+ {
+ tasks.at(i).setBuffers(src->buffer(), dst_buffer);
+ }
+ assert(tasks.size() >= 1);
+ _external_context->ruy_context()->mutable_thread_pool()->Execute(tasks.size(), tasks.data());
+}
+
+void PermuteLayer::run()
+{
+ assert(_src_tensors.size() == _dst_tensors.size());
+ // PermuteLayer infers dynamic shape inside itself whenever run is called for the following
+ // reasons:
+ // 1. PermuteLayer has to access dynamic tensor manager for input/output tensors of other backends
+ // 2. Other controlflow operation(If/While) uses this layout for copying tensors of other
+ // subgraphs(with other backends)
+ // 3. This infering code is placed here to avoid duplicated code that can be caused by above 2
+ // reasons
+
+ // check if output is not dynamic
+ for (size_t i = 0; i < _src_tensors.size(); ++i)
+ {
+ auto dst_tensor = _dst_tensors.at(i);
+ auto src_tensor = _src_tensors.at(i);
+ if (src_tensor->is_dynamic() || dst_tensor->is_dynamic())
+ {
+ // getting output shape
+ auto src_shape = src_tensor->getShape();
+
+ // set output shape and output buffer
+ ir::Shape new_shape =
+ exec::convertShape(src_shape, src_tensor->layout(), dst_tensor->layout());
+
+ try
+ {
+ if (!dst_tensor->applyShape(new_shape))
+ throw std::runtime_error{
+ "Error: PermuteLayer: output's TensorManager does not support dynamic tensor"};
+ assert(dst_tensor->buffer() != nullptr);
+ }
+ catch (const std::out_of_range &e)
+ {
+ std::cerr << "Error: out_of_range in PermuteLayer: output's TensorManager does not support "
+ "dynamic tensor"
+ << '\n';
+ throw;
+ }
+ }
+ assert(exec::convertShape(src_tensor->getShape(), src_tensor->layout(), dst_tensor->layout()) ==
+ dst_tensor->getShape());
+ }
+ assert(_src_tensors.size() == _dst_tensors.size());
+ assert(_src_tensors.size() == _src_tensors_offsets.size());
+ assert(_dst_tensors.size() == _dst_tensors_offsets.size());
+ auto src_it = _src_tensors.begin();
+ auto dst_it = _dst_tensors.begin();
+ auto src_offsets_it = _src_tensors_offsets.begin();
+ auto dst_offsets_it = _dst_tensors_offsets.begin();
+ while (src_it != _src_tensors.end())
+ {
+ auto src = *src_it;
+ auto dst = *dst_it;
+ auto &src_offsets = *src_offsets_it;
+ auto &dst_offsets = *dst_offsets_it;
+
+ if (src->total_size() == 0)
+ {
+ assert(dst->total_size() == 0);
+ }
+ else
+ {
+ if (src != dst)
+ {
+ // Conditions to run permutation with multithreading
+ // 1. The tasks for multithreathing was created
+ // 2. The tasks's size > 1
+ // 3. Both tensors are not dynamic
+ if (_tasks_map.find(src) == _tasks_map.end() || _tasks_map.at(src).size() == 1 ||
+ src->is_dynamic() || dst->is_dynamic())
+ {
+ permute(src, dst, src->num_dimensions(), src_offsets, dst_offsets);
+ }
+ // If dst is subtensor, we have to use clEnqueueMapBuffer instead of clEnqueueWirteBuffer
+ else if (dst->needMemoryMap() && !dst->is_subtensor())
+ {
+ if (!src->has_padding() && !dst->has_padding() && src->layout() == dst->layout())
+ {
+ // This is more effective than multi-threading
+ src->access([&](backend::ITensor &) { dst->enqueueWriteBuffer(src->buffer(), false); });
+ }
+ else
+ {
+ // TODO Optimize this block in case of that padding size of dst is big.
+ _buffers_map[dst].reserve(dst->total_size());
+ auto dst_buffer = _buffers_map[dst].data();
+
+ src->access([&](backend::ITensor &) { runPermuteTasks(src, dst_buffer); });
+ dst->enqueueWriteBuffer(dst_buffer, false);
+ }
+ }
+ else if (src->needMemoryMap() && !src->is_subtensor() && !src->has_padding() &&
+ !dst->has_padding() && src->layout() == dst->layout())
+ {
+ // This is more effective than multi-threading
+ assert(!dst->needMemoryMap());
+ dst->access([&](backend::ITensor &) { src->enqueueReadBuffer(dst->buffer(), true); });
+ }
+ else
+ {
+ auto fn = [&](backend::ITensor &) {
+ dst->access([&](backend::ITensor &) { runPermuteTasks(src, dst->buffer()); });
+ };
+ src->access(fn);
+ }
+ }
+ }
+ src_it++;
+ dst_it++;
+ src_offsets_it++;
+ dst_offsets_it++;
+ }
+}
+
+} // namespace kernel
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/controlflow/kernel/PermuteLayer.h b/runtime/onert/core/src/backend/controlflow/kernel/PermuteLayer.h
new file mode 100644
index 000000000..5d0f1918e
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/kernel/PermuteLayer.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_KERNEL_PERMUTELAYER_H__
+#define __ONERT_BACKEND_CONTROLFLOW_KERNEL_PERMUTELAYER_H__
+
+#include "backend/ITensorBuilder.h"
+#include "exec/IPermuteFunction.h"
+#include "exec/IExecutor.h"
+#include "../ExternalContext.h"
+#include "ruy/thread_pool.h" // from @ruy
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+namespace kernel
+{
+
+class PermuteLayer : public onert::exec::IPermuteFunction
+{
+public:
+ PermuteLayer(const std::vector<ITensor *> &src_tensors, const std::vector<ITensor *> &dst_tensors,
+ const std::shared_ptr<ExternalContext> &external_context);
+
+ void optimize() override;
+
+ void run() override;
+
+private:
+ std::shared_ptr<ExternalContext> _external_context;
+
+private:
+ void appendPermuteTasks(const ITensor *src_tensor, ITensor *dst_tensor,
+ const ir::Shape &loop_shape, size_t size);
+
+ void runPermuteTasks(backend::ITensor *src, uint8_t *dst_buffer);
+
+ struct PermuteWorkerTask : ruy::Task
+ {
+ using Strides = ir::Coordinates;
+
+ PermuteWorkerTask(const ITensor &src_tensor, ITensor &dst_tensor,
+ const ir::Coordinates &start_coords, const ir::Shape &loop_shape, size_t size)
+ : _src_buffer{src_tensor.buffer()}, _dst_buffer{dst_tensor.buffer()},
+ _src_start_offset{src_tensor.calcOffset(start_coords)},
+ _dst_start_offset{dst_tensor.calcOffset(start_coords)}, _src_strides{}, _dst_strides{},
+ _loop_shape{loop_shape}, _size{size}, _src_layout{src_tensor.layout()},
+ _dst_layout{dst_tensor.layout()}, _is_permutation{true}
+ {
+ // Set strides
+ setStrides(src_tensor, &_src_strides);
+ setStrides(dst_tensor, &_dst_strides);
+
+ _is_permutation = (_src_layout != _dst_layout && loop_shape.rank() == 4);
+ }
+ // Constructor for a copy
+ PermuteWorkerTask(const uint8_t *src_buffer, uint8_t *dst_buffer, uint32_t src_start_offset,
+ uint32_t dst_start_offset, size_t size)
+ : _src_buffer{src_buffer}, _dst_buffer{dst_buffer}, _src_start_offset{src_start_offset},
+ _dst_start_offset{dst_start_offset}, _src_strides{0}, _dst_strides{0}, _loop_shape{1},
+ _size{size}, _src_layout{}, _dst_layout{}, _is_permutation{false}
+ {
+ // DO NOTHING
+ }
+ void setBuffers(const uint8_t *src_buffer, uint8_t *dst_buffer)
+ {
+ _src_buffer = src_buffer;
+ _dst_buffer = dst_buffer;
+ }
+ void Run() override
+ {
+ ShapeLoop(_loop_shape, [&](const onert::ir::Coordinates &coords) {
+ size_t src_offset = _src_start_offset;
+ size_t dst_offset = _dst_start_offset;
+ assert(static_cast<size_t>(_loop_shape.rank()) == coords.size());
+ ir::Coordinates dst_coords = coords;
+ if (_is_permutation)
+ {
+ dst_coords = ir::convertCoordinates(coords, _src_layout, _dst_layout);
+ }
+ for (auto i = 0; i < _loop_shape.rank(); ++i)
+ {
+ assert(coords[i] >= 0 && dst_coords[i] >= 0);
+ src_offset += coords[i] * _src_strides[i];
+ dst_offset += dst_coords[i] * _dst_strides[i];
+ }
+ memcpy(_dst_buffer + dst_offset, _src_buffer + src_offset, _size);
+ });
+ }
+
+ private:
+ void setStrides(const ITensor &tensor, Strides *strides)
+ {
+ const size_t rank = tensor.num_dimensions();
+ for (size_t i = 0; i < rank; ++i)
+ {
+ ir::Coordinates no_step(rank), one_step(rank);
+ one_step.set(i, 1);
+ if (tensor.dimension(i) > 1)
+ {
+ strides->set(i, tensor.calcOffset(one_step) - tensor.calcOffset(no_step));
+ }
+ else
+ {
+ // If dimension value is 0 or 1, the stride of the dimension will be not used
+ // Do not call calcOffset() with coordinate value that is greater than dimension value
+ strides->set(i, 0);
+ }
+ assert((*strides)[i] >= 0);
+ }
+ }
+
+ private:
+ const uint8_t *_src_buffer;
+ uint8_t *_dst_buffer;
+ size_t _src_start_offset;
+ size_t _dst_start_offset;
+ Strides _src_strides;
+ Strides _dst_strides;
+ const ir::Shape _loop_shape;
+ const size_t _size;
+ const ir::Layout _src_layout;
+ const ir::Layout _dst_layout;
+ bool _is_permutation;
+ };
+ std::unordered_map<const ITensor *, std::vector<PermuteWorkerTask>> _tasks_map;
+};
+
+} // namespace kernel
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_KERNEL_PERMUTELAYER_H__
diff --git a/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.cc b/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.cc
new file mode 100644
index 000000000..a0d478603
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.cc
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "WhileLayer.h"
+
+#include <backend/ITensor.h>
+#include "exec/ExecutorBase.h"
+#include <misc/polymorphic_downcast.h>
+#include "PermuteLayer.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+namespace kernel
+{
+
+WhileLayer::WhileLayer(const std::vector<backend::ITensor *> input_tensors,
+ const std::vector<backend::ITensor *> output_tensors,
+ const ir::OperandIndexSequence &output_indices, const ir::Graph &graph,
+ const ir::SubgraphIndex &cond_subg_index,
+ const ir::SubgraphIndex &body_subg_index, exec::ExecutorMap *executor_map,
+ const std::shared_ptr<ExternalContext> &external_context)
+ : _cond_subg_index{cond_subg_index}, _body_subg_index{body_subg_index},
+ _output_indices{output_indices}, _graph{graph}, _input_tensors{input_tensors},
+ _output_tensors{output_tensors}, _executor_map{executor_map},
+ _external_context{external_context}
+{
+ // At this point, executor_map may not have executors of cond subg and body subg
+}
+
+void WhileLayer::run()
+{
+ // Copy "_input_tensors" -> "cond subg inputs"
+ // Run cond subg
+ // Start loop while output of cond subg is ture
+ // // Copy "_input_tensors" -> "body subg inputs" in the first iteration, then copy "body subg
+ // outputs" -> "body subg inputs" in the second or more iterations
+ // // Run body subg
+ // // Copy "body subg outputs" -> "cond subg inputs"
+ // // Run cond subg
+ // If there is no loop copy "_input_tensors" -> "_dst_tensors", else copy "cond subg inputs" ->
+ // "_dst_tensors"
+ auto cond_exec = nnfw::misc::polymorphic_downcast<exec::ExecutorBase *>(
+ _executor_map->at(_cond_subg_index).get());
+ auto body_exec = nnfw::misc::polymorphic_downcast<exec::ExecutorBase *>(
+ _executor_map->at(_body_subg_index).get());
+
+ const auto &cond_graph = cond_exec->graph();
+ const auto &body_graph = body_exec->graph();
+
+ std::vector<backend::ITensor *> input_tensors;
+ std::vector<backend::ITensor *> cond_input_tensors;
+ std::vector<backend::ITensor *> body_input_tensors;
+ std::vector<backend::ITensor *> body_output_tensors;
+ std::vector<backend::ITensor *> output_tensors;
+
+ // Add only used tensors in cond subgraph
+ assert(cond_graph.getInputs().size() == _input_tensors.size());
+ assert(cond_graph.getInputs().size() == cond_exec->getInputTensors().size());
+ for (uint32_t i = 0; i < cond_graph.getInputs().size(); ++i)
+ {
+ const auto &cond_input = cond_graph.operands().at(cond_graph.getInputs().at(i));
+ if (cond_input.getUses().size() > 0)
+ {
+ input_tensors.emplace_back(_input_tensors.at(i));
+ cond_input_tensors.emplace_back(cond_exec->getInputTensors().at(i));
+ }
+ }
+ const auto permute_op_input_to_cond_input =
+ std::make_shared<PermuteLayer>(input_tensors, cond_input_tensors, _external_context);
+
+ // Add only used tensors among outputs of while operation
+ assert(_output_indices.size() == _input_tensors.size());
+ assert(_output_indices.size() == _output_tensors.size());
+ input_tensors.clear();
+ output_tensors.clear();
+ for (size_t i = 0; i < _output_indices.size(); ++i)
+ {
+ const auto &output_index = _output_indices.at(i);
+ const auto &output = _graph.operands().at(output_index);
+ if (output.getUses().size() > 0 || _graph.getOutputs().contains(output_index))
+ {
+ input_tensors.emplace_back(_input_tensors.at(i));
+ output_tensors.emplace_back(_output_tensors.at(i));
+ }
+ }
+ const auto permute_op_input_to_op_output =
+ std::make_shared<PermuteLayer>(input_tensors, output_tensors, _external_context);
+
+ // Add all tensors with unused tensors in body subgraph because unused input tensors will be
+ // copied output tensors in body subgraph
+ assert(_input_tensors.size() == body_exec->getInputTensors().size());
+ input_tensors = _input_tensors;
+ body_input_tensors = body_exec->getInputTensors();
+ const auto permute_op_input_to_body_input =
+ std::make_shared<PermuteLayer>(input_tensors, body_input_tensors, _external_context);
+
+ // Add only used tensors in cond subgraph
+ assert(cond_graph.getInputs().size() == body_exec->getOutputTensors().size());
+ assert(cond_graph.getInputs().size() == cond_exec->getInputTensors().size());
+ body_output_tensors.clear();
+ cond_input_tensors.clear();
+ for (uint32_t i = 0; i < cond_graph.getInputs().size(); ++i)
+ {
+ const auto &cond_input = cond_graph.operands().at(cond_graph.getInputs().at(i));
+ if (cond_input.getUses().size() > 0)
+ {
+ body_output_tensors.emplace_back(body_exec->getOutputTensors().at(i));
+ cond_input_tensors.emplace_back(cond_exec->getInputTensors().at(i));
+ }
+ }
+ const auto permute_body_output_to_cond_input =
+ std::make_shared<PermuteLayer>(body_output_tensors, cond_input_tensors, _external_context);
+
+ // Add only used tensors in body subgraph
+ assert(body_graph.getInputs().size() == body_exec->getOutputTensors().size());
+ assert(body_graph.getInputs().size() == body_exec->getInputTensors().size());
+ body_output_tensors.clear();
+ body_input_tensors.clear();
+ for (uint32_t i = 0; i < body_graph.getInputs().size(); ++i)
+ {
+ const auto &body_input_index = body_graph.getInputs().at(i);
+ const auto &body_input = body_graph.operands().at(body_input_index);
+ if (body_input.getUses().size() > 0 &&
+ !body_exec->graph().getOutputs().contains(body_input_index))
+ {
+ body_output_tensors.emplace_back(body_exec->getOutputTensors().at(i));
+ body_input_tensors.emplace_back(body_exec->getInputTensors().at(i));
+ }
+ }
+ const auto permute_body_output_to_body_input =
+ std::make_shared<PermuteLayer>(body_output_tensors, body_input_tensors, _external_context);
+
+ // Add only used tensors among outputs of while operation
+ assert(_output_indices.size() == body_exec->getOutputTensors().size());
+ assert(_output_indices.size() == _output_tensors.size());
+ body_output_tensors.clear();
+ output_tensors.clear();
+ for (size_t i = 0; i < _output_indices.size(); ++i)
+ {
+ const auto &output_index = _output_indices.at(i);
+ const auto &output = _graph.operands().at(output_index);
+ if (output.getUses().size() > 0 || _graph.getOutputs().contains(output_index))
+ {
+ body_output_tensors.emplace_back(body_exec->getOutputTensors().at(i));
+ output_tensors.emplace_back(_output_tensors.at(i));
+ }
+ }
+ const auto permute_body_output_to_op_output =
+ std::make_shared<PermuteLayer>(body_output_tensors, output_tensors, _external_context);
+
+ // Remove copying of unused tensor
+ permute_op_input_to_cond_input->prepare();
+ permute_op_input_to_op_output->prepare();
+ permute_op_input_to_body_input->prepare();
+ permute_body_output_to_cond_input->prepare();
+ permute_body_output_to_body_input->prepare();
+ permute_body_output_to_op_output->prepare();
+
+ VERBOSE(While) << "Call to $" << _cond_subg_index << " (cond)" << std::endl;
+ cond_exec->execute(_input_tensors, permute_op_input_to_cond_input);
+ VERBOSE(While) << "Return from $" << _cond_subg_index << std::endl;
+
+ assert(cond_exec->getOutputTensors().size() == 1);
+ auto &cond_output_tensor = cond_exec->getOutputTensors().at(0);
+ auto getResultCond = [](backend::ITensor *tensor) -> bool {
+ bool ret = false;
+ tensor->access([&](ITensor &tensor) { ret = *reinterpret_cast<bool *>(tensor.buffer()); });
+ return ret;
+ };
+
+ const auto body_execute_with_op_inputs = [&]() {
+ VERBOSE(While) << "Call to $" << _body_subg_index << " (body)" << std::endl;
+ body_exec->execute(_input_tensors, permute_op_input_to_body_input);
+ VERBOSE(While) << "Return from $" << _body_subg_index << std::endl;
+ };
+
+ const auto body_execute_with_body_outputs = [&]() {
+ VERBOSE(While) << "Call to $" << _body_subg_index << " (body)" << std::endl;
+ body_exec->execute(body_exec->getOutputTensors(), permute_body_output_to_body_input);
+ VERBOSE(While) << "Return from $" << _body_subg_index << std::endl;
+ };
+
+ std::function<void()> body_execute = body_execute_with_op_inputs;
+ const auto cond_execute = [&]() {
+ VERBOSE(While) << "Call to $" << _cond_subg_index << " (cond)" << std::endl;
+ cond_exec->execute(body_exec->getOutputTensors(), permute_body_output_to_cond_input);
+ VERBOSE(While) << "Return from $" << _cond_subg_index << std::endl;
+ };
+ auto permute_to_outputs_fn = permute_op_input_to_op_output;
+
+ // Loop while Cond subgraph's output is true
+ while (getResultCond(cond_output_tensor))
+ {
+ body_execute();
+ cond_execute();
+ body_execute = body_execute_with_body_outputs;
+ permute_to_outputs_fn = permute_body_output_to_op_output;
+ }
+ permute_to_outputs_fn->run();
+}
+
+} // namespace kernel
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.h b/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.h
new file mode 100644
index 000000000..8f82bd973
--- /dev/null
+++ b/runtime/onert/core/src/backend/controlflow/kernel/WhileLayer.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CONTROLFLOW_KERNEL_WHILE_LAYER_H__
+#define __ONERT_BACKEND_CONTROLFLOW_KERNEL_WHILE_LAYER_H__
+
+#include <backend/ITensor.h>
+#include <exec/IExecutor.h>
+#include <exec/IFunction.h>
+#include <ir/OperandIndexSequence.h>
+#include <ir/Graph.h>
+#include "../ExternalContext.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace controlflow
+{
+namespace kernel
+{
+
+class WhileLayer : public ::onert::exec::IFunction
+{
+public:
+ WhileLayer(const std::vector<backend::ITensor *> input_tensors,
+ const std::vector<backend::ITensor *> output_tensors,
+ const ir::OperandIndexSequence &output_indices, const ir::Graph &graph,
+ const ir::SubgraphIndex &cond_subg_index, const ir::SubgraphIndex &body_subg_index,
+ exec::ExecutorMap *executor_map,
+ const std::shared_ptr<ExternalContext> &external_context);
+
+public:
+ void run() override;
+
+private:
+ const ir::SubgraphIndex _cond_subg_index;
+ const ir::SubgraphIndex _body_subg_index;
+ const ir::OperandIndexSequence &_output_indices;
+ const ir::Graph &_graph;
+ const std::vector<backend::ITensor *> _input_tensors;
+ const std::vector<backend::ITensor *> _output_tensors;
+ exec::ExecutorMap *_executor_map;
+ const std::shared_ptr<ExternalContext> _external_context;
+};
+
+} // namespace kernel
+} // namespace controlflow
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CONTROLFLOW_KERNEL_WHILE_LAYER_H__
diff --git a/runtime/onert/core/src/backend/cpu_common/Allocator.cc b/runtime/onert/core/src/backend/cpu_common/Allocator.cc
new file mode 100644
index 000000000..0ba444ee6
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/Allocator.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/cpu_common/Allocator.h"
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+Allocator::Allocator(uint32_t capacity)
+{
+ _base = std::make_unique<uint8_t[]>(capacity);
+
+ VERBOSE(ALLOC) << "allocation capacity: " << capacity << std::endl;
+ VERBOSE(ALLOC) << "base pointer: " << static_cast<void *>(_base.get()) << std::endl;
+}
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/cpu_common/DynamicTensorManager.cc b/runtime/onert/core/src/backend/cpu_common/DynamicTensorManager.cc
new file mode 100644
index 000000000..740248ccd
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/DynamicTensorManager.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/cpu_common/DynamicTensorManager.h"
+
+#include "util/logging.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+DynamicTensorManager::DynamicTensorManager(const std::shared_ptr<TensorRegistry> &reg)
+ : _dynamic_mem_mgr{new DynamicMemoryManager()}, _tensors{reg}
+{
+ // DO NOTHING
+}
+
+void DynamicTensorManager::buildTensor(const ir::OperandIndex &ind,
+ const ir::OperandInfo &tensor_info,
+ ir::Layout backend_layout)
+{
+ assert(_tensors->getNativeTensor(ind) == nullptr);
+ auto tensor = std::make_unique<Tensor>(tensor_info, backend_layout, _dynamic_mem_mgr.get());
+ _tensors->setNativeTensor(ind, std::move(tensor));
+}
+
+void DynamicTensorManager::planDealloc(ir::OperationIndex op_ind, backend::ITensor *tensor)
+{
+ _dealloc_tensor_map[op_ind].emplace(tensor);
+}
+
+void DynamicTensorManager::deallocInput(ir::OperationIndex op_ind)
+{
+ auto find = _dealloc_tensor_map.find(op_ind);
+ if (find == _dealloc_tensor_map.end())
+ return;
+
+ auto &input_set = find->second;
+ for (auto *tensor : input_set)
+ {
+ if (!tensor->is_dynamic())
+ continue;
+
+ _dynamic_mem_mgr->deallocate(tensor);
+
+ auto *cpu_tensor = nnfw::misc::polymorphic_downcast<cpu_common::Tensor *>(tensor);
+ cpu_tensor->resetBuffer();
+
+ VERBOSE(DynamicTensorManager) << "Deallocating tensor " << (void *)cpu_tensor
+ << " (input of op_ind: " << op_ind.value() << ")" << std::endl;
+ }
+}
+
+const ITensor *DynamicTensorManager::getRawITensor(ir::OperandIndex ind)
+{
+ auto ptr = _tensors->getITensor(ind);
+ assert(ptr);
+ return ptr;
+}
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/cpu_common/MemoryManager.cc b/runtime/onert/core/src/backend/cpu_common/MemoryManager.cc
new file mode 100644
index 000000000..9f179d9ee
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/MemoryManager.cc
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <backend/cpu_common/MemoryManager.h>
+
+#include <cassert>
+
+#include "MemoryPlannerFactory.h"
+#include "util/ConfigSource.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+MemoryManager::MemoryManager() : _mem_planner{createMemoryPlanner()}
+{
+ // DO NOTHING
+}
+
+MemoryManager::MemoryManager(const std::string planner_id)
+ : _mem_planner{createMemoryPlanner(planner_id)}
+{
+ // DO NOTHING
+}
+
+cpu_common::IMemoryPlanner *MemoryManager::createMemoryPlanner()
+{
+ auto planner_id = util::getConfigString(util::config::CPU_MEMORY_PLANNER);
+ return cpu_common::MemoryPlannerFactory::get().create(planner_id);
+}
+
+cpu_common::IMemoryPlanner *MemoryManager::createMemoryPlanner(const std::string planner_id)
+{
+ return cpu_common::MemoryPlannerFactory::get().create(planner_id);
+}
+
+void MemoryManager::claimPlan(const ir::OperandIndex &ind, uint32_t size)
+{
+ _mem_planner->claim(ind, size);
+}
+
+void MemoryManager::releasePlan(const ir::OperandIndex &ind) { _mem_planner->release(ind); }
+
+void MemoryManager::allocate(void)
+{
+ _mem_alloc = std::make_shared<cpu_common::Allocator>(_mem_planner->capacity());
+ assert(_mem_alloc->base());
+}
+
+uint8_t *MemoryManager::getBuffer(const ir::OperandIndex &ind) const
+{
+ assert(_mem_planner->memory_plans().find(ind) != _mem_planner->memory_plans().end());
+ const auto &mem_blk = _mem_planner->memory_plans().at(ind);
+ return _mem_alloc->base() + mem_blk.offset;
+}
+
+std::shared_ptr<cpu_common::Allocator> DynamicMemoryManager::allocate(const ITensor *tensor,
+ uint32_t capacity)
+{
+ auto find = _mem_alloc_map.find(tensor);
+ if (find != _mem_alloc_map.end())
+ throw std::runtime_error("Cannot allocate memory for a tensor. It was already allocated.");
+
+ _mem_alloc_map[tensor] = std::make_shared<cpu_common::Allocator>(capacity);
+ return _mem_alloc_map[tensor];
+}
+
+void DynamicMemoryManager::deallocate(const ITensor *tensor)
+{
+ auto find = _mem_alloc_map.find(tensor);
+ if (find == _mem_alloc_map.end())
+ throw std::runtime_error("Cannot find Allocator for the requested index");
+
+ find->second->release(); // explicitly erase memory
+ _mem_alloc_map.erase(find); // remove tensor and alloc
+}
+
+void DynamicMemoryManager::deallocate(void)
+{
+ for (auto &mem_alloc : _mem_alloc_map)
+ {
+ // Release memory buffer of mem_alloc
+ mem_alloc.second->release();
+ }
+
+ _mem_alloc_map.clear();
+}
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.cc b/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.cc
new file mode 100644
index 000000000..01cd1a0fe
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.cc
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MemoryPlanner.h"
+#include "util/logging.h"
+#include <cassert>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+void BumpPlanner::claim(const ir::OperandIndex &ind, size_t size)
+{
+ Block blk{_capacity, size};
+ _mem_plans[ind] = blk;
+ _capacity += size;
+
+ VERBOSE(BP_PLANNER) << "CLAIM(#" << ind.value() << "): " << blk.offset << ", " << blk.size
+ << std::endl;
+}
+
+void BumpPlanner::release(const ir::OperandIndex &ind)
+{
+ VERBOSE(BP_PLANNER) << "RELEASE(#" << ind.value() << "): "
+ << "NOTHING does" << std::endl;
+}
+
+// There are some assumptions for claiming memory(== making a reservation for memory).
+// 1. About _claim_table(std::map).
+// - The table's data structure is std::map so that it always sorts
+// value(OperandIndex) by key(base_offset).
+// - This claim() inserts key/value into _claim_table and the release() removes the key/value from
+// _claim_table.
+// - _claim_table shows the memory status at a certain point in time. Therefore,
+// - If _claim_table has an offset and a certain size at a certain point in time,
+// it means the place at the offset has been already claimed(== can't claim now. need to find
+// someplace new).
+// - If _claim_table doesn't have any element for an offset and a certain size at a certain
+// point in time, it means the place at the offset can be claimed.
+// 2. In the loop for _claim_table, we can assume the current claim_base_offset value is bigger than
+// the previous claim_base_offset.
+void FirstFitPlanner::claim(const ir::OperandIndex &ind, size_t size)
+{
+ // Find the right position for claiming
+ uint32_t next_offset = 0;
+ for (auto &mem_claim : _claim_table)
+ {
+ auto claimed_base_offset = mem_claim.first;
+ auto claimed_size = _mem_plans[mem_claim.second].size;
+ if (next_offset + size <= claimed_base_offset)
+ {
+ break;
+ }
+ else
+ {
+ next_offset = claimed_base_offset + claimed_size;
+ }
+ }
+
+ // Now next_offset is set to the proper offset
+ _claim_table[next_offset] = ind;
+ _mem_plans[ind] = {next_offset, size};
+
+ VERBOSE(FF_PLANNER) << "claim(#" << ind.value() << "): [+" << next_offset << ", " << size << "sz]"
+ << std::endl;
+
+ if (_capacity < next_offset + size)
+ {
+ _capacity = next_offset + size;
+ }
+}
+
+void FirstFitPlanner::release(const ir::OperandIndex &ind)
+{
+ for (auto it = _claim_table.cbegin(); it != _claim_table.cend(); ++it)
+ {
+ if (it->second == ind)
+ {
+ uint32_t offset = it->first;
+ uint32_t index = ind.value();
+ uint32_t size = _mem_plans[ind].size;
+
+ _claim_table.erase(it);
+
+ VERBOSE(FF_PLANNER) << "release(#" << index << "): [+" << offset << ", " << size << "sz]"
+ << std::endl;
+ return;
+ }
+ }
+ assert(!"Cannot release for given index. It has been not claimed or released already.");
+}
+
+WICPlanner::WICPlanner()
+ : _initialized(false), _capacity(0), _mem_plans(), _live_operands(), _interference_graph(),
+ _operands()
+{
+ // DO NOTHING
+}
+
+void WICPlanner::claim(const ir::OperandIndex &ind, size_t size)
+{
+ _operands.emplace(size, ind);
+ _interference_graph[ind].insert(_interference_graph[ind].end(), _live_operands.cbegin(),
+ _live_operands.cend());
+ for (const auto &live_operand : _live_operands)
+ {
+ _interference_graph[live_operand].emplace_back(ind);
+ }
+ _live_operands.emplace(ind);
+
+ VERBOSE(WIC_PLANNER) << "claim(#" << ind.value() << "): [" << size << "sz]" << std::endl;
+}
+
+void WICPlanner::release(const ir::OperandIndex &ind)
+{
+ _live_operands.erase(ind);
+ VERBOSE(WIC_PLANNER) << "release(#" << ind.value() << ")" << std::endl;
+}
+
+/*
+ * Build memory plans using liveness and size of operands
+ * 1. Build inference graph at claim
+ * - Two operands interfere if they have overlapped live range
+ * 2. Sort operands in descending order of size
+ * - Use std::multimap to sort operands
+ * 3. Allocate memory block for sorted operands
+ * - Find free memory block which does not overlap with interfered operands
+ */
+void WICPlanner::buildMemoryPlans()
+{
+ for (const auto &operand : _operands)
+ {
+ uint32_t size = operand.first;
+ const ir::OperandIndex &ind = operand.second;
+ VERBOSE(WIC_PLANNER) << "build_plan(#" << ind.value() << "): [" << size << "sz]" << std::endl;
+
+ uint32_t next_offset = 0;
+ if (_interference_graph.count(ind))
+ {
+ // Find interfered memory plans and sort them by offset
+ std::multimap<uint32_t, uint32_t> interfered_plans;
+ for (const auto &interference : _interference_graph[ind])
+ {
+ if (_mem_plans.count(interference))
+ interfered_plans.emplace(_mem_plans[interference].offset, _mem_plans[interference].size);
+ }
+
+ // Find free memory block in first-fit manner
+ for (const auto &interfered_plan : interfered_plans)
+ {
+ auto claimed_base_offset = interfered_plan.first;
+ auto claimed_size = interfered_plan.second;
+ VERBOSE(WIC_PLANNER) << "interfere : [+" << claimed_base_offset << ", " << claimed_size
+ << "sz]" << std::endl;
+ if (next_offset + size <= claimed_base_offset)
+ {
+ break;
+ }
+ else if (next_offset < claimed_base_offset + claimed_size)
+ {
+ next_offset = claimed_base_offset + claimed_size;
+ }
+ }
+ }
+ else
+ {
+ VERBOSE(WIC_PLANNER) << "No interference" << std::endl;
+ }
+
+ _mem_plans[ind] = {next_offset, size};
+ VERBOSE(WIC_PLANNER) << "alloc(#" << ind.value() << "): [+" << next_offset << ", " << size
+ << "sz]" << std::endl;
+
+ if (_capacity < next_offset + size)
+ {
+ _capacity = next_offset + size;
+ }
+ }
+ _initialized = true;
+ _interference_graph.clear();
+ _operands.clear();
+}
+
+WICPlanner::MemoryPlans &WICPlanner::memory_plans()
+{
+ if (!_initialized)
+ buildMemoryPlans();
+ return _mem_plans;
+}
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.h b/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.h
new file mode 100644
index 000000000..7c387e542
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        MemoryPlanner.h
+ * @brief       This file contains Memory Planning related classes
+ */
+
+#ifndef __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_H__
+#define __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_H__
+
+#include <map>
+#include <vector>
+#include <unordered_set>
+#include <memory>
+
+#include "backend/cpu_common/Allocator.h"
+#include "backend/cpu_common/IMemoryPlanner.h"
+#include "ir/OperandIndexMap.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+/**
+ * @brief Class to plan memory by bump way
+ */
+class BumpPlanner : public IMemoryPlanner
+{
+public:
+ /**
+ * @brief Claim memory for operand by bump way
+ * @param[in] index The operand index
+ * @param[in] size The size of the memory
+ */
+ void claim(const ir::OperandIndex &, size_t) override;
+ /**
+ * @brief Release memory for operand by bump way
+ * @param[in] index The operand index
+ */
+ void release(const ir::OperandIndex &) override;
+ /**
+ * @brief Get capacity for memory planning
+ * @return The value of capacity
+ */
+ uint32_t capacity() override { return _capacity; }
+ /**
+ * @brief Get MemoryPlans
+ * @return MemoryPlans
+ */
+ MemoryPlans &memory_plans() override { return _mem_plans; }
+
+private:
+ uint32_t _capacity = 0;
+ MemoryPlans _mem_plans;
+};
+
+/**
+ * @brief Class to plan memory by firstfit way
+ */
+class FirstFitPlanner : public IMemoryPlanner
+{
+public:
+ /**
+ * @brief Claim memory for operand by firstfit way
+ * @param[in] index The operand index
+ * @param[in] size The size of the memory
+ */
+ void claim(const ir::OperandIndex &, size_t) override;
+ /**
+ * @brief Release memory for operand by firstfit way
+ * @param[in] index The operand index
+ */
+ void release(const ir::OperandIndex &) override;
+ /**
+ * @brief Get capacity for memory planning
+ * @return The value of capacity
+ */
+ uint32_t capacity() override { return _capacity; }
+ /**
+ * @brief Get MemoryPlans
+ * @return MemoryPlans
+ */
+ MemoryPlans &memory_plans() override { return _mem_plans; }
+
+private:
+ uint32_t _capacity = 0;
+ MemoryPlans _mem_plans;
+ // Use std::map because claim() assumes that _claim_table is sorted by uint32_t(base_offset)
+ std::map<uint32_t, ir::OperandIndex> _claim_table;
+};
+
+/**
+ * @brief Class to plan memory by Weighted Interval Color algorithm
+ */
+class WICPlanner : public IMemoryPlanner
+{
+public:
+ WICPlanner();
+
+ /**
+ * @brief Claim memory for operand by WIC algorithm
+ * @param[in] index The operand index
+ * @param[in] size The size of the memory
+ */
+ void claim(const ir::OperandIndex &, size_t) override;
+ /**
+ * @brief Release memory for operand by WIC algorithm
+ * @param[in] index The operand index
+ */
+ void release(const ir::OperandIndex &) override;
+ /**
+ * @brief Get capacity for memory planning
+ * @return The value of capacity
+ */
+ uint32_t capacity() override
+ {
+ if (!_initialized)
+ buildMemoryPlans();
+ return _capacity;
+ }
+ /**
+ * @brief Get MemoryPlans
+ * @return MemoryPlans
+ */
+ MemoryPlans &memory_plans() override;
+
+private:
+ void buildMemoryPlans();
+
+ bool _initialized;
+ uint32_t _capacity;
+ MemoryPlans _mem_plans;
+ std::unordered_set<ir::OperandIndex> _live_operands;
+ ir::OperandIndexMap<std::vector<ir::OperandIndex>> _interference_graph;
+ // Sort operands by descending order of size
+ std::multimap<uint32_t, ir::OperandIndex, std::greater<uint32_t>> _operands;
+};
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_H__
diff --git a/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.test.cc b/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.test.cc
new file mode 100644
index 000000000..5208a94d4
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/MemoryPlanner.test.cc
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "MemoryPlanner.h"
+#include "ir/Index.h"
+
+TEST(Allocator, allocate_test)
+{
+ ::onert::backend::cpu_common::Allocator allocator(1024);
+ ASSERT_NE(allocator.base(), nullptr);
+}
+
+TEST(BumpPlanner, claim_test)
+{
+ ::onert::backend::cpu_common::BumpPlanner planner;
+
+ auto claim = [&planner](uint32_t index, size_t size, uint32_t expected_offset) {
+ onert::ir::OperandIndex mem_idx(index);
+ planner.claim(mem_idx, size);
+ auto mem_blk = planner.memory_plans()[mem_idx];
+ ASSERT_EQ(mem_blk.offset, expected_offset);
+ ASSERT_EQ(mem_blk.size, size);
+ };
+
+ claim(0, 10, 0);
+ claim(1, 20, 10);
+ claim(2, 30, 30);
+}
+
+TEST(FirstFitPlanner, claim_release_test)
+{
+ ::onert::backend::cpu_common::FirstFitPlanner planner;
+
+ auto claim = [&planner](uint32_t index, size_t size, uint32_t expected_offset) {
+ onert::ir::OperandIndex mem_idx(index);
+ planner.claim(mem_idx, size);
+ auto mem_blk = planner.memory_plans()[mem_idx];
+ ASSERT_EQ(mem_blk.offset, expected_offset);
+ ASSERT_EQ(mem_blk.size, size);
+ };
+
+ auto release = [&planner](uint32_t index) {
+ onert::ir::OperandIndex mem_idx(index);
+ planner.release(mem_idx);
+ };
+
+ // 0 CLAIM - 10
+ claim(0, 10, 0);
+
+ // 1 CLAIM - 20
+ claim(1, 20, 10);
+
+ // 2 CLAIM - 30
+ claim(2, 30, 30);
+
+ // 0 RELEASE - 10
+ release(0);
+
+ // 3 CLAIM - 20
+ claim(3, 20, 60);
+
+ // 4 CLAIM - 5
+ claim(4, 5, 0);
+
+ // 5 CLAIM - 10
+ claim(5, 10, 80);
+
+ // 6 CLAIM - 5
+ claim(6, 5, 5);
+
+ // 2 RELEASE - 30
+ release(2);
+
+ // 7 CLAIM - 35
+ claim(7, 35, 90);
+
+ // 8 CLAIM - 10
+ claim(8, 10, 30);
+
+ // 4 RELEASE - 5
+ release(4);
+
+ // 9 CLAIM - 10
+ claim(9, 10, 40);
+
+ // 10 CLAIM - 10
+ claim(10, 10, 50);
+
+ // 6 RELEASE
+ release(6);
+
+ // 1 RELEASE
+ release(1);
+
+ // 8 RELEASE
+ release(8);
+
+ // 9 RELEASE
+ release(9);
+
+ // 10 RELEASE
+ release(10);
+
+ // 3 RELEASE
+ release(3);
+
+ // 5 RELEASE
+ release(5);
+
+ // 7 RELEASE
+ release(7);
+}
+
+TEST(WICPlanner, claim_release_test)
+{
+ ::onert::backend::cpu_common::WICPlanner planner;
+
+ auto claim = [&planner](uint32_t index, size_t size) {
+ onert::ir::OperandIndex mem_idx(index);
+ planner.claim(mem_idx, size);
+ };
+
+ auto release = [&planner](uint32_t index) {
+ onert::ir::OperandIndex mem_idx(index);
+ planner.release(mem_idx);
+ };
+
+ auto verify = [&planner](uint32_t index, uint32_t size, uint32_t expected_offset) {
+ onert::ir::OperandIndex mem_idx(index);
+ auto mem_blk = planner.memory_plans()[mem_idx];
+ ASSERT_EQ(mem_blk.offset, expected_offset);
+ ASSERT_EQ(mem_blk.size, size);
+ };
+
+ auto capacity = [&planner](uint32_t expected_capacity) {
+ auto actual_capacity = planner.capacity();
+ ASSERT_EQ(actual_capacity, expected_capacity);
+ };
+
+ claim(0, 20);
+ claim(1, 5);
+ release(0);
+ claim(2, 10);
+ release(1);
+ claim(3, 10);
+ release(2);
+ claim(4, 10);
+ release(3);
+ claim(5, 20);
+ release(4);
+ claim(6, 20);
+ release(5);
+ release(7);
+
+ // VERIFY 0 - 0
+ verify(0, 20, 0);
+
+ // VERIFY 1 - 20
+ verify(1, 5, 20);
+
+ // VERIFY 2 - 0
+ verify(2, 10, 0);
+
+ // VERIFY 3 - 10
+ verify(3, 10, 10);
+
+ // VERIFY 4 - 20
+ verify(4, 10, 20);
+
+ // VERIFY 5 - 0
+ verify(5, 20, 0);
+
+ // VERIFY 6 - 20
+ verify(6, 20, 20);
+
+ // CAPACITY - 40
+ capacity(40);
+}
diff --git a/runtime/onert/core/src/backend/cpu_common/MemoryPlannerFactory.cc b/runtime/onert/core/src/backend/cpu_common/MemoryPlannerFactory.cc
new file mode 100644
index 000000000..ead4f3294
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/MemoryPlannerFactory.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MemoryPlannerFactory.h"
+
+#include "MemoryPlanner.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+MemoryPlannerFactory &MemoryPlannerFactory::get()
+{
+ static MemoryPlannerFactory instance;
+ return instance;
+}
+
+IMemoryPlanner *MemoryPlannerFactory::create(const std::string &key)
+{
+ if (key == "FirstFit")
+ {
+ return new FirstFitPlanner;
+ }
+ else if (key == "Bump")
+ {
+ return new BumpPlanner;
+ }
+ else if (key == "WIC")
+ {
+ return new WICPlanner;
+ }
+ return new FirstFitPlanner; // Default Planner
+}
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/cpu_common/MemoryPlannerFactory.h b/runtime/onert/core/src/backend/cpu_common/MemoryPlannerFactory.h
new file mode 100644
index 000000000..d14ec13ca
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/MemoryPlannerFactory.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_FACTORY_H__
+#define __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_FACTORY_H__
+
+#include "backend/cpu_common/IMemoryPlanner.h"
+
+#include <string>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+class MemoryPlannerFactory
+{
+public:
+ static MemoryPlannerFactory &get();
+
+private:
+ MemoryPlannerFactory() = default;
+
+public:
+ IMemoryPlanner *create(const std::string &key);
+};
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
+
+#endif // __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_FACTORY_H__
diff --git a/runtime/onert/core/src/backend/cpu_common/StaticTensorManager.cc b/runtime/onert/core/src/backend/cpu_common/StaticTensorManager.cc
new file mode 100644
index 000000000..cac43babe
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/StaticTensorManager.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/cpu_common/StaticTensorManager.h"
+
+#include "backend/cpu_common/DynamicTensorManager.h"
+#include <util/logging.h>
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+StaticTensorManager::StaticTensorManager(const std::shared_ptr<TensorRegistry> &reg,
+ DynamicMemoryManager *dynamic_mem_mgr)
+ : _const_mgr{new DynamicMemoryManager()}, _nonconst_mgr{new MemoryManager()}, _tensors{reg},
+ _dynamic_mem_mgr{dynamic_mem_mgr}
+{
+ // DO NOTHING
+}
+
+void StaticTensorManager::allocateConsts(void)
+{
+ for (auto &pair : _tensors->native_tensors())
+ {
+ const auto &ind = pair.first;
+ auto tensor = pair.second.get();
+ if (_as_constants[ind])
+ {
+ auto mem_alloc = _const_mgr->allocate(_tensors->getITensor(ind), tensor->total_size());
+ tensor->setBuffer(mem_alloc);
+ auto buffer = mem_alloc->base();
+ VERBOSE(CPU_COMMON_StaticTensorManager) << "CONSTANT TENSOR(#" << ind.value()
+ << "): " << static_cast<void *>(buffer)
+ << "size : " << tensor->total_size() << std::endl;
+ }
+ }
+}
+
+void StaticTensorManager::allocateNonconsts(void)
+{
+ _nonconst_mgr->allocate();
+
+ for (auto &pair : _tensors->native_tensors())
+ {
+ const auto &ind = pair.first;
+ auto tensor = pair.second.get();
+ if (!_as_constants[ind] && !tensor->is_dynamic())
+ {
+ auto *buffer = _nonconst_mgr->getBuffer(ind);
+ tensor->setBuffer(buffer);
+
+ VERBOSE(CPU_COMMON_StaticTensorManager) << "TENSOR(#" << ind.value()
+ << "): " << static_cast<void *>(buffer) << std::endl;
+ }
+ }
+}
+
+void StaticTensorManager::deallocateConsts(void) { _const_mgr->deallocate(); }
+
+void StaticTensorManager::deallocateNonconsts(void) { _nonconst_mgr->deallocate(); }
+
+void StaticTensorManager::buildTensor(const ir::OperandIndex &ind,
+ const ir::OperandInfo &tensor_info, ir::Layout backend_layout,
+ bool as_const)
+{
+ assert(!_tensors->getNativeTensor(ind));
+ auto tensor = std::make_unique<Tensor>(tensor_info, backend_layout, _dynamic_mem_mgr);
+ _tensors->setNativeTensor(ind, std::move(tensor));
+ _as_constants[ind] = as_const;
+}
+
+void StaticTensorManager::claimPlan(const ir::OperandIndex &ind, uint32_t size)
+{
+ assert(_tensors->getNativeTensor(ind));
+
+ // This method is called only when a tensor has proper shape
+ assert(!_tensors->getNativeTensor(ind)->is_dynamic());
+
+ if (!_as_constants[ind])
+ _nonconst_mgr->claimPlan(ind, size);
+}
+
+void StaticTensorManager::releasePlan(const ir::OperandIndex &ind)
+{
+ assert(_tensors->getNativeTensor(ind));
+
+ // This method is called only when a tensor has proper shape
+ assert(!_tensors->getNativeTensor(ind)->is_dynamic());
+
+ if (!_as_constants[ind])
+ _nonconst_mgr->releasePlan(ind);
+}
+
+void StaticTensorManager::iterate(const std::function<void(const ir::OperandIndex &)> &fn)
+{
+ for (const auto &it : _tensors->native_tensors())
+ fn(it.first);
+}
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/backend/cpu_common/Tensor.cc b/runtime/onert/core/src/backend/cpu_common/Tensor.cc
new file mode 100644
index 000000000..d3dcf9a6d
--- /dev/null
+++ b/runtime/onert/core/src/backend/cpu_common/Tensor.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "backend/cpu_common/Tensor.h"
+
+#include "ir/DataType.h"
+#include "backend/cpu_common/MemoryManager.h"
+
+namespace onert
+{
+namespace backend
+{
+namespace cpu_common
+{
+
+Tensor::~Tensor() {}
+
+size_t Tensor::calcOffset(const ir::Coordinates &coords) const
+{
+ size_t rank = num_dimensions();
+ rank = rank == 0 ? 1 : rank;
+ size_t offset = 0;
+ for (size_t i = 0; i < rank; ++i)
+ {
+ offset = offset * dimension(i) + coords[i];
+ }
+ offset *= sizeOfDataType(data_type());
+ return offset;
+}
+
+void Tensor::setShape(const ir::Shape &new_shape) { _info.shape(new_shape); }
+
+bool Tensor::applyShape(const ir::Shape &new_shape)
+{
+ bool previously_dynamic = is_dynamic();
+
+ auto allocTensorMem = [&](bool overwrite = false) {
+ auto capacity = total_size();
+ auto alloc = _dynamic_mem_mgr->allocate(this, capacity);
+
+ if (overwrite)
+ overwriteBuffer(alloc);
+ else
+ setBuffer(alloc);
+ };
+
+ if (!previously_dynamic)
+ {
+ // TODO deallocate tensor->buffer()
+ // issue is that staticTensorManager might have allocate this memory
+ setShape(new_shape);
+ set_dynamic();
+ allocTensorMem(true);
+ }
+ else if (buffer() == nullptr)
+ {
+ setShape(new_shape);
+ set_dynamic();
+ allocTensorMem();
+ }
+ // when buffer was already allocated and new_shape requires different size
+ else
+ {
+ auto previous_size = total_size();
+ auto new_size = new_shape.num_elements() * ir::sizeOfDataType(data_type());
+ if (previous_size != new_size)
+ {
+ _dynamic_mem_mgr->deallocate(this);
+
+ setShape(new_shape);
+ set_dynamic();
+ allocTensorMem(true);
+ }
+ else
+ { // when buffer with same size was already allocated, shape could differ
+ setShape(new_shape);
+ }
+ }
+ return true;
+}
+
+} // namespace cpu_common
+} // namespace backend
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/BackendManager.cc b/runtime/onert/core/src/compiler/BackendManager.cc
new file mode 100644
index 000000000..0093f50fd
--- /dev/null
+++ b/runtime/onert/core/src/compiler/BackendManager.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/BackendManager.h"
+
+#include <memory>
+#include <dlfcn.h>
+
+#include "backend/Backend.h"
+#include "backend/controlflow/Backend.h"
+#include "backend/controlflow/Config.h"
+#include "backend/IConfig.h"
+#include "util/logging.h"
+#include "util/ConfigSource.h"
+#include "misc/string_helpers.h"
+
+static const char *SHARED_LIB_EXT =
+#if defined(__APPLE__) && defined(__MACH__)
+ ".dylib";
+#else
+ ".so";
+#endif
+
+namespace onert
+{
+namespace compiler
+{
+
+BackendManager &BackendManager::get()
+{
+ static BackendManager object;
+ return object;
+}
+
+BackendManager::BackendManager() { loadControlflowBackend(); }
+
+void BackendManager::loadControlflowBackend()
+{
+ auto backend_object = std::unique_ptr<backend::controlflow::Backend, backend_destroy_t>(
+ new backend::controlflow::Backend, [](backend::Backend *backend) { delete backend; });
+
+ bool initialized = backend_object->config()->initialize(); // Call initialize here?
+ if (!initialized)
+ {
+ throw std::runtime_error(backend::controlflow::Config::ID + " backend initialization failed");
+ }
+ _controlflow = backend_object.get(); // Save the controlflow backend implementation pointer
+ assert(_controlflow);
+ _gen_map.emplace(backend_object->config()->id(), std::move(backend_object));
+}
+
+void BackendManager::loadBackend(const std::string &backend)
+{
+ if (get(backend) != nullptr)
+ {
+ return;
+ }
+
+ // TODO Remove indentation
+ {
+ const std::string backend_so = "libbackend_" + backend + SHARED_LIB_EXT;
+ void *handle = dlopen(backend_so.c_str(), RTLD_LAZY | RTLD_LOCAL);
+
+ if (handle == nullptr)
+ {
+ VERBOSE_F() << "Failed to load backend '" << backend << "' - " << dlerror() << std::endl;
+ return;
+ }
+
+ VERBOSE_F() << "Successfully loaded '" << backend << "' - " << backend_so << "\n";
+
+ {
+ // load object creator function
+ auto backend_create = (backend_create_t)dlsym(handle, "onert_backend_create");
+ if (backend_create == nullptr)
+ {
+ fprintf(stderr, "BackendManager: unable to open function onert_backend_create : %s\n",
+ dlerror());
+ abort();
+ }
+
+ // load object creator function
+ auto backend_destroy = (backend_destroy_t)dlsym(handle, "onert_backend_destroy");
+ if (backend_destroy == nullptr)
+ {
+ fprintf(stderr, "BackendManager: unable to open function onert_backend_destroy : %s\n",
+ dlerror());
+ abort();
+ }
+
+ auto backend_object =
+ std::unique_ptr<backend::Backend, backend_destroy_t>(backend_create(), backend_destroy);
+ bool initialized = backend_object->config()->initialize(); // Call initialize here?
+ if (!initialized)
+ {
+ VERBOSE_F() << backend.c_str() << " backend initialization failed. Don't use this backend"
+ << std::endl;
+ dlclose(handle);
+ return;
+ }
+ _gen_map.emplace(backend_object->config()->id(), std::move(backend_object));
+ }
+
+ // Save backend handle (avoid warning by handle lost without dlclose())
+ auto u_handle = std::unique_ptr<void, dlhandle_destroy_t>{handle, [](void *h) { dlclose(h); }};
+ _handle_map.emplace(backend, std::move(u_handle));
+ }
+}
+
+backend::Backend *BackendManager::get(const std::string &key)
+{
+ if (_gen_map.find(key) != _gen_map.end())
+ {
+ return _gen_map.at(key).get();
+ }
+
+ return nullptr;
+}
+
+const backend::Backend *BackendManager::get(const std::string &key) const
+{
+ if (_gen_map.find(key) != _gen_map.end())
+ {
+ return _gen_map.at(key).get();
+ }
+
+ return nullptr;
+}
+
+const backend::controlflow::Backend *BackendManager::getControlflow() const { return _controlflow; }
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/BackendResolver.cc b/runtime/onert/core/src/compiler/BackendResolver.cc
new file mode 100644
index 000000000..a47d8d2d5
--- /dev/null
+++ b/runtime/onert/core/src/compiler/BackendResolver.cc
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/BackendResolver.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/Compiler.cc b/runtime/onert/core/src/compiler/Compiler.cc
new file mode 100644
index 000000000..c2844bd7c
--- /dev/null
+++ b/runtime/onert/core/src/compiler/Compiler.cc
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/Compiler.h"
+
+#include "ParamChecker.h"
+#include "ExecutorFactory.h"
+#include "ShapeValidator.h"
+#include "Fp32ToFp16Converter.h"
+
+#include <backend/controlflow/Config.h>
+#include "compiler/BackendManager.h"
+#include "compiler/IScheduler.h"
+#include "compiler/ManualScheduler.h"
+#include "compiler/HEScheduler.h"
+#include "compiler/StaticShapeInferer.h"
+#include "compiler/pass/ConstantOutputPass.h"
+#include "compiler/pass/OddOutputPass.h"
+#include "compiler/pass/PassRunner.h"
+#include "exec/ExecTime.h"
+#include "ir/operation/LowerInfo.h"
+#include "ir/verifier/Verifier.h"
+#include "dumper/dot/DotDumper.h"
+#include "compiler/Linear.h"
+#include "interp/InterpExecutor.h"
+#include "util/ConfigSource.h"
+#include "util/logging.h"
+#include "ir/OperationDumper.h"
+#include "misc/string_helpers.h"
+
+namespace onert
+{
+
+namespace compiler
+{
+
+CompilerOptions fetchCompilerOptionsFromGlobalConfig(const ir::Subgraphs &subgs)
+{
+ CompilerOptions options;
+ options.backend_list = nnfw::misc::split(util::getConfigString(util::config::BACKENDS), ';');
+ options.is_primary_subgraph = false;
+ options.trace_filepath = util::getConfigString(util::config::TRACE_FILEPATH);
+ options.graph_dump_level = util::getConfigInt(util::config::GRAPH_DOT_DUMP);
+ options.op_seq_max_node = util::getConfigInt(util::config::OP_SEQ_MAX_NODE);
+ options.executor = util::getConfigString(util::config::EXECUTOR);
+ options.he_scheduler = util::getConfigBool(util::config::USE_SCHEDULER);
+ options.he_profiling_mode = util::getConfigBool(util::config::PROFILING_MODE);
+ options.disable_compile = util::getConfigBool(util::config::DISABLE_COMPILE);
+ options.fp16_enable = util::getConfigBool(util::config::FP16_ENABLE);
+#ifdef RUY_PROFILER
+ options.op_seq_max_node = 1;
+#endif
+
+ {
+ // Backend for all
+ auto &ms_options = options.manual_scheduler_options;
+
+ // Default value for op_backend_all is first element in the backend list
+ ms_options.backend_for_all = util::getConfigString(util::config::OP_BACKEND_ALLOPS);
+
+// Opcode to Backend
+#define OP(OpName) \
+ { \
+ const auto &backend_str = util::getConfigString(util::config::OP_BACKEND_##OpName); \
+ if (!backend_str.empty()) \
+ { \
+ ms_options.opcode_to_backend[ir::OpCode::OpName] = backend_str; \
+ } \
+ }
+#include "ir/Operations.lst"
+#undef OP
+
+ // Index to Backend
+ // TODO Support multiple subgraphs for manual scheduling
+ auto map_str = util::getConfigString(util::config::OP_BACKEND_MAP);
+ auto key_val_list = nnfw::misc::split(map_str, ';');
+ for (const auto &key_val_str : key_val_list)
+ {
+ if (key_val_str.empty())
+ {
+ continue;
+ }
+
+ auto key_val = nnfw::misc::split(key_val_str, '=');
+ const auto &key_str = key_val.at(0);
+ const auto &val = key_val.at(1);
+ auto key = static_cast<uint32_t>(std::stoi(key_str));
+
+ subgs.at(ir::SubgraphIndex{0})
+ ->operations()
+ .at(ir::OperationIndex{key}); // Check if exist, or this wil throw
+ ms_options.index_to_backend.emplace(ir::OperationIndex{key}, val);
+ }
+ }
+ return options;
+}
+
+Compiler::Compiler(const std::shared_ptr<ir::Subgraphs> &subgs)
+ : _subgraphs{subgs}, _state{State::CREATED}
+{
+ // Set default values for CompilerOptions
+ // All these default values should not be fetched from Env, when we stop supporting Android NN
+ // API.
+ _options = fetchCompilerOptionsFromGlobalConfig(*subgs);
+}
+
+void Compiler::enableToFp16() { _options.fp16_enable = true; }
+
+void Compiler::checkProfilerConditions()
+{
+ if (!_options.he_scheduler)
+ throw std::runtime_error("Heterogeneous scheduler must be enabled during profiling.");
+
+ if (_options.executor != "Dataflow")
+ throw std::runtime_error("Profiling mode works only with 'Dataflow' executor");
+}
+
+std::shared_ptr<exec::ExecutorMap> Compiler::compile(void)
+{
+ // Set control flow backend for control flow operators
+ {
+ _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::If] =
+ backend::controlflow::Config::ID;
+ _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::While] =
+ backend::controlflow::Config::ID;
+ _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::Permute] =
+ backend::controlflow::Config::ID;
+ }
+
+ // FIXME This is a workaround for bcq operations, should remove it
+ {
+ _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::BCQFullyConnected] = "bcq";
+ _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::BCQGather] = "bcq";
+ }
+
+ {
+ VERBOSE(Compiler) << std::boolalpha;
+ VERBOSE(Compiler) << "==== Compiler Options ====" << std::endl;
+ VERBOSE(Compiler) << "backend_list : "
+ << nnfw::misc::join(_options.backend_list.begin(),
+ _options.backend_list.end(), "/")
+ << std::endl;
+ VERBOSE(Compiler) << "trace_filepath : " << _options.trace_filepath << std::endl;
+ VERBOSE(Compiler) << "graph_dump_level : " << _options.graph_dump_level << std::endl;
+ VERBOSE(Compiler) << "op_seq_max_node : " << _options.op_seq_max_node << std::endl;
+ VERBOSE(Compiler) << "executor : " << _options.executor << std::endl;
+ VERBOSE(Compiler) << "manual_scheduler_options : (Too many things to print)" << std::endl;
+ VERBOSE(Compiler) << "he_scheduler : " << _options.he_scheduler << std::endl;
+ VERBOSE(Compiler) << "he_profiling_mode : " << _options.he_profiling_mode << std::endl;
+ VERBOSE(Compiler) << "disable_compile : " << _options.disable_compile << std::endl;
+ VERBOSE(Compiler) << "fp16_enable : " << _options.fp16_enable << std::endl;
+ VERBOSE(Compiler) << std::noboolalpha;
+ }
+
+ _subgraphs->iterate([&](const ir::SubgraphIndex &, ir::Graph &subg) {
+ // Mandatory passes
+ pass::PassRunner{}
+ .append(std::make_unique<pass::ConstantOutputPass>(subg))
+ .append(std::make_unique<pass::OddOutputPass>(subg))
+ .run();
+ });
+
+ /***************************************************
+ * Prepare compilation phase
+ ***************************************************/
+ auto executors = std::make_shared<exec::ExecutorMap>();
+
+ // Compilable check
+ // TODO: Support hybrid execution -
+ // execution between interpreter and compiled executor (including control flow)
+ if (!checkCompilable())
+ {
+ _subgraphs->iterate([&](const ir::SubgraphIndex &index, ir::Graph &subg) {
+ executors->emplace(index, std::make_unique<interp::InterpExecutor>(subg));
+ });
+ _state = State::COMPILED;
+ return executors;
+ }
+
+ // Mode check
+ if (_options.he_profiling_mode)
+ checkProfilerConditions();
+
+ /***************************************************
+ * Backend independent analysis & optimization phase
+ ***************************************************/
+ auto dump_level = static_cast<dumper::dot::DotDumper::Level>(_options.graph_dump_level);
+
+ // Lower: Assign backend
+ std::unordered_map<ir::SubgraphIndex, std::unique_ptr<compiler::LoweredGraph>> lowered_subgs;
+ _subgraphs->iterate([&](const ir::SubgraphIndex &index, ir::Graph &subg) {
+ _options.is_primary_subgraph = (index == ir::SubgraphIndex{0});
+ onert::dumper::dot::DotDumper dot_dumper(subg, dump_level);
+ dot_dumper.dump(nnfw::misc::str("before_lower_subg-", index.value()));
+
+ // Lower: Assign backend
+ lowered_subgs[index] = std::make_unique<compiler::LoweredGraph>(subg, _options);
+
+ // Check backend(s) for subgraph support FP16
+ bool backends_support_fp16 = true;
+ auto &contexts = (*lowered_subgs[index]).backend_contexts();
+ for (auto it = contexts.begin(); it != contexts.end(); it++)
+ {
+ // Controlflow backend is not for actual computaion of operations so it is an exception
+ if (it->first->config()->id() != backend::controlflow::Config::ID)
+ backends_support_fp16 &= it->first->config()->supportFP16();
+ }
+
+ if (_options.fp16_enable && backends_support_fp16)
+ {
+ // NOTE: the only acl_cl backend enables fp16 mode
+ Fp32ToFp16Converter(*lowered_subgs[index]).run();
+ }
+
+ subg.setSubgraphs(nullptr);
+ });
+
+ _subgraphs.reset();
+
+ // Shape inference.
+ {
+ const auto primary_subg_idx = ir::SubgraphIndex{0};
+ StaticShapeInferer inferer(primary_subg_idx, lowered_subgs);
+ lowered_subgs.at(primary_subg_idx)
+ ->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ auto has_dynamic_tensor = inferer.infer(op_seq);
+ op_seq.has_dynamic_tensor(has_dynamic_tensor);
+ });
+ inferer.dump();
+ }
+
+ // Shape validation
+ // TODO Move shape independent feature check from ShapeValidator to OperationValidator
+ // TODO Move ShapeValidator into shape inference
+ // - Check input tensor shape validation
+ // - Check parameter value validation which valid value is depend on input tensor shape
+ // - Output tensor shape validation check is needless because
+ // static/dynamic shape inferer will make valid output shape
+ for (auto &pair : lowered_subgs)
+ {
+ auto &lowered_subg = pair.second;
+ compiler::ShapeValidator{lowered_subg->graph()}();
+ }
+
+ /*************************************************************
+ * Backend independent analysis & optimization phase finished
+ *************************************************************/
+
+ executors = std::make_shared<exec::ExecutorMap>();
+ for (auto &pair : lowered_subgs)
+ {
+ const auto &subg_index = pair.first;
+ auto &lowered_subg = pair.second;
+ auto indexed_ranks = lowered_subg->indexed_ranks();
+
+ _options.is_primary_subgraph = (subg_index == ir::SubgraphIndex{0});
+
+ onert::dumper::dot::DotDumper dot_dumper_lowered(lowered_subg.get(), dump_level);
+ dot_dumper_lowered.dump("after_lower_subg-" + std::to_string(subg_index.value()));
+
+ ir::OperationDumper dumper("START SUBGRAPH " + std::to_string(subg_index.value()));
+ lowered_subg->graph().operations().iterate(
+ [&](const ir::OperationIndex &, const ir::Operation &op) { op.accept(dumper); });
+ auto executor = std::unique_ptr<exec::IExecutor>{
+ ExecutorFactory::get().create(std::move(lowered_subg), _options, executors)};
+ executor->setIndexedRanks(indexed_ranks);
+ executors->insert(std::make_pair(subg_index, std::move(executor)));
+ }
+
+ /********************************
+ * Code generation phase finished
+ ********************************/
+ _state = State::COMPILED;
+ return executors;
+}
+
+bool Compiler::checkCompilable()
+{
+ // Disable compile phase
+ // When ready to use interpreter backend, remove this config and use backend setting
+ if (_options.disable_compile)
+ {
+ return false;
+ }
+
+ // TODO check unspecified operand shape
+
+ // Check compilable parameter
+ for (uint32_t i = 0; i < _subgraphs->count(); ++i)
+ {
+ auto graph = _subgraphs->at(ir::SubgraphIndex{i});
+ ParamChecker paramChecker{graph};
+ paramChecker();
+ if (paramChecker.haveNoneConstParam())
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace compiler
+
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/ExecutorFactory.cc b/runtime/onert/core/src/compiler/ExecutorFactory.cc
new file mode 100644
index 000000000..bb325ffbc
--- /dev/null
+++ b/runtime/onert/core/src/compiler/ExecutorFactory.cc
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExecutorFactory.h"
+
+#include <functional>
+#include "exec/ExecutionObservers.h"
+#include "exec/LinearExecutor.h"
+#include "exec/DataflowExecutor.h"
+#include "exec/ParallelExecutor.h"
+#include "compiler/BackendManager.h"
+#include "compiler/ExecutionBuilder.h"
+#include "exec/ExecTime.h"
+#include "compiler/Linear.h"
+#include "compiler/TensorBuilders.h"
+#include "backend/IConstantInitializer.h"
+#include "backend/IKernelGenerator.h"
+#include "backend/IOptimizer.h"
+#include "backend/IPortableTensor.h"
+#include "backend/ITensorRegister.h"
+#include "backend/controlflow/Config.h"
+#include "backend/controlflow/KernelGenerator.h"
+#include "backend/controlflow/UserTensor.h"
+#include "backend/controlflow/TensorBuilder.h"
+#include <memory>
+
+namespace onert
+{
+namespace
+{
+
+class SyncFunction final : public exec::IFunction
+{
+public:
+ virtual ~SyncFunction() = default;
+ SyncFunction(std::unique_ptr<exec::IFunction> fn, const std::shared_ptr<backend::IConfig> config)
+ : _fn{std::move(fn)}, _config{config}
+ {
+ assert(_fn);
+ assert(_config);
+ }
+
+ void run() override
+ {
+ _fn->run();
+ _config->sync();
+ }
+
+ void prepare() override { _fn->prepare(); }
+
+private:
+ std::unique_ptr<exec::IFunction> _fn;
+ std::shared_ptr<backend::IConfig> _config;
+};
+
+} // namespace
+} // namespace onert
+
+namespace onert
+{
+namespace compiler
+{
+
+ExecutorFactory &ExecutorFactory::get()
+{
+ static ExecutorFactory singleton;
+ return singleton;
+}
+
+ExecutorFactory::ExecutorFactory()
+{
+ _map["Linear"] = createLinearExecutor;
+ _map["Dataflow"] = std::bind(createDataflowExecutor, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, false);
+ _map["Parallel"] = std::bind(createDataflowExecutor, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, true);
+}
+
+exec::IExecutor *ExecutorFactory::create(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const compiler::CompilerOptions &options,
+ const std::shared_ptr<exec::ExecutorMap> &executor_map)
+{
+ return _map.at(options.executor)(std::move(lowered_graph), options, executor_map);
+}
+
+void ExecutorFactory::initializeBackendContext(compiler::LoweredGraph *lowered_graph)
+{
+ struct Entry
+ {
+ std::vector<backend::BackendContext::OperationInfo> operation_list;
+ std::vector<ir::OperandIndex> operand_list;
+ };
+ std::unordered_map<const backend::Backend *, Entry> backend_assets;
+
+ // Build lists for operations
+ lowered_graph->op_seqs().iterate(
+ [&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &op_seq) {
+ auto &op_seq_li = lowered_graph->getLowerInfo()->op_seq;
+ auto backend = op_seq_li.at(op_seq_index)->backend();
+ for (auto &operation_idx : op_seq.operations())
+ {
+ backend_assets[backend].operation_list.emplace_back(operation_idx, op_seq.getLayout());
+ }
+ });
+
+ // Build lists for operands
+ lowered_graph->graph().operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &) {
+ const auto lower_info = lowered_graph->getLowerInfo(ind);
+ for (auto factor : lower_info->def_factors())
+ {
+ auto backend = factor.backend();
+ backend_assets[backend].operand_list.emplace_back(ind);
+ }
+ });
+
+ for (auto &pair : backend_assets)
+ {
+ auto backend = pair.first;
+ auto &arg = pair.second;
+ lowered_graph->backend_contexts().at(backend)->initialize(arg.operation_list, arg.operand_list);
+ }
+}
+
+void ExecutorFactory::runTensorRegistration(compiler::LoweredGraph *lowered_graph,
+ const std::vector<ir::OpSequenceIndex> &order)
+{
+ for (const auto index : order)
+ {
+ const auto &op_seq = lowered_graph->op_seqs().at(index);
+ const auto backend = lowered_graph->getLowerInfo(index)->backend();
+ const auto tensor_register = lowered_graph->backend_contexts().at(backend)->tensor_register;
+ auto tensor_builder = lowered_graph->backend_contexts().at(backend)->tensor_builder;
+ auto model_io = lowered_graph->graph().getInputs() + lowered_graph->graph().getOutputs();
+
+ if (tensor_register)
+ {
+ // Custom registration
+ tensor_register->registerTensors(op_seq, lowered_graph->getLowerInfo());
+ }
+ else
+ {
+ // Default registration
+ for (const auto op_idx : op_seq)
+ {
+ const auto &op = lowered_graph->graph().operations().at(op_idx);
+ for (const auto &index :
+ (op.getInputs() | ir::Remove::UNDEFINED) + (op.getOutputs() | ir::Remove::UNDEFINED))
+ {
+ if (!tensor_builder->isRegistered(index) && !model_io.contains(index))
+ {
+ const auto &operand_lower_info =
+ lowered_graph->getLowerInfo(index)->def_factors().getOnlyElement();
+
+ // E.g., permute (CPU) -> tensor A -> MaxPool2D(acl_cl)
+ // op.getOutputs() of permute (CPU) returns tensor A
+ // but tensor A belongs to the backend of acl_cl.
+ // So, we have to make this tensor NOT registered for CPU.
+ if (operand_lower_info.backend() != backend)
+ continue;
+
+ const auto &obj = lowered_graph->graph().operands().at(index);
+ const auto frontend_layout = op_seq.getLayout();
+ const auto backend_layout = operand_lower_info.layout();
+ ir::OperandInfo backend_info{permuteShape(obj.shape(), frontend_layout, backend_layout),
+ obj.typeInfo(), obj.info().memAllocType(),
+ obj.isConstant()};
+ tensor_builder->registerTensorInfo(index, backend_info, backend_layout);
+ }
+ }
+ }
+ }
+ }
+}
+
+std::vector<backend::ITensor *>
+ExecutorFactory::initializeModelIOTensors(compiler::LoweredGraph &lowered_graph,
+ const ir::OperandIndexSequence &indices)
+{
+ std::vector<backend::ITensor *> ret;
+
+ // TODO Store controlflow backend in BackendContext
+ std::shared_ptr<backend::controlflow::TensorBuilder> cf_tensor_builder;
+ std::shared_ptr<backend::controlflow::TensorRegistry> cf_tensor_reg;
+ for (const auto &e : lowered_graph.backend_contexts())
+ {
+ auto backend = e.first;
+ auto &context = e.second;
+ if (backend->config()->id() == backend::controlflow::Config::ID)
+ {
+ cf_tensor_builder =
+ std::dynamic_pointer_cast<backend::controlflow::TensorBuilder>(context->tensor_builder);
+ cf_tensor_reg =
+ std::dynamic_pointer_cast<backend::controlflow::TensorRegistry>(context->tensor_registry);
+ }
+ }
+ assert(cf_tensor_builder);
+ assert(cf_tensor_reg);
+
+ for (auto ind : indices)
+ {
+ const auto &operand = lowered_graph.graph().operands().at(ind);
+ auto tensor = std::make_unique<backend::controlflow::UserTensor>(
+ operand.info(),
+ ir::Layout::NHWC /* FIXME find op_seq for this operand and use frontend_layout */
+ );
+
+ // Add tensor to controlflow TensorRegistry.
+ cf_tensor_reg->setNativeUserTensor(ind, std::move(tensor));
+ auto *itensor = cf_tensor_reg->getITensor(ind);
+ ret.push_back(itensor);
+ }
+ return ret;
+}
+
+void ExecutorFactory::prepareMigrantTensors(compiler::LoweredGraph &lowered_graph)
+{
+ TensorRegistries tensor_regs{lowered_graph.backend_contexts(), true};
+
+ lowered_graph.op_seqs().iterate(
+ [&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &op_seq) {
+ auto lower_info = lowered_graph.getLowerInfo(op_seq_index);
+ auto &backend_ctx = lowered_graph.backend_contexts().at(lower_info->backend());
+ for (auto ind : (op_seq.getInputs() + op_seq.getOutputs()) | ir::Remove::DUPLICATED |
+ ir::Remove::UNDEFINED)
+ {
+ // If an OpSequence input/output tensor does not have a own tensor object,
+ // it must be using migrant tensors, so find the tensor from other tensor builders and
+ // set the tensor to this tensor builder if portable
+ if (!backend_ctx->tensor_registry->getITensor(ind))
+ {
+ auto tensor = tensor_regs.getITensor(ind);
+ assert(tensor); // The tensor must have been registered
+ auto ptensor = dynamic_cast<backend::IPortableTensor *>(tensor);
+ if (ptensor)
+ backend_ctx->tensor_registry->setMigrantTensor(ind, ptensor);
+ }
+ }
+ });
+}
+
+exec::IExecutor *
+ExecutorFactory::createLinearExecutor(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const compiler::CompilerOptions &options,
+ const std::shared_ptr<exec::ExecutorMap> &executor_map)
+{
+ const auto &backend_contexts = lowered_graph->backend_contexts();
+
+ initializeBackendContext(lowered_graph.get());
+
+ // linearize
+ assert(!lowered_graph->graph().isBuildingPhase());
+
+ /*************************************************
+ * Backend dependent analysis & optimization phase
+ *************************************************/
+
+ for (auto &pair : backend_contexts)
+ {
+ auto &optimizer = pair.second->optimizer;
+ if (optimizer)
+ optimizer->optimize();
+ }
+
+ /**********************************************************
+ * Backend dependent analysis & optimization phase finished
+ **********************************************************/
+
+ /***********************
+ * Code generation phase
+ ***********************/
+
+ auto order = Linear::linearize(*lowered_graph);
+ runTensorRegistration(lowered_graph.get(), order);
+
+ std::vector<backend::ITensor *> input_tensors;
+ std::vector<backend::ITensor *> output_tensors;
+ if (options.is_primary_subgraph)
+ {
+ input_tensors = initializeModelIOTensors(*lowered_graph, lowered_graph->graph().getInputs());
+ output_tensors = initializeModelIOTensors(*lowered_graph, lowered_graph->graph().getOutputs());
+ }
+
+ Linear::dump(*lowered_graph, order);
+ Linear::planTensors(*lowered_graph, order);
+
+ TensorBuilders tensor_builders{lowered_graph->backend_contexts(), true};
+ TensorRegistries tensor_regs{lowered_graph->backend_contexts(), true};
+
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->prepare();
+ }
+
+ prepareMigrantTensors(*lowered_graph);
+
+ ExecutionBuilder builder;
+
+ // Generate kernels
+ lowered_graph->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &op_seq_index,
+ const ir::OpSequence &op_seq) {
+ auto lower_info = lowered_graph->getLowerInfo(op_seq_index);
+ auto kernel_gen = lowered_graph->backend_contexts().at(lower_info->backend())->kernel_gen;
+ // Set TensorBuilderSet and ExecutorMap to kernel_gen of control flow
+ auto cf_kernel_gen = dynamic_cast<backend::controlflow::KernelGenerator *>(kernel_gen.get());
+ if (cf_kernel_gen != nullptr)
+ {
+ cf_kernel_gen->setTensorRegistries(tensor_regs);
+ cf_kernel_gen->setExecutorMap(executor_map);
+ }
+ auto fn_seq = kernel_gen->generate(op_seq);
+ if (options.he_profiling_mode)
+ {
+ fn_seq->wrap<SyncFunction>(lower_info->backend()->config());
+ }
+ builder.append(op_seq_index, {&op_seq, lower_info, std::move(fn_seq)});
+ });
+
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->allocate();
+ }
+
+ for (auto &pair : backend_contexts)
+ {
+ pair.second->initConsts();
+ }
+
+ lowered_graph->graph().operands().iterate(
+ [](const ir::OperandIndex &, ir::Operand &obj) { obj.releaseData(); });
+
+ auto code_map = builder.releaseCodeMap();
+
+ for (auto &it : code_map)
+ {
+ auto op_seq_index = it.first;
+ auto &fn_seq = it.second.fn_seq;
+
+ fn_seq->iterate([&](exec::IFunction &ifunc) {
+ ifunc.prepare();
+ auto backend = lowered_graph->getLowerInfo(op_seq_index)->backend();
+ auto tensor_builder = lowered_graph->backend_contexts().at(backend)->tensor_builder;
+ tensor_builder->postFunctionPrepare();
+ });
+ }
+
+ auto exec =
+ new exec::LinearExecutor{std::move(lowered_graph), input_tensors, output_tensors, tensor_regs,
+ std::move(code_map), order};
+
+ if (!options.trace_filepath.empty())
+ {
+ std::unique_ptr<exec::IExecutionObserver> ctp =
+ std::make_unique<exec::ChromeTracingObserver>(options.trace_filepath, exec->graph());
+ exec->addObserver(std::move(ctp));
+ }
+
+ return exec;
+}
+
+exec::IExecutor *ExecutorFactory::createDataflowExecutor(
+ std::unique_ptr<compiler::LoweredGraph> lowered_graph, const compiler::CompilerOptions &options,
+ const std::shared_ptr<exec::ExecutorMap> &executor_map, bool parallel)
+{
+ const auto &backend_contexts = lowered_graph->backend_contexts();
+
+ initializeBackendContext(lowered_graph.get());
+
+ auto order = Linear::linearize(*lowered_graph);
+ runTensorRegistration(lowered_graph.get(), order);
+
+ std::vector<backend::ITensor *> input_tensors;
+ std::vector<backend::ITensor *> output_tensors;
+ if (options.is_primary_subgraph)
+ {
+ input_tensors = initializeModelIOTensors(*lowered_graph, lowered_graph->graph().getInputs());
+ output_tensors = initializeModelIOTensors(*lowered_graph, lowered_graph->graph().getOutputs());
+ }
+
+ TensorBuilders tensor_builders{lowered_graph->backend_contexts(), true};
+ TensorRegistries tensor_regs{lowered_graph->backend_contexts(), true};
+
+ // To make tensors never be deallocated, this is a workaround to use static memory planner
+ for (auto &tensor_builder : tensor_builders)
+ {
+ lowered_graph->graph().operands().iterate(
+ [&](const ir::OperandIndex &ind, const ir::Operand &) {
+ if (tensor_builder->isRegistered(ind))
+ {
+ tensor_builder->notifyFirstUse(ind);
+ }
+ });
+ }
+
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->prepare();
+ }
+
+ prepareMigrantTensors(*lowered_graph);
+
+ ExecutionBuilder builder;
+
+ // Generate kernels
+ lowered_graph->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &op_seq_index,
+ const ir::OpSequence &op_seq) {
+ auto lower_info = lowered_graph->getLowerInfo(op_seq_index);
+ auto kernel_gen = lowered_graph->backend_contexts().at(lower_info->backend())->kernel_gen;
+ // Set TensorBuilderSet and ExecutorMap to kernel_gen of control flow
+ auto cf_kernel_gen = dynamic_cast<backend::controlflow::KernelGenerator *>(kernel_gen.get());
+ if (cf_kernel_gen != nullptr)
+ {
+ assert(cf_kernel_gen != nullptr);
+ cf_kernel_gen->setTensorRegistries(tensor_regs);
+ cf_kernel_gen->setExecutorMap(executor_map);
+ }
+ auto fn_seq = kernel_gen->generate(op_seq);
+ if (options.he_profiling_mode)
+ {
+ fn_seq->wrap<SyncFunction>(lower_info->backend()->config());
+ }
+ builder.append(op_seq_index, {&op_seq, lower_info, std::move(fn_seq)});
+ });
+
+ for (const auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->allocate();
+ }
+
+ for (auto &pair : backend_contexts)
+ {
+ pair.second->initConsts();
+ }
+
+ lowered_graph->graph().operands().iterate(
+ [](const ir::OperandIndex &, ir::Operand &obj) { obj.releaseData(); });
+
+ auto code_map = builder.releaseCodeMap();
+
+ for (auto &it : code_map)
+ {
+ auto op_seq_index = it.first;
+ auto &fn_seq = it.second.fn_seq;
+
+ fn_seq->iterate([&](exec::IFunction &ifunc) {
+ ifunc.prepare();
+ auto backend = lowered_graph->getLowerInfo(op_seq_index)->backend();
+ auto tensor_builder = lowered_graph->backend_contexts().at(backend)->tensor_builder;
+ tensor_builder->postFunctionPrepare();
+ });
+ }
+
+ exec::ExecutorBase *exec = nullptr;
+ if (parallel)
+ {
+ exec = new exec::ParallelExecutor{std::move(lowered_graph), input_tensors, output_tensors,
+ tensor_regs, std::move(code_map)};
+ }
+ else
+ {
+ auto dataflow_exec = new exec::DataflowExecutor{
+ std::move(lowered_graph), input_tensors, output_tensors, tensor_regs, std::move(code_map)};
+ if (options.he_profiling_mode)
+ {
+ std::vector<const backend::Backend *> backends;
+ for (const auto &pair : backend_contexts)
+ {
+ backends.push_back(pair.first);
+ }
+ auto et = std::make_shared<exec::ExecTime>(backends);
+ std::unique_ptr<exec::IExecutionObserver> obs =
+ std::make_unique<exec::ProfileObserver>(et, dataflow_exec->graph());
+ dataflow_exec->addObserver(std::move(obs));
+ }
+ exec = dataflow_exec;
+ }
+
+ if (!options.trace_filepath.empty())
+ {
+ std::unique_ptr<exec::IExecutionObserver> ctp =
+ std::make_unique<exec::ChromeTracingObserver>(options.trace_filepath, exec->graph());
+ exec->addObserver(std::move(ctp));
+ }
+
+ return exec;
+}
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/ExecutorFactory.h b/runtime/onert/core/src/compiler/ExecutorFactory.h
new file mode 100644
index 000000000..e76b721ea
--- /dev/null
+++ b/runtime/onert/core/src/compiler/ExecutorFactory.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_EXECUTOR_FACTORY_H__
+#define __ONERT_COMPILER_EXECUTOR_FACTORY_H__
+
+#include <unordered_map>
+
+#include "backend/ITensor.h"
+#include "exec/IExecutor.h"
+#include "compiler/LoweredGraph.h"
+#include "TensorRegistries.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+class ExecutorFactory
+{
+public:
+ static ExecutorFactory &get();
+
+public:
+ exec::IExecutor *create(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const compiler::CompilerOptions &options,
+ const std::shared_ptr<exec::ExecutorMap> &executor_map);
+
+private:
+ ExecutorFactory();
+
+private:
+ static void initializeBackendContext(compiler::LoweredGraph *lowered_graph);
+ static void runTensorRegistration(compiler::LoweredGraph *lowered_graph,
+ const std::vector<ir::OpSequenceIndex> &order);
+ static std::vector<backend::ITensor *>
+ initializeModelIOTensors(compiler::LoweredGraph &lowered_graph,
+ const ir::OperandIndexSequence &indices);
+ static void prepareMigrantTensors(compiler::LoweredGraph &lowered_graph);
+ static exec::IExecutor *
+ createLinearExecutor(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const compiler::CompilerOptions &options,
+ const std::shared_ptr<exec::ExecutorMap> &executor_map);
+ static exec::IExecutor *
+ createDataflowExecutor(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const compiler::CompilerOptions &options,
+ const std::shared_ptr<exec::ExecutorMap> &executor_map, bool parallel);
+
+private:
+ std::unordered_map<std::string, std::function<exec::IExecutor *(
+ std::unique_ptr<compiler::LoweredGraph>,
+ const compiler::CompilerOptions &options,
+ const std::shared_ptr<exec::ExecutorMap> &executor_map)>>
+ _map;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_EXECUTOR_FACTORY_H__
diff --git a/runtime/onert/core/src/compiler/Fp32ToFp16Converter.cc b/runtime/onert/core/src/compiler/Fp32ToFp16Converter.cc
new file mode 100644
index 000000000..23a6a253d
--- /dev/null
+++ b/runtime/onert/core/src/compiler/Fp32ToFp16Converter.cc
@@ -0,0 +1,954 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Fp32ToFp16Converter.h"
+#include "ir/operation/ConvertFp32ToFp16.h"
+#include "ir/operation/ConvertFp16ToFp32.h"
+#include "util/logging.h"
+
+#include <Half.h>
+
+using float16 = Half;
+
+namespace
+{
+
+const std::string kAclClBackendConfigId = "acl_cl";
+
+void copyDataFromFp32ToFp16(const float *from, float16 *into, size_t num_elements)
+{
+ for (size_t i = 0; i < num_elements; ++i)
+ {
+ into[i] = static_cast<float16>(from[i]);
+ }
+}
+
+} // namespace
+
+namespace onert
+{
+
+namespace compiler
+{
+
+Fp32ToFp16Converter::Fp32ToFp16Converter(compiler::LoweredGraph &lowered_graph)
+ : _lowered_graph{lowered_graph}
+{
+ VERBOSE(Fp32ToFp16Converter) << "Fp16 Enable on" << std::endl;
+}
+
+// For example, two OpSequences are there and each OpSequence has an Operation
+//
+// OP#0 // model input
+// |
+// [OPERATION] // OpSeq#0
+// |
+// OP#1
+// |
+// [OPERATION] // OpSeq#1
+// |
+// OP#2 // model output
+//
+//
+// AFTER `appendOpSequences()`,
+// note that model_input and model_output are not changed.
+//
+// OP#0
+// |
+// [FP32TO16] // OpSeq#2
+// |
+// OP#3
+// |
+// [OPERATION] // OpSeq#0
+// |
+// OP#4
+// |
+// [FP16TO32] // OpSeq#3
+// |
+// OP#1
+// |
+// [FP32TO16] // OpSeq#4
+// |
+// OP#5
+// |
+// [OPERATION] // OpSeq#1
+// |
+// OP#6
+// |
+// [FP16TO32] // OpSeq#5
+// |
+// OP#2
+//
+//
+// AFTER `optimize()`,
+//
+// OP#0
+// |
+// [FP32TO16] // OpSeq#2
+// |
+// OP#3
+// |
+// [OPERATION] // OpSeq#0
+// |
+// OP#4
+// |
+// [OPERATION] // OpSeq#1
+// |
+// OP#6
+// |
+// [FP16TO32] // OpSeq#5
+// |
+// OP#2
+//
+//
+// AFTER `convertOperands()`,
+//
+// OP#0 // model_input, not fp16
+// |
+// [FP32TO16] // OpSeq#2
+// |
+// OP#3 // fp16
+// |
+// [OPERATION] // OpSeq#0
+// |
+// OP#4 // fp16
+// |
+// [OPERATION] // OpSeq#1
+// |
+// OP#6 // fp16
+// |
+// [FP16TO32] // OpSeq#5
+// |
+// OP#2 // model_output, notfp16
+//
+//
+// AFTER `convertDatas()`,
+//
+// OP#0 // model_input, not fp16
+// |
+// [FP32TO16] // OpSeq#2
+// |
+// OP#3 // fp16
+// |
+// [OPERATION] // OpSeq#0, constants are fp16
+// |
+// OP#4 // fp16
+// |
+// [OPERATION] // OpSeq#1, constants are fp16
+// |
+// OP#6 // fp16
+// |
+// [FP16TO32] // OpSeq#5
+// |
+// OP#2 // model_output, notfp16
+//
+void Fp32ToFp16Converter::run()
+{
+ // Append new OpSequence which includes ConvertFp32ToFp16
+ // and append new OpSequence which includes ConvertFp16ToFp32
+ appendOpSequences();
+
+ // Remove unnecessary converting operations
+ optimize();
+
+ // Convert operands' data types from fp32 to fp16
+ convertOperands();
+
+ // Convert Datas
+ convertDatas();
+
+ // Print the result
+ printOpSequences("FINAL OpSequences");
+}
+
+void Fp32ToFp16Converter::appendOpSequences()
+{
+ _lowered_graph.op_seqs().iterate(
+ [&](const ir::OpSequenceIndex &op_seq_ind, ir::OpSequence &op_seq) {
+ const auto lower_info = _lowered_graph.getLowerInfo(op_seq_ind);
+ assert(lower_info != nullptr);
+
+ // For now, the only acl_cl supports fully fp16 type
+ // TODO Support fp16 on acl_neon. Current acl_neon supports the only reshape and concat
+ // operations.
+ // To do this, we could check the support by `operation by operation`. After that, we
+ // would partition an op_seq if it contains unsupported operations.
+ if (lower_info->backend()->config()->id() != kAclClBackendConfigId)
+ return;
+
+ // OpSeq's input set should be included in the first operation's input set or
+ // OpSeq's output set should be included in the last operation's output set
+ assert(checkOperandsOfOpSequence(op_seq));
+
+ // Append converting OpSequence for fp16 but all operands' types are not fp16 still.
+ appendNewOpSeqForConvertFp32ToFp16(op_seq_ind, op_seq);
+ appendNewOpSeqForConvertFp16ToFp32(op_seq_ind, op_seq);
+ });
+}
+
+//
+// BEFORE
+//
+// OP#0 // model input
+// |
+// [OPERATION] // OpSeq#0
+// |
+// OP#1 // model output
+//
+//
+// AFTER
+//
+// OP#0 // model input
+// |
+// [FP32TO16] // OpSeq#1
+// |
+// OP#2
+// |
+// [OPERATION] // OpSeq#0
+// |
+// OP#1 // model output
+//
+void Fp32ToFp16Converter::appendNewOpSeqForConvertFp32ToFp16(const ir::OpSequenceIndex &op_seq_ind,
+ ir::OpSequence &op_seq)
+{
+ // OpSeq's input set is included in the first operation's input set
+ const ir::OperandIndexSequence op_seq_inputs = op_seq.getInputs(); // copied
+
+ // NOTE Please do not change sequence of op_seq_inputs. It can change the sequence of inputs of
+ // Subgraph
+ for (const auto &op_seq_input_ind :
+ op_seq_inputs | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ if (checkOperandType(op_seq_input_ind) == false)
+ continue;
+
+ // new operand w/ datatype fp32
+ const auto new_op_ind = newCopiedOperand(op_seq_input_ind);
+
+ // set new lower_info for operand
+ setNewOperandLowerInfo(op_seq_ind, new_op_ind);
+
+ // manipulate input of operation and op_seq
+ // - replace the first operation's input to new operand
+ // with old operand's removeUse and new operand's appendUse()
+ manipulateInput(op_seq_ind, op_seq_input_ind, new_op_ind);
+
+ // new op
+ const auto new_node_ind = newOperationConvertFp32ToFp16(op_seq_input_ind, new_op_ind);
+
+ // new op_seq
+ const auto new_op_seq_ind = newOpSequence(op_seq_ind, new_node_ind);
+
+ // set new lower_info for op_seq
+ setNewOpSequenceLowerInfo(op_seq_ind, new_op_seq_ind);
+
+ _list_fp32_to_fp16.insert(new_op_seq_ind);
+
+ VERBOSE(Fp32ToFp16Converter) << "NEW |Fp32To16]"
+ << ir::getStrFromOpSeq(_lowered_graph.op_seqs().at(new_op_seq_ind),
+ _lowered_graph.graph().operations())
+ << std::endl;
+ }
+}
+
+//
+// BEFORE
+//
+// OP#0 // model input
+// |
+// [FP32TO16] // OpSeq#1
+// |
+// OP#2
+// |
+// [OPERATION] // OpSeq#0
+// |
+// OP#1 // model output
+//
+//
+// AFTER
+//
+// OP#0 // model input
+// |
+// [FP32TO16] // OpSeq#1
+// |
+// OP#2
+// |
+// [OPERATION] // OpSeq#0
+// |
+// OP#3
+// |
+// [FP16TO32] // OpSeq#2
+// |
+// OP#1 // model output
+//
+void Fp32ToFp16Converter::appendNewOpSeqForConvertFp16ToFp32(const ir::OpSequenceIndex &op_seq_ind,
+ ir::OpSequence &op_seq)
+{
+ // OpSeq's output set is included in the last operation's output set
+ const ir::OperandIndexSequence op_seq_outputs = op_seq.getOutputs(); // copied
+
+ // NOTE Please do not change sequence of op_seq_outputs. It can change the sequence of outputs of
+ // Subgraph
+ for (const auto &op_seq_output_ind :
+ op_seq_outputs | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ if (checkOperandType(op_seq_output_ind) == false)
+ continue;
+
+ // new operand w/ datatype fp32
+ const auto new_op_ind = newCopiedOperand(op_seq_output_ind);
+
+ // set new lower_info for operand
+ setNewOperandLowerInfo(op_seq_ind, new_op_ind);
+
+ // manipulate output of operation and op_seq
+ // - replace output of the last operation's output to new operand
+ // with old operand's unsetDef and new operand's appendDef()
+ manipulateOutput(op_seq_ind, op_seq_output_ind, new_op_ind);
+
+ // new op
+ auto new_node_ind = newOperationConvertFp16ToFp32(op_seq_output_ind, new_op_ind);
+
+ // new op_seq
+ auto new_op_seq_ind = newOpSequence(op_seq_ind, new_node_ind);
+
+ // set new lower_info for op_seq
+ setNewOpSequenceLowerInfo(op_seq_ind, new_op_seq_ind);
+
+ _list_fp16_to_fp32.insert(new_op_seq_ind);
+
+ VERBOSE(Fp32ToFp16Converter) << "NEW |Fp16To32]"
+ << ir::getStrFromOpSeq(_lowered_graph.op_seqs().at(new_op_seq_ind),
+ _lowered_graph.graph().operations())
+ << std::endl;
+ }
+}
+
+void Fp32ToFp16Converter::optimize()
+{
+ printOpSequences("BEFORE opt");
+
+ removeContiguousConvertOpSequences();
+
+ printOpSequences("AFTER removeContiguousConverts");
+
+ // TODO Handle Split from the beginning of the model. ex) MODELS/inception_module
+ //
+ // BEFORE)
+ //
+ // OP#0---------------------. // model_input
+ // | |
+ // [FP32TO16] // OpSeq#0 [FP32TO16] // OpSeq#1
+ // | |
+ // OP#1 OP#2
+ // | |
+ // [OPERATION] // OpSeq#2 [OPERATION] // OpSeq#3
+ //
+ //
+ // AFTER)
+ //
+ // OP#0 // model_input
+ // |
+ // [FP32TO16] // OpSeq#4
+ // |
+ // OP#3---------------------------.
+ // | |
+ // [OPERATION] // OpSeq#2 [OPERATION] // OpSeq#3
+}
+
+void Fp32ToFp16Converter::convertOperands()
+{
+ _lowered_graph.op_seqs().iterate(
+ [&](const ir::OpSequenceIndex &op_seq_ind, ir::OpSequence &op_seq) {
+ const auto lower_info = _lowered_graph.getLowerInfo(op_seq_ind);
+ assert(lower_info != nullptr);
+ // For now, the only acl_cl supports fully fp16
+ if (lower_info->backend()->config()->id() != kAclClBackendConfigId)
+ return;
+
+ // Convert input,output operands' type to fp16
+ convertOperandsOfOpSequence(op_seq);
+ });
+}
+
+void Fp32ToFp16Converter::convertOperandsOfOpSequence(ir::OpSequence &op_seq)
+{
+ auto &operands = _lowered_graph.graph().operands();
+ const auto &operations = _lowered_graph.graph().operations();
+ const auto &op_seq_inputs = _lowered_graph.graph().getInputs();
+ const auto &op_seq_outputs = _lowered_graph.graph().getOutputs();
+
+ for (auto &op_idx : op_seq)
+ {
+ const auto &node = operations.at(op_idx);
+ for (auto &ind : node.getInputs() | ir::Remove::UNDEFINED)
+ {
+ if (node.opcode() == ir::OpCode::ConvertFp32ToFp16 || op_seq_inputs.contains(ind))
+ continue;
+
+ auto &obj = operands.at(ind);
+ if (obj.isConstant() || obj.typeInfo().type() != ir::DataType::FLOAT32)
+ continue;
+
+ obj.type(ir::DataType::FLOAT16);
+
+ VERBOSE(Fp32ToFp16Converter) << "Input Operand #" << ind.value() << ": fp16" << std::endl;
+ }
+
+ for (auto &ind : node.getOutputs())
+ {
+ if (node.opcode() == ir::OpCode::ConvertFp16ToFp32 || op_seq_outputs.contains(ind))
+ continue;
+
+ auto &obj = operands.at(ind);
+ if (obj.isConstant() || obj.typeInfo().type() != ir::DataType::FLOAT32)
+ continue;
+
+ obj.type(ir::DataType::FLOAT16);
+
+ VERBOSE(Fp32ToFp16Converter) << "Output Operand #" << ind.value() << ": fp16" << std::endl;
+ }
+ }
+}
+
+void Fp32ToFp16Converter::convertDatas()
+{
+ _lowered_graph.graph().operands().iterate([&](const ir::OperandIndex &ind, ir::Operand &obj) {
+ const auto type = obj.typeInfo().type();
+ if (type == ir::DataType::FLOAT32 && obj.isConstant())
+ {
+ auto data = obj.data();
+ assert(data != nullptr);
+
+ size_t num_elements = obj.operandSize() / ir::sizeOfDataType(type);
+ size_t new_ptr_size = num_elements * sizeof(float16);
+ auto new_ptr = std::make_unique<uint8_t[]>(new_ptr_size);
+ copyDataFromFp32ToFp16(reinterpret_cast<const float *>(data->base()),
+ reinterpret_cast<float16 *>(new_ptr.get()), num_elements);
+ obj.releaseData();
+
+ auto new_data = std::make_unique<ir::CachedData>(new_ptr.get(), new_ptr_size);
+
+ obj.data(std::move(new_data));
+ obj.type(ir::DataType::FLOAT16);
+ VERBOSE(Fp32ToFp16Converter) << "Constant Operand #" << ind.value() << ": fp16" << std::endl;
+ }
+ });
+}
+
+void Fp32ToFp16Converter::printOpSequences(const std::string &pre_msg, const std::string &post_msg)
+{
+ if (pre_msg.empty() == false)
+ {
+ VERBOSE(Fp32ToFp16Converter) << pre_msg << std::endl;
+ }
+
+ _lowered_graph.op_seqs().iterate([&](const ir::OpSequenceIndex &, const ir::OpSequence &op_seq) {
+ VERBOSE(Fp32ToFp16Converter) << ir::getStrFromOpSeq(op_seq, _lowered_graph.graph().operations())
+ << std::endl;
+ });
+
+ if (post_msg.empty() == false)
+ {
+ VERBOSE(Fp32ToFp16Converter) << post_msg << std::endl;
+ }
+}
+
+bool Fp32ToFp16Converter::checkOperandType(const ir::OperandIndex &op_ind) const
+{
+ const auto &operands = _lowered_graph.graph().operands();
+ const auto &obj = operands.at(op_ind);
+ return (obj.isConstant() == false && obj.typeInfo().type() == ir::DataType::FLOAT32);
+}
+
+bool Fp32ToFp16Converter::checkOperandsOfOpSequence(const ir::OpSequence &op_seq) const
+{
+ const auto &operations = _lowered_graph.graph().operations();
+
+ // the first node's input
+ const auto &first_node_ind = op_seq.operations().at(0);
+ const auto &first_node = operations.at(first_node_ind);
+ const auto &first_node_inputs = first_node.getInputs();
+ for (const auto &op_seq_input_ind : op_seq.getInputs() | ir::Remove::UNDEFINED)
+ {
+ if (first_node_inputs.contains(op_seq_input_ind) == false)
+ return false;
+ }
+
+ // the last node's output
+ size_t last_ind = op_seq.size() - 1;
+ const auto &last_node_ind = op_seq.operations().at(last_ind);
+ const auto &last_node = operations.at(last_node_ind);
+ const auto &last_node_outputs = last_node.getOutputs();
+ for (const auto &op_seq_output_ind : op_seq.getOutputs())
+ {
+ if (last_node_outputs.contains(op_seq_output_ind) == false)
+ return false;
+ }
+
+ return true;
+}
+
+ir::OperandIndex Fp32ToFp16Converter::newCopiedOperand(const ir::OperandIndex &op_ind)
+{
+ auto &operands = _lowered_graph.graph().operands();
+ const auto &obj = operands.at(op_ind);
+ auto new_op_ind = operands.emplace(obj.shape(), obj.typeInfo());
+ return new_op_ind;
+}
+
+void Fp32ToFp16Converter::setNewOperandLowerInfo(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OperandIndex &new_op_ind)
+{
+ const auto lower_info = _lowered_graph.getLowerInfo(op_seq_ind);
+ assert(lower_info != nullptr);
+ auto new_lower_info = std::make_unique<ir::operand::LowerInfo>();
+ auto permute_factor = ir::operand::PermuteFactor(lower_info->backend(), lower_info->layout());
+ new_lower_info->addDefPermuteFactor(permute_factor);
+ new_lower_info->addUsePermuteFactor(permute_factor);
+ _lowered_graph.setLowerInfo(new_op_ind, std::move(new_lower_info));
+}
+
+void Fp32ToFp16Converter::setNewOpSequenceLowerInfo(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OpSequenceIndex &new_op_seq_ind)
+{
+ const auto lower_info = _lowered_graph.getLowerInfo(op_seq_ind);
+ assert(lower_info != nullptr);
+
+ auto new_lower_info =
+ std::make_unique<ir::operation::LowerInfo>(lower_info->backend(), lower_info->layout());
+ _lowered_graph.setLowerInfo(new_op_seq_ind, std::move(new_lower_info));
+}
+
+void Fp32ToFp16Converter::manipulateInput(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OperandIndex &op_seq_input_ind,
+ const ir::OperandIndex &new_op_ind)
+{
+ auto &operands = _lowered_graph.graph().operands();
+ auto &operations = _lowered_graph.graph().operations();
+
+ auto &op_seq = _lowered_graph.op_seqs().at(op_seq_ind);
+
+ auto &first_node_ind = op_seq.operations().at(0);
+ auto &first_node = operations.at(first_node_ind);
+ assert(first_node.getInputs().contains(op_seq_input_ind));
+
+ auto &input_obj = operands.at(op_seq_input_ind);
+ assert(input_obj.isConstant() == false);
+
+ auto &new_op_obj = operands.at(new_op_ind);
+
+ // The same inputs having the index as op_seq_input_ind are replaced all at once
+ op_seq.replaceInputs(op_seq_input_ind, new_op_ind);
+ first_node.replaceInputs(op_seq_input_ind, new_op_ind);
+
+ // op_seq_obj doesn't have uses/def
+ input_obj.removeUse(first_node_ind);
+ new_op_obj.insertUse(first_node_ind);
+}
+
+void Fp32ToFp16Converter::manipulateOutput(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OperandIndex &op_seq_output_ind,
+ const ir::OperandIndex &new_op_ind)
+{
+ auto &operands = _lowered_graph.graph().operands();
+ auto &operations = _lowered_graph.graph().operations();
+
+ auto &op_seq = _lowered_graph.op_seqs().at(op_seq_ind);
+
+ size_t last_ind = op_seq.size() - 1;
+ auto &last_node_ind = op_seq.operations().at(last_ind);
+ auto &last_node = operations.at(last_node_ind);
+ assert(last_node.getOutputs().contains(op_seq_output_ind));
+
+ auto &output_obj = operands.at(op_seq_output_ind);
+ assert(output_obj.isConstant() == false);
+
+ auto &new_op_obj = operands.at(new_op_ind);
+
+ // The same outputs having the index as op_seq_output_ind are replaced all at once
+ op_seq.replaceOutputs(op_seq_output_ind, new_op_ind);
+ last_node.replaceOutputs(op_seq_output_ind, new_op_ind);
+
+ // op_seq_obj doesn't have uses/def
+ assert(output_obj.getDef() == last_node_ind);
+ output_obj.unsetDef();
+ new_op_obj.setDef(last_node_ind);
+}
+
+ir::OperationIndex
+Fp32ToFp16Converter::newOperationConvertFp32ToFp16(const ir::OperandIndex &op_seq_input_ind,
+ const ir::OperandIndex &new_op_ind)
+{
+ auto &operands = _lowered_graph.graph().operands();
+ auto &operations = _lowered_graph.graph().operations();
+
+ auto &input_obj = operands.at(op_seq_input_ind);
+ auto &new_op_obj = operands.at(new_op_ind);
+
+ std::unique_ptr<ir::Operation> new_node(
+ new ir::operation::ConvertFp32ToFp16({op_seq_input_ind}, {new_op_ind}));
+ const auto new_node_ind = operations.push(std::move(new_node));
+
+ input_obj.insertUse(new_node_ind);
+ new_op_obj.setDef(new_node_ind);
+
+ return new_node_ind;
+}
+
+ir::OperationIndex
+Fp32ToFp16Converter::newOperationConvertFp16ToFp32(const ir::OperandIndex &op_seq_output_ind,
+ const ir::OperandIndex &new_op_ind)
+{
+ auto &operands = _lowered_graph.graph().operands();
+ auto &operations = _lowered_graph.graph().operations();
+
+ auto &output_obj = operands.at(op_seq_output_ind);
+ auto &new_op_obj = operands.at(new_op_ind);
+
+ std::unique_ptr<ir::Operation> new_node(
+ new ir::operation::ConvertFp16ToFp32({new_op_ind}, {op_seq_output_ind}));
+ const auto new_node_ind = operations.push(std::move(new_node));
+
+ new_op_obj.insertUse(new_node_ind);
+ output_obj.setDef(new_node_ind);
+
+ return new_node_ind;
+}
+
+ir::OpSequenceIndex Fp32ToFp16Converter::newOpSequence(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OperationIndex &node_index)
+{
+ auto &node = _lowered_graph.graph().operations().at(node_index);
+ const auto lower_info = _lowered_graph.getLowerInfo(op_seq_ind);
+ assert(lower_info != nullptr);
+ auto layout = lower_info->layout();
+
+ auto op_seq = std::make_unique<ir::OpSequence>(layout);
+ op_seq->appendOperation(node_index);
+ op_seq->setOutputs(node.getOutputs());
+ op_seq->setInputs(node.getInputs());
+
+ return _lowered_graph.op_seqs().emplace(std::move(op_seq));
+}
+
+// The op_seq(Fp16To32)'s output operand is the next to op_seq (Fp32To16)?
+// If so, connect Fp16To32's previous OpSeq to Fp32To16's next OpSeq
+//
+// Assume that an OpSequence has an operation for easy explaination
+//
+// BEFORE)
+//
+// [OPERATION] // OpSeq#0
+// |
+// OP#0
+// |
+// [FP16TO32] // OpSeq#1
+// |
+// OP#1
+// |
+// [FP32TO16] // OpSeq#2
+// |
+// OP#2
+// |
+// [OPERATION] // OpSeq#3
+//
+//
+// AFTER)
+//
+// [OPERATION] // OpSeq#0
+// |
+// OP#0
+// |
+// [OPERATION] // OpSeq#3
+//
+void Fp32ToFp16Converter::removeContiguousConvertOpSequences()
+{
+ // Prepare InputToOpSeqs map
+ const auto input_to_op_seqs = prepareInputToOpSeqs();
+
+ // Find OpSequences to delete while manipulating input of OpSeq.
+ auto opseq_map_to_delete = findOpSequencesContiguous(input_to_op_seqs);
+
+ // Find Operations to delete
+ auto list_to_delete_op_seqs = getListOpSequences(opseq_map_to_delete);
+ auto list_to_delete_ops = findOperationsToDelete(list_to_delete_op_seqs);
+
+ // Before deleting, manipulateInputs of OpSeq & Operation
+ manipulateContiguousOpSequences(input_to_op_seqs, opseq_map_to_delete);
+
+ // Delete OpSequences & Operations & obj's use/def & operands
+ deleteContiguousOpSequences(list_to_delete_op_seqs, list_to_delete_ops);
+}
+
+Fp32ToFp16Converter::OpSeqIndexToOpSeqIndexList
+Fp32ToFp16Converter::findOpSequencesContiguous(const InputToOpSeqs &input_to_op_seqs) const
+{
+ const auto &op_seqs = _lowered_graph.op_seqs();
+ OpSeqIndexToOpSeqIndexList opseq_map_to_delete;
+
+ //
+ // Assume that an Operation an OpSequence for easy explaination
+ //
+ // [OPERATION]
+ // |
+ // OP#0
+ // |
+ // [FP16TO32] // op_seq_ind_fp16_to_fp32 & op_seq_fp16_to_fp32
+ // |
+ // OP#1 // output_ind_fp16_fp32
+ // |
+ // [FP32TO16] // op_seq_ind
+ // |
+ // OP#2
+ // |
+ // [OPERATION]
+ //
+ for (auto it = _list_fp16_to_fp32.cbegin(); it != _list_fp16_to_fp32.cend(); ++it)
+ {
+ // fp16_to_fp32's input/output num is always 1
+ auto &op_seq_ind_fp16_to_fp32 = *it;
+ auto &op_seq_fp16_to_fp32 = op_seqs.at(op_seq_ind_fp16_to_fp32);
+ assert(op_seq_fp16_to_fp32.size() == 1);
+ assert(op_seq_fp16_to_fp32.getInputs().size() == 1);
+
+ auto &output_ind_fp16_to_fp32 = op_seq_fp16_to_fp32.getOutputs().at(0);
+ auto found_input_in_op_seqs = input_to_op_seqs.find(output_ind_fp16_to_fp32);
+ if (found_input_in_op_seqs == input_to_op_seqs.end())
+ {
+ continue;
+ }
+
+ // DO NOT FORGET THE CASE
+ //
+ // |
+ // [FP16TO32]
+ // |
+ // OP#0---------------------.
+ // | |
+ // [FP32TO16] [FP32TO16]
+ // | |
+ // OP#1 OP#2
+ // | |
+ // [OPERATION] [OPERATION]
+ //
+ for (auto &op_seq_ind : found_input_in_op_seqs->second)
+ {
+ auto found_in_fp32_to_fp16 = _list_fp32_to_fp16.find(op_seq_ind);
+ if (found_in_fp32_to_fp16 != _list_fp32_to_fp16.end())
+ {
+ if (opseq_map_to_delete.find(op_seq_ind_fp16_to_fp32) == opseq_map_to_delete.end())
+ {
+ opseq_map_to_delete[op_seq_ind_fp16_to_fp32].emplace(op_seq_ind);
+ }
+ else
+ {
+ opseq_map_to_delete[op_seq_ind_fp16_to_fp32].insert(op_seq_ind);
+ }
+
+ VERBOSE(Fp32ToFp16Converter)
+ << "Contiguous from OpSeq#" << op_seq_ind_fp16_to_fp32.value() << "(ToFp32)"
+ << " to OpSeq#" << op_seq_ind.value() << "(ToFp16)" << std::endl;
+ }
+ }
+ }
+
+ return opseq_map_to_delete;
+}
+
+Fp32ToFp16Converter::InputToOpSeqs Fp32ToFp16Converter::prepareInputToOpSeqs() const
+{
+ const auto &op_seqs = _lowered_graph.op_seqs();
+
+ InputToOpSeqs input_to_op_seqs;
+ op_seqs.iterate([&](const ir::OpSequenceIndex &op_seq_idx, const ir::OpSequence &op_seq) {
+ for (auto input : op_seq.getInputs() | ir::Remove::UNDEFINED)
+ {
+ auto it = input_to_op_seqs.find(input);
+ if (it == input_to_op_seqs.end())
+ {
+ input_to_op_seqs[input].emplace(op_seq_idx);
+ }
+ else
+ {
+ input_to_op_seqs[input].insert(op_seq_idx);
+ }
+ }
+ });
+
+ return input_to_op_seqs;
+}
+
+Fp32ToFp16Converter::OpSeqIndexList
+Fp32ToFp16Converter::getListOpSequences(const OpSeqIndexToOpSeqIndexList &opseq_map_to_delete) const
+{
+ OpSeqIndexList list;
+ for (const auto &it : opseq_map_to_delete)
+ {
+ auto &opseq_ind_fp16_to_fp32 = it.first;
+ if (list.find(opseq_ind_fp16_to_fp32) == list.end())
+ {
+ list.emplace(opseq_ind_fp16_to_fp32);
+ }
+
+ for (auto &opseq_ind_fp32_to_fp16 : it.second)
+ {
+ if (list.find(opseq_ind_fp32_to_fp16) == list.end())
+ {
+ list.emplace(opseq_ind_fp32_to_fp16);
+ }
+ }
+ }
+ return list;
+}
+
+ir::OperandIndexSequence
+Fp32ToFp16Converter::findOperationsToDelete(const OpSeqIndexList &list_to_delete_op_seqs) const
+{
+ const auto &operations = _lowered_graph.graph().operations();
+ const auto &op_seqs = _lowered_graph.op_seqs();
+
+ ir::OperandIndexSequence list_to_delete_ops;
+ for (const auto &op_seq_ind : list_to_delete_op_seqs)
+ {
+ const auto &op_seq = op_seqs.at(op_seq_ind);
+ assert(op_seq.size() == 1);
+
+ const auto &first_node_ind = op_seq.operations().at(0);
+ const auto &first_node = operations.at(first_node_ind);
+ assert(first_node.opcode() == ir::OpCode::ConvertFp32ToFp16 ||
+ first_node.opcode() == ir::OpCode::ConvertFp16ToFp32);
+
+ for (const auto &ind : first_node.getOutputs())
+ {
+ list_to_delete_ops.append(ind);
+ }
+ }
+
+ return list_to_delete_ops;
+}
+
+void Fp32ToFp16Converter::manipulateContiguousOpSequences(
+ const InputToOpSeqs &input_to_op_seqs, const OpSeqIndexToOpSeqIndexList &opseq_map_to_delete)
+{
+ auto &op_seqs = _lowered_graph.op_seqs();
+
+ //
+ // [OPERATION]
+ // |
+ // OP#0 // input_ind_fp16_to_fp32
+ // |
+ // [FP16TO32] // op_seq_ind_fp16_to_fp32 & op_seq_fp16_to_fp32
+ // |
+ // OP#1
+ // |
+ // [FP32TO16] // op_seq_ind_fp32_to_fp16, op_seq_fp32_to_fp16
+ // |
+ // OP#2 // output_ind_fp32_to_fp16
+ // |
+ // [OPERATION] // op_seq_ind_next_to_fp16
+ //
+ for (auto it : opseq_map_to_delete)
+ {
+ // fp16_to_fp32's input/output num is always 1
+ auto &op_seq_ind_fp16_to_fp32 = it.first;
+ auto &op_seq_fp16_to_fp32 = op_seqs.at(op_seq_ind_fp16_to_fp32);
+ auto &input_ind_fp16_to_fp32 = op_seq_fp16_to_fp32.getInputs().at(0);
+
+ for (auto &op_seq_ind_fp32_to_fp16 : it.second)
+ {
+ auto &op_seq_fp32_to_fp16 = op_seqs.at(op_seq_ind_fp32_to_fp16);
+ assert(op_seq_fp32_to_fp16.size() == 1);
+ assert(op_seq_fp32_to_fp16.getInputs().size() == 1);
+
+ auto &output_ind_fp32_to_fp16 = op_seq_fp32_to_fp16.getOutputs().at(0);
+ auto found_next_to_fp16 = input_to_op_seqs.find(output_ind_fp32_to_fp16);
+ assert(found_next_to_fp16 != input_to_op_seqs.end());
+
+ for (auto &op_seq_ind_next_to_fp16 : found_next_to_fp16->second)
+ {
+ manipulateInput(op_seq_ind_next_to_fp16, output_ind_fp32_to_fp16, input_ind_fp16_to_fp32);
+ }
+ //
+ // [OPERATION]
+ // |
+ // OP#0 // input_ind_fp16_to_fp32
+ // |
+ // [OPERATION] // op_seq_ind_next_to_fp16
+ //
+ }
+ }
+}
+
+void Fp32ToFp16Converter::deleteContiguousOpSequences(
+ const OpSeqIndexList &list_to_delete_op_seqs,
+ const ir::OperandIndexSequence &list_to_delete_ops)
+{
+ auto &operands = _lowered_graph.graph().operands();
+ auto &operations = _lowered_graph.graph().operations();
+ auto &op_seqs = _lowered_graph.op_seqs();
+
+ for (auto &op_seq_ind : list_to_delete_op_seqs)
+ {
+ auto &op_seq = op_seqs.at(op_seq_ind);
+ assert(op_seq.size() == 1);
+ VERBOSE(Fp32ToFp16Converter) << "Delete OpSeq #" << op_seq_ind.value() << std::endl;
+
+ auto &first_node_ind = op_seq.operations().at(0);
+ auto &first_node = operations.at(first_node_ind);
+ assert(first_node.opcode() == ir::OpCode::ConvertFp32ToFp16 ||
+ first_node.opcode() == ir::OpCode::ConvertFp16ToFp32);
+ VERBOSE(Fp32ToFp16Converter) << "Delete Node #" << first_node_ind.value() << std::endl;
+
+ // Uses
+ for (auto &ind : first_node.getInputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ auto &obj = operands.at(ind);
+ obj.removeUse(first_node_ind);
+ VERBOSE(Fp32ToFp16Converter) << "Operand #" << ind.value() << "'s Use(Node#"
+ << first_node_ind.value() << ") is removed" << std::endl;
+ }
+
+ // Def
+ for (auto &ind : first_node.getOutputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ auto &obj = operands.at(ind);
+ assert(obj.getDef() == first_node_ind);
+ obj.unsetDef();
+ VERBOSE(Fp32ToFp16Converter) << "Operand #" << ind.value() << "'s Def(Node#"
+ << first_node_ind.value() << ") is removed" << std::endl;
+ }
+
+ // Operation
+ operations.remove(first_node_ind);
+ VERBOSE(Fp32ToFp16Converter) << "Node#" << first_node_ind.value() << " is removed" << std::endl;
+
+ // OpSequence
+ op_seqs.remove(op_seq_ind);
+ VERBOSE(Fp32ToFp16Converter) << "OpSeq#" << op_seq_ind.value() << " is removed" << std::endl;
+ }
+
+ // Operand
+ for (auto &ind : list_to_delete_ops)
+ {
+ operands.remove(ind);
+ VERBOSE(Fp32ToFp16Converter) << "Operand #" << ind.value() << " is removed" << std::endl;
+ }
+}
+
+} // namespace compiler
+
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/Fp32ToFp16Converter.h b/runtime/onert/core/src/compiler/Fp32ToFp16Converter.h
new file mode 100644
index 000000000..eeecb9846
--- /dev/null
+++ b/runtime/onert/core/src/compiler/Fp32ToFp16Converter.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_FP32_TO_FP16_CONVERTER_H__
+#define __ONERT_COMPILER_FP32_TO_FP16_CONVERTER_H__
+
+#include "compiler/LoweredGraph.h"
+
+namespace onert
+{
+
+namespace compiler
+{
+
+class Fp32ToFp16Converter
+{
+public:
+ Fp32ToFp16Converter(compiler::LoweredGraph &lowered_graph);
+
+public:
+ void run();
+
+private:
+ using OpSeqIndexList = std::unordered_set<ir::OpSequenceIndex>;
+ using InputToOpSeqs = std::unordered_map<ir::OperandIndex, OpSeqIndexList>;
+ using OpSeqIndexToOpSeqIndexList = std::unordered_map<ir::OpSequenceIndex, OpSeqIndexList>;
+
+private:
+ void appendOpSequences();
+ void optimize();
+ void convertOperands();
+ void convertDatas();
+ void printOpSequences(const std::string &pre_msg = std::string(),
+ const std::string &post_msg = std::string());
+
+ bool checkOperandType(const ir::OperandIndex &op_ind) const;
+ bool checkOperandsOfOpSequence(const ir::OpSequence &op_seq) const;
+
+ void appendNewOpSeqForConvertFp32ToFp16(const ir::OpSequenceIndex &op_seq_ind,
+ ir::OpSequence &op_seq);
+ void appendNewOpSeqForConvertFp16ToFp32(const ir::OpSequenceIndex &op_seq_ind,
+ ir::OpSequence &op_seq);
+
+ ir::OperandIndex newCopiedOperand(const ir::OperandIndex &op_ind);
+ ir::OperationIndex newOperationConvertFp32ToFp16(const ir::OperandIndex &op_seq_input_ind,
+ const ir::OperandIndex &new_op_ind);
+ ir::OperationIndex newOperationConvertFp16ToFp32(const ir::OperandIndex &op_seq_output_ind,
+ const ir::OperandIndex &new_op_ind);
+ ir::OpSequenceIndex newOpSequence(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OperationIndex &node_index);
+
+ void setNewOperandLowerInfo(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OperandIndex &new_op_ind);
+ void setNewOpSequenceLowerInfo(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OpSequenceIndex &new_op_seq_ind);
+
+ void manipulateInput(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OperandIndex &op_seq_input_ind,
+ const ir::OperandIndex &new_op_ind);
+ void manipulateOutput(const ir::OpSequenceIndex &op_seq_ind,
+ const ir::OperandIndex &op_seq_output_ind,
+ const ir::OperandIndex &new_op_ind);
+
+ void removeContiguousConvertOpSequences();
+ InputToOpSeqs prepareInputToOpSeqs() const;
+ OpSeqIndexToOpSeqIndexList
+ findOpSequencesContiguous(const InputToOpSeqs &intput_to_op_seqs) const;
+ OpSeqIndexList getListOpSequences(const OpSeqIndexToOpSeqIndexList &opseq_map_to_delete) const;
+ ir::OperandIndexSequence
+ findOperationsToDelete(const OpSeqIndexList &list_to_delete_op_seqs) const;
+ void manipulateContiguousOpSequences(const InputToOpSeqs &input_to_op_seqs,
+ const OpSeqIndexToOpSeqIndexList &opseq_map_to_delete);
+ void deleteContiguousOpSequences(const OpSeqIndexList &list_to_delete_op_seqs,
+ const ir::OperandIndexSequence &list_to_delete_ops);
+
+ void convertOperandsOfOpSequence(ir::OpSequence &op_seq);
+
+private:
+ compiler::LoweredGraph &_lowered_graph;
+ OpSeqIndexList _list_fp32_to_fp16;
+ OpSeqIndexList _list_fp16_to_fp32;
+};
+
+} // namespace compiler
+
+} // namespace onert
+
+#endif // __ONERT_COMPILER_FP32_TO_FP16_CONVERTER_H__
diff --git a/runtime/onert/core/src/compiler/HEScheduler.cc b/runtime/onert/core/src/compiler/HEScheduler.cc
new file mode 100644
index 000000000..349b1c221
--- /dev/null
+++ b/runtime/onert/core/src/compiler/HEScheduler.cc
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Operand.h"
+#include "compiler/HEScheduler.h"
+#include "ir/Graph.h"
+#include "util/ConfigSource.h"
+#include "compiler/BackendResolver.h"
+#include "util/logging.h"
+#include "util/Utils.h"
+#include "exec/FunctionSequence.h"
+#include <cassert>
+#include <cmath>
+#include <chrono>
+
+namespace
+{
+
+using namespace onert;
+
+uint32_t getOperationsFlattenedIOSize(const ir::Graph &graph, const ir::Operation &node)
+{
+ uint32_t size = 0;
+ for (const auto &ind :
+ (node.getInputs() | ir::Remove::UNDEFINED) + (node.getOutputs() | ir::Remove::UNDEFINED))
+ {
+ size += graph.operands().at(ind).info().total_size();
+ }
+ return size;
+}
+
+bool isQuant(const ir::Graph &graph, const ir::Operation &node)
+{
+ for (const auto &input : node.getInputs() | ir::Remove::UNDEFINED)
+ {
+ const auto &obj = graph.operands().at(input);
+ if (obj.typeInfo().type() == ir::DataType::QUANT_UINT8_ASYMM)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isWorkaroundSkip(const ir::Graph &, const backend::Backend *, const ir::Operation &, bool)
+{
+ // Now, there is no workaround
+ return false;
+}
+
+// if a node can be merged into op_seq
+bool isMergeable(const ir::Graph &graph, const ir::Operation &node)
+{
+ size_t prev_op_cnt = 0;
+ for (const auto &input : node.getInputs() | ir::Remove::UNDEFINED)
+ {
+ // only valid_inputs
+ const auto &operand = graph.operands().at(input);
+ if (operand.isConstant())
+ continue;
+
+ // This operand is output of operation, not weight or bias
+ if (operand.getDef().valid())
+ ++prev_op_cnt;
+
+ // Current node has multiple inputs as concat or at the beginning of the separated branch
+ if (prev_op_cnt > 1 || operand.getUses().size() > 1)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+namespace onert
+{
+
+namespace compiler
+{
+
+void HEScheduler::scheduleShufflingBackends()
+{
+ VERBOSE(HEScheduler::schedule)
+ << "Started task scheduling: uses all backends to get more metrics for data transfer"
+ << std::endl;
+ size_t backend_ind = 0;
+ for (const auto &rank : _rank_to_op)
+ {
+ VERBOSE(HEScheduler::schedule) << "scheduling (" << rank.second.value() << ")" << std::endl;
+ const auto &node = _graph->operations().at(rank.second);
+ const bool quant = isQuant(*_graph, node);
+ const auto size = getOperationsFlattenedIOSize(*_graph, node);
+ for (size_t i = 0;; ++i)
+ {
+ if (i == _all_backends.size())
+ {
+ // wasn't able to find backend
+ assert(false);
+ break;
+ }
+ if (backend_ind == _all_backends.size())
+ {
+ backend_ind = 0;
+ }
+ if (isWorkaroundSkip(*_graph, _all_backends[backend_ind], node, quant))
+ {
+ ++backend_ind;
+ continue;
+ }
+ const auto exec_time =
+ _exec_time->getOperationExecTime(_all_backends[backend_ind], node.name(), quant, size);
+ // Scheduling to measure data transfer must be done after measuring all backends separately
+ assert(exec_time != _exec_time->NOT_FOUND);
+ if (exec_time == _exec_time->getMax())
+ {
+ ++backend_ind;
+ continue;
+ }
+ _backend_resolver->setBackend(rank.second, _all_backends[backend_ind]);
+ VERBOSE(HEScheduler::schedule) << "backend for " << node.name() << " is "
+ << _all_backends[backend_ind]->config()->id() << std::endl;
+ ++backend_ind;
+ break;
+ }
+ }
+}
+
+bool HEScheduler::isNodeProfiled(const ir::Operation &node)
+{
+ const bool quant = isQuant(*_graph, node);
+ const auto size = getOperationsFlattenedIOSize(*_graph, node);
+ for (const auto *backend : _all_backends)
+ {
+ const auto exec_time = _exec_time->getOperationExecTime(backend, node.name(), quant, size);
+ if (exec_time == _exec_time->NOT_FOUND)
+ return false;
+ }
+ return true;
+}
+
+void HEScheduler::scheduleBranch(const ir::OperationIndex &index,
+ ir::OperationIndexMap<bool> &scheduled)
+{
+ auto loc_index = index;
+ const backend::Backend *parent_backend = nullptr;
+ while (true)
+ {
+ if (scheduled[loc_index])
+ {
+ return;
+ }
+ if (!schedule(loc_index, parent_backend))
+ {
+ return;
+ }
+ scheduled[loc_index] = true;
+ parent_backend = _backend_resolver->getBackend(loc_index);
+
+ const auto &node = _graph->operations().at(loc_index);
+ /* get the only output operand, that is input of the next single operation
+ * and just this nodes output.*/
+ if (node.getOutputs().size() != 1)
+ {
+ return;
+ }
+ const auto &only_out_operand = _graph->operands().at(*node.getOutputs().begin());
+ // One of the last nodes
+ if (only_out_operand.getUses().size() == 0)
+ {
+ return;
+ }
+ loc_index = *only_out_operand.getUses().begin();
+ /* verify, that next node is neither beginning nor ending node of a branch*/
+ const auto &next_node = _graph->operations().at(loc_index);
+ if (!isMergeable(*_graph, next_node))
+ {
+ return;
+ }
+ }
+}
+
+std::unique_ptr<compiler::BackendResolver> HEScheduler::schedule(const ir::Graph &graph)
+{
+ _graph = &graph;
+ VERBOSE(HEScheduler::schedule) << "task scheduling started" << std::endl;
+ // Make ranks and save in descending order
+ makeRank();
+
+ for (const auto *backend : _all_backends)
+ {
+ _backends_avail_time.emplace(backend, std::map<int64_t, int64_t>{{0, 0}});
+ }
+
+ if (_is_profiling_mode)
+ {
+ // Check if profiling info about all backend/node pairs already exists
+ bool all_nodes_are_profiled = true;
+ _graph->operations().iterate([&](const ir::OperationIndex &, const ir::Operation &op) {
+ if (all_nodes_are_profiled)
+ all_nodes_are_profiled = isNodeProfiled(op);
+ });
+
+ // If all nodes are already profiled - schedule backends in such order, so more profiling
+ // information about between-backends data transfer could be collected
+ if (all_nodes_are_profiled)
+ {
+ scheduleShufflingBackends();
+ VERBOSE(HEScheduler::schedule) << "task scheduling finished" << std::endl;
+ return std::move(_backend_resolver);
+ }
+ }
+
+ ir::OperationIndexMap<bool> visited;
+ graph.operations().iterate(
+ [&](const ir::OperationIndex &index, const ir::Operation &) { visited[index] = false; });
+ // for each task select the backend with the smallest earliest finishing time(eft)
+ for (const auto &rank : _rank_to_op)
+ {
+ scheduleBranch(rank.second, visited);
+ }
+ VERBOSE(HEScheduler::schedule) << "task scheduling finished" << std::endl;
+ return std::move(_backend_resolver);
+}
+
+int64_t HEScheduler::getOpTime(const backend::Backend *backend, const std::string &operation,
+ bool quant, uint32_t size)
+{
+ const auto time = _exec_time->getOperationExecTime(backend, operation, quant, size);
+ if (time != _exec_time->NOT_FOUND)
+ return time;
+
+ return _is_supported.at(backend).at(operation) ? 1 : _exec_time->getMax();
+}
+
+int64_t HEScheduler::getPermuteTime(const backend::Backend *src_backend,
+ const backend::Backend *dst_backend, bool quant, uint32_t size)
+{
+ // TODO Change it to getOperationExecTime()
+ const auto time = _exec_time->getPermuteTime(src_backend, dst_backend, quant, size);
+
+ if (time != _exec_time->NOT_FOUND)
+ return time;
+
+ // FIXME permute time is not recorded so the control reaches here always
+ // Makes the scheduler prefer keeping computations on one backend
+ return size / 400;
+}
+
+int64_t HEScheduler::tryBackend(const ir::Operation &node, const backend::Backend *backend)
+{
+ // if there is no profiling info don't use this backend during scheduling
+ if (!_is_profiling_mode)
+ {
+ VERBOSE(HEScheduler::tryBackend)
+ << "Trying to HE schedule while there is no profiling info for " << node.name()
+ << " on backend " << backend->config()->id() << ". So this backend won't be used. "
+ << std::endl;
+ _is_supported[backend][node.name()] = false;
+ return _exec_time->getMax();
+ }
+ auto iter = _is_supported.find(backend);
+ if (iter != _is_supported.end())
+ {
+ auto it2 = iter->second.find(node.name());
+ if (it2 != iter->second.end())
+ {
+ return _is_supported[backend][node.name()] ? 1 : _exec_time->getMax();
+ }
+ }
+ try
+ {
+ // DO NOTHING
+
+ _is_supported[backend][node.name()] = true;
+ }
+ catch (std::runtime_error &e)
+ {
+ _is_supported[backend][node.name()] = false;
+ }
+ return _is_supported[backend][node.name()] ? 1 : _exec_time->getMax();
+}
+
+void HEScheduler::makeRank()
+{
+ VERBOSE(HEScheduler::makeRank) << "task prioritizing" << std::endl;
+
+ _graph->operations().iterate(
+ [&](const ir::OperationIndex &index, const ir::Operation &) { DFSMaxRank(index); });
+
+ // Check that ranks are calculated for all operations(nodes)
+ _graph->operations().iterate([&](const ir::OperationIndex &index, const ir::Operation &) {
+ UNUSED_RELEASE(index);
+ assert(_op_to_rank->find(index) != _op_to_rank->end());
+ });
+ VERBOSE(HEScheduler::makeRank) << "task prioritizing finished" << std::endl;
+}
+
+int64_t HEScheduler::DFSMaxRank(const ir::OperationIndex &index)
+{
+ auto op_to_rank_it = _op_to_rank->find(index);
+ if (op_to_rank_it != _op_to_rank->end())
+ return op_to_rank_it->second;
+
+ const auto &node = _graph->operations().at(index);
+ int64_t rank = 0;
+ const bool quant = isQuant(*_graph, node);
+ const auto size = getOperationsFlattenedIOSize(*_graph, node);
+ auto supported_backends_quantity = static_cast<int64_t>(_all_backends.size());
+
+ const auto max_child_rank = DFSChildrenMaxRank(index);
+
+ // get average exec time of this op
+ for (const auto &backend : _all_backends)
+ {
+ auto exec_time = _exec_time->getOperationExecTime(backend, node.name(), quant, size);
+ if (exec_time == _exec_time->NOT_FOUND)
+ {
+ exec_time = tryBackend(node, backend);
+ }
+ if (exec_time < _exec_time->getMax())
+ {
+ rank += exec_time;
+ }
+ else
+ {
+ // this operation isn't supported in this backend
+ --supported_backends_quantity;
+ }
+ }
+ if (supported_backends_quantity == 0)
+ {
+ throw std::runtime_error{"Encountered unsupported op: " + node.name()};
+ }
+ rank /= supported_backends_quantity;
+
+ // get standard deviation
+ int64_t std = 0;
+ for (const auto backend : _all_backends)
+ {
+ const auto exec_time = getOpTime(backend, node.name(), quant, size);
+ if (exec_time < _exec_time->getMax())
+ {
+ std += (exec_time - rank) * (exec_time - rank);
+ }
+ }
+ std /= supported_backends_quantity;
+ if (std > 0)
+ {
+ std = static_cast<int>(std::sqrt(std));
+ rank *= std;
+ }
+ rank += max_child_rank;
+
+ assert(rank >= 0);
+ _rank_to_op.emplace(rank, index);
+ _op_to_rank->emplace(index, rank);
+ VERBOSE(HEScheduler::DFSMaxRank) << "rank of operation (" << index.value() << ")" << node.name()
+ << " is " << rank << std::endl;
+
+ return rank;
+}
+
+int64_t HEScheduler::DFSChildrenMaxRank(const ir::OperationIndex &index)
+{
+ const auto &node = _graph->operations().at(index);
+ int64_t max_child_rank = 0;
+ for (const auto &output : node.getOutputs() | ir::Remove::UNDEFINED)
+ {
+ const auto &operand = _graph->operands().at(output);
+ const bool quant = operand.typeInfo().type() == ir::DataType::QUANT_UINT8_ASYMM;
+ // average data transfer cost of this operand's data
+ int64_t avg_transfer_cost = 1;
+ for (const auto *backend : _all_backends)
+ {
+ for (const auto *other_backend : _all_backends)
+ {
+ if (backend == other_backend)
+ {
+ continue;
+ }
+ // TODO Change it to controlflow backend
+ auto transfer_cost =
+ getPermuteTime(backend, other_backend, quant, operand.info().total_size());
+ avg_transfer_cost += transfer_cost;
+ }
+ }
+ avg_transfer_cost /= _all_backends.size();
+ for (const auto &use : operand.getUses())
+ {
+ const auto cur_child_rank = DFSMaxRank(use);
+ max_child_rank = std::max(max_child_rank, cur_child_rank + avg_transfer_cost);
+ }
+ }
+ return max_child_rank;
+}
+
+int64_t HEScheduler::backendAvailableTime(const backend::Backend *backend,
+ const int64_t &starting_time, const int64_t &time_amount)
+{
+ const auto backend_times = _backends_avail_time.at(backend);
+ // finishing and starting times of an op, that will come after current op
+ auto next_op_fst = backend_times.upper_bound(starting_time);
+ // finishing time of an op, that will come before current op
+ auto prev_op_ft = starting_time;
+ // until reach the "hole/gap", that is enough to run this op
+ while (next_op_fst != backend_times.end() && next_op_fst->second - prev_op_ft <= time_amount)
+ {
+ prev_op_ft = next_op_fst->first + 1;
+ ++next_op_fst;
+ }
+ return prev_op_ft;
+}
+
+bool HEScheduler::schedule(const ir::OperationIndex &index, const backend::Backend *parent_backend)
+{
+ VERBOSE(HEScheduler::schedule) << "scheduling (" << index.value() << ")" << std::endl;
+ int64_t eft = std::numeric_limits<int64_t>::max(), selected_exec_time = 0;
+ const auto &node = _graph->operations().at(index);
+
+ std::multimap<int64_t, int64_t> selected_transfer_st_exec_time;
+ // select the backend with the smallest eft of this task
+ const backend::Backend *chosen_backend = nullptr;
+ for (const auto *backend : _all_backends)
+ {
+ std::multimap<int64_t, int64_t> transfer_st_exec_time;
+ const auto est_and_et = ESTAndExecTime(backend, index, transfer_st_exec_time);
+
+ if (eft > est_and_et.first + est_and_et.second)
+ {
+ eft = est_and_et.first + est_and_et.second;
+ selected_exec_time = est_and_et.second;
+ chosen_backend = backend;
+ selected_transfer_st_exec_time = transfer_st_exec_time;
+ }
+ }
+
+ if (chosen_backend == nullptr)
+ {
+ throw std::runtime_error{"Fail to choose backend on scheduler"};
+ }
+
+ // this is part of a branch and it is assigned another backend
+ if (parent_backend && parent_backend != chosen_backend)
+ {
+ return false;
+ }
+ for (const auto &it : selected_transfer_st_exec_time)
+ {
+ auto prev_op_ft = backendAvailableTime(_cpu_backend, it.first, it.second);
+ _backends_avail_time[_cpu_backend].insert({prev_op_ft + it.second, prev_op_ft});
+ }
+
+ _ops_eft[index] = eft;
+ _backends_avail_time[chosen_backend].emplace(eft, eft - selected_exec_time);
+ _backend_resolver->setBackend(index, chosen_backend);
+
+ VERBOSE(HEScheduler::schedule) << "backend for " << node.name() << " is "
+ << chosen_backend->config()->id() << ". Its eft: " << eft
+ << std::endl;
+ return true;
+}
+
+std::pair<int64_t, int64_t>
+HEScheduler::ESTAndExecTime(const backend::Backend *backend, const ir::OperationIndex &index,
+ std::multimap<int64_t, int64_t> &transfer_st_exec_time)
+{
+ // Permutation will cause creating a separate op_seq that contains just this permutation node.
+ // This isn't needed for Linear executor since it doesn't use op_seqs
+ // Number 1 ms is picked experimentally
+ int64_t permute_fine = 1000;
+ // Multiply cpu operations' exec time by 2 because in parallel executor it might be busy with
+ // permutation on other branches or non-nnfw specific tasks and have to wait for it.
+ // Number 2 is picked experimentally
+ const int64_t CPU_DELAY = 2;
+ const auto &node = _graph->operations().at(index);
+ const bool quant = isQuant(*_graph, node);
+ const auto size = getOperationsFlattenedIOSize(*_graph, node);
+ // if this node can be part of a op_seq, then assigning different backend will cause creating
+ // another op_seq
+ if (isMergeable(*_graph, node))
+ {
+ permute_fine *= 2;
+ }
+ if (isWorkaroundSkip(*_graph, backend, node, quant))
+ {
+ return {_exec_time->getMax(), _exec_time->getMax()};
+ }
+ // get average exec time of the op on this backend
+ auto exec_time = getOpTime(backend, node.name(), quant, size);
+ if (backend->config()->id() == "cpu" && _is_parallel_exec)
+ {
+ exec_time *= CPU_DELAY;
+ }
+
+ // get max eft of direct (one level above) predecessors
+ auto max_pred_eft = predMaxEFT(backend, node, transfer_st_exec_time);
+
+ int64_t total_transfer_cost = 0;
+ std::vector<std::multimap<int64_t, int64_t>::iterator> inserted_permutations;
+ // Find free time for data transferring and insert it into backend taskset. This is needed:
+ // 1. Time for multiple permutations for this node's input is found correctly
+ // 2. If backend==cpu, then free time for this node must come after permutations
+ for (auto &it : transfer_st_exec_time)
+ {
+ if (_is_parallel_exec)
+ {
+ it.second *= CPU_DELAY;
+ }
+ if (!_is_linear_exec)
+ {
+ it.second += permute_fine;
+ }
+ total_transfer_cost += it.second;
+
+ const auto prev_op_ft = backendAvailableTime(_cpu_backend, it.first, it.second);
+
+ max_pred_eft = std::max(max_pred_eft, prev_op_ft + it.second);
+
+ const auto tmp = _backends_avail_time[_cpu_backend].emplace(prev_op_ft + it.second, prev_op_ft);
+ inserted_permutations.push_back(tmp.first);
+ }
+ // find the hole/gap, where this op can be put or the finishing time of the last assigned op
+ auto prev_op_ft = backendAvailableTime(backend, max_pred_eft, exec_time);
+
+ // Remove inserted permutation from cpu's task set
+ for (const auto &it : inserted_permutations)
+ {
+ _backends_avail_time[_cpu_backend].erase(it);
+ }
+
+ /* In case non-parallel executor measure just exec time and data transfer time
+ * because EFT(prev_op_ft) is the same for all backends. Since two operations
+ * can't be run simultaneously, finish of running operation must be waited for.
+ * When an operation starts, all backends are free. So, they need time just for
+ * data transfer.*/
+ if (!_is_parallel_exec)
+ {
+ VERBOSE(HEScheduler::ESTAndExecTime)
+ << "exec_time of (" << index.value() << ") " << node.name() << " quant==" << quant << " on "
+ << backend->config()->id() << " is " << exec_time
+ << " microseconds. Data transfer cost: " << total_transfer_cost << std::endl;
+
+ return {total_transfer_cost, exec_time};
+ }
+ VERBOSE(HEScheduler::ESTAndExecTime)
+ << "exec_time of (" << index.value() << ") " << node.name() << " quant==" << quant << " on "
+ << backend->config()->id() << ": " << exec_time
+ << " microseconds. Backend available time: " << prev_op_ft
+ << " Parent's max eft: " << max_pred_eft - total_transfer_cost
+ << " data transfer cost: " << total_transfer_cost << std::endl;
+
+ return {prev_op_ft, exec_time};
+}
+
+int64_t HEScheduler::predMaxEFT(const backend::Backend *backend, const ir::Operation &node,
+ std::multimap<int64_t, int64_t> &transfer_st_exec_time)
+{
+ int64_t max_pred_eft = 0;
+ for (const auto &input_operand_idx : node.getInputs() | ir::Remove::UNDEFINED)
+ {
+ const auto &input_operand = _graph->operands().at(input_operand_idx);
+ const bool quant = input_operand.typeInfo().type() == ir::DataType::QUANT_UINT8_ASYMM;
+
+ auto input_node_idx = input_operand.getDef();
+ if (input_node_idx.valid())
+ {
+ // Data transfer cost from parent's node backend to current node's backend:
+ auto parent_backend = _backend_resolver->getBackend(input_node_idx);
+
+ max_pred_eft = std::max(max_pred_eft, _ops_eft.at(input_node_idx));
+ if (parent_backend != backend)
+ {
+ // Multiply operand size by 2 because size must describe input+output size
+ int64_t transfer_cost =
+ getPermuteTime(parent_backend, backend, quant, input_operand.info().total_size() * 2);
+ transfer_st_exec_time.emplace(_ops_eft.at(input_node_idx), transfer_cost);
+ }
+ }
+ }
+ return max_pred_eft;
+}
+
+} // namespace compiler
+
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/HEScheduler.h b/runtime/onert/core/src/compiler/HEScheduler.h
new file mode 100644
index 000000000..b9cee5881
--- /dev/null
+++ b/runtime/onert/core/src/compiler/HEScheduler.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file HEScheduler.h
+ * @brief This file contains HEScheduler class to define and run task Heterogeneous Execution
+ * Scheduler
+ */
+
+#ifndef __ONERT_COMPILER_H_E_SCHEDULER_H_
+#define __ONERT_COMPILER_H_E_SCHEDULER_H_
+
+#include "compiler/IScheduler.h"
+#include "compiler/BackendManager.h"
+#include "compiler/Compiler.h"
+#include "ir/Graph.h"
+#include "exec/ExecTime.h"
+#include "backend/Backend.h"
+#include <memory>
+#include "ir/OperationIndexMap.h"
+#include <map>
+#include <memory>
+
+namespace onert
+{
+
+namespace compiler
+{
+/**
+ * @brief Class to schedule tasks
+ */
+class HEScheduler : IScheduler
+{
+public:
+ /**
+ * @brief Construct a new Heterogeneous Execution Scheduler object
+ * @param[in] model Graph model
+ * @param[in] backend_resolver backend resolver
+ */
+ HEScheduler(const backend::BackendContexts &backend_contexts, const CompilerOptions &options)
+ : _is_supported{}, _backends_avail_time{}, _ops_eft{},
+ _op_to_rank{std::make_shared<ir::OperationIndexMap<int64_t>>()},
+ _is_profiling_mode{options.he_profiling_mode},
+ _is_linear_exec{options.executor == "Linear"},
+ _is_parallel_exec{options.executor == "Parallel"}
+ {
+ for (auto &entry : backend_contexts)
+ {
+ if (entry.first->config()->id() == backend::controlflow::Config::ID)
+ continue;
+ _all_backends.push_back(entry.first);
+ }
+ _backend_resolver = std::make_unique<compiler::BackendResolver>();
+ _exec_time = std::make_unique<exec::ExecTime>(_all_backends);
+
+ // Find cpu backend
+ auto cpu_backend_it = std::find_if(
+ _all_backends.begin(), _all_backends.end(),
+ [](const backend::Backend *backend) { return backend->config()->id() == "cpu"; });
+ if (cpu_backend_it == _all_backends.end())
+ throw std::runtime_error("HEScheduler could be used only if 'cpu' backend is available");
+ _cpu_backend = *cpu_backend_it;
+ }
+
+public:
+ /**
+ * @brief Task scheduling
+ *
+ * @note The main idea is taken from HSIP algo:
+ * https://www.hindawi.com/journals/sp/2016/3676149/
+ */
+ std::unique_ptr<compiler::BackendResolver> schedule(const ir::Graph &graph) final;
+ std::shared_ptr<ir::OperationIndexMap<int64_t>> getIndexedRanks() { return _op_to_rank; }
+
+private:
+ bool isNodeProfiled(const ir::Operation &);
+
+ bool schedule(const ir::OperationIndex &, const backend::Backend *parent_backend);
+ /**
+ * @brief Get earliest starting time and execution time of an operation on a backend.
+ *
+ * @note Returns a time when operation's inputs are ready and backend is available
+ * It also returns exec time. If this is "cpu" backend, then exec_time*CPU_DELAY
+ *
+ * @param[in] backend: backend, for which to return the time
+ * @param[in] index: index of an operation
+ * @param[out] transfer_st_exec_time: est and exec time of data transfer operation
+ *
+ * @return earliest starting time and execution time
+ */
+ std::pair<int64_t, int64_t>
+ ESTAndExecTime(const backend::Backend *backend, const ir::OperationIndex &index,
+ std::multimap<int64_t, int64_t> &transfer_st_exec_time);
+ /**
+ * @brief Returns the latest finishing time of parents of a node.
+ *
+ * @param[in] backend: backend, for which to return the time
+ * @param[in] node: node to get eft of parents
+ * @param[out] transfer_st_exec_time: est and exec time of data transfer operation
+ *
+ * @return earliest finishing time of parent nodes
+ */
+ int64_t predMaxEFT(const backend::Backend *backend, const ir::Operation &node,
+ std::multimap<int64_t, int64_t> &transfer_st_exec_time);
+
+ void makeRank();
+
+ int64_t DFSMaxRank(const ir::OperationIndex &index);
+
+ int64_t DFSChildrenMaxRank(const ir::OperationIndex &index);
+ /**
+ * @brief Returns the time, when backend is available for at least given amount of time.
+ *
+ * @note Returns either hole/gap between two performing two already scheduled operations,
+ * or the finishing time of the last scheduled operation
+ *
+ * @param[in] backend backend, for which to return the time
+ * @param[in] starting_time time, starting which to look for gap
+ * @param[in] time_amount amount of the time, for which to look gap
+ *
+ * @return time, when backend has at least time_amount free time
+ */
+ int64_t backendAvailableTime(const backend::Backend *backend, const int64_t &starting_time,
+ const int64_t &time_amount);
+
+ int64_t getOpTime(const backend::Backend *backend, const std::string &operation, bool quant,
+ uint32_t size);
+
+ int64_t getPermuteTime(const backend::Backend *src_backend, const backend::Backend *dst_backend,
+ bool quant, uint32_t size);
+
+ void scheduleShufflingBackends();
+
+ int64_t tryBackend(const ir::Operation &node, const backend::Backend *backend);
+
+ /**
+ * @brief Schedule a node and its successor until:
+ * 1. there is no branching or connection of multiple branches
+ * 2. for subsequent nodes: other than predecessor's backend is prefered
+ *
+ * @param[in] index: index of an operation
+ * @param[in] scheduled: a map to check if this node has already been scheduled
+ *
+ * @return N/A
+ */
+ void scheduleBranch(const ir::OperationIndex &index, ir::OperationIndexMap<bool> &scheduled);
+
+private:
+ // This variable stores backend/node pairs with unknown execution time, and hints scheduler
+ // whether it should assign these backends to these nodes:
+ // * It stores false for unsupported nodes
+ // * During rank calculation with enabled profiling mode it stores true for supported nodes
+ std::unordered_map<const backend::Backend *, std::unordered_map<std::string, bool>> _is_supported;
+ // Finishing and starting time of each backend
+ std::unordered_map<const backend::Backend *, std::map<int64_t, int64_t>> _backends_avail_time;
+ ir::OperationIndexMap<int64_t> _ops_eft;
+ std::multimap<int64_t, ir::OperationIndex, std::greater<int64_t>> _rank_to_op;
+ std::shared_ptr<ir::OperationIndexMap<int64_t>> _op_to_rank;
+ std::unique_ptr<compiler::BackendResolver> _backend_resolver;
+ std::unique_ptr<exec::ExecTime> _exec_time;
+ const ir::Graph *_graph{nullptr};
+ std::vector<const backend::Backend *> _all_backends;
+ const backend::Backend *_cpu_backend{nullptr}; // TODO Change this to controlflow_backend
+ bool _is_profiling_mode;
+ bool _is_linear_exec;
+ bool _is_parallel_exec;
+};
+
+} // namespace compiler
+
+} // namespace onert
+
+#endif // __ONERT_COMPILER_H_E_SCHEDULER_H_
diff --git a/runtime/onert/core/src/compiler/IScheduler.h b/runtime/onert/core/src/compiler/IScheduler.h
new file mode 100644
index 000000000..5e9b9bd3c
--- /dev/null
+++ b/runtime/onert/core/src/compiler/IScheduler.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_CORE_COMPILER_I_SCHEDULER_H__
+#define __ONERT_CORE_COMPILER_I_SCHEDULER_H__
+
+#include "compiler/BackendResolver.h"
+#include "ir/Graph.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+struct IScheduler
+{
+ virtual ~IScheduler() = default;
+
+ virtual std::unique_ptr<BackendResolver> schedule(const ir::Graph &graph) = 0;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_CORE_COMPILER_I_SCHEDULER_H__
diff --git a/runtime/onert/core/src/compiler/Linear.cc b/runtime/onert/core/src/compiler/Linear.cc
new file mode 100644
index 000000000..30c8f72a5
--- /dev/null
+++ b/runtime/onert/core/src/compiler/Linear.cc
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+
+#include "Linear.h"
+
+#include "backend/IConfig.h"
+#include "backend/IConstantInitializer.h"
+#include "backend/ITensorRegister.h"
+#include "backend/Backend.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+std::vector<ir::OpSequenceIndex> Linear::linearize(const compiler::LoweredGraph &lowered_graph)
+{
+ std::vector<ir::OpSequenceIndex> order;
+ lowered_graph.iterateTopolOpSeqs(
+ [&](const ir::OpSequenceIndex &index, const ir::OpSequence &) -> void {
+ order.emplace_back(index);
+ });
+ return order;
+}
+
+void Linear::dump(const compiler::LoweredGraph &lowered_graph,
+ const std::vector<ir::OpSequenceIndex> &order)
+{
+ {
+ const auto &toString = [](const onert::backend::Backend *backend) {
+ assert(backend);
+ std::string str;
+ str += backend->config()->id();
+ return "{" + str + "}";
+ };
+
+ VERBOSE(Linear) << "Final OpSequence" << std::endl;
+ for (const auto index : order)
+ {
+ const auto &op_seq = lowered_graph.op_seqs().at(index);
+ const auto lower_info = lowered_graph.getLowerInfo(index);
+ const auto &operations = lowered_graph.graph().operations();
+ VERBOSE(Linear) << "* OP_SEQ " << toString(lower_info->backend()) << " "
+ << ir::getStrFromOpSeq(op_seq, operations) << std::endl;
+ }
+ }
+}
+
+void Linear::planTensors(const compiler::LoweredGraph &lowered_graph,
+ const std::vector<ir::OpSequenceIndex> &order)
+{
+ const auto &graph = lowered_graph.graph();
+ ir::OperandIndexMap<std::shared_ptr<backend::ITensorBuilder>> tensor_builder_map;
+
+ ir::OperandIndexMap<uint32_t> uses_map;
+ ir::OperandIndexMap<uint32_t> def_map;
+ ir::OperandIndexSequence constants;
+
+ // Prepare scanning
+ graph.operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) {
+ const auto lower_info = lowered_graph.getLowerInfo(ind);
+ // TODO Remove if onert doesn't support anymore such as
+ // GeneratedTests.reshape_quant8_weights_as_inputs
+ if (lower_info->def_factors().size() == 0 && lower_info->use_factors().size() == 0 &&
+ !graph.getInputs().contains(ind))
+ {
+ VERBOSE(LINEAR) << "Operand #" << ind.value() << " will not be used. no more process."
+ << std::endl;
+ return;
+ }
+
+ // Unused input of subgraph
+ // TODO Register unused input as nullptr in tensor_builder
+ if (lower_info->def_factors().size() == 0 && lower_info->use_factors().size() == 0 &&
+ graph.getInputs().contains(ind))
+ {
+ VERBOSE(LINEAR) << "Operand #" << ind.value() << " will not be used. no more process."
+ << std::endl;
+ return;
+ }
+
+ uses_map[ind] = obj.getUses().size();
+ def_map[ind] = obj.getDef().valid() ? 1 : 0;
+
+ bool is_const = obj.isConstant();
+ if (is_const)
+ {
+ constants.append(ind);
+ }
+
+ auto factor = lower_info->def_factors().getOnlyElement();
+ auto backend = factor.backend();
+ auto tensor_builder = lowered_graph.backend_contexts().at(backend)->tensor_builder;
+ if (!tensor_builder->isRegistered(ind))
+ {
+ // These tensors do not exist in any op_seq (No use and def)
+ const auto info = obj.info();
+ const auto backend_layout = factor.layout();
+ // TODO Change tensor info to have permuted shape
+ tensor_builder->registerTensorInfo(ind, info, backend_layout);
+ }
+
+ tensor_builder_map[ind] = tensor_builder;
+ });
+
+ const auto io_tensors =
+ (graph.getInputs() + graph.getOutputs()) | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED;
+
+ // If a tensor is model output, increase the use of the tensor.
+ // This aim is same to above one.
+ for (const auto &ind : io_tensors)
+ {
+ uses_map[ind]++;
+ }
+
+ // Start scanning to do notify{First|Last}Use for each tensor
+
+ // If a tensor is a constant, increase the use of the tensor.
+ // It makes the tensor not be dealloced. It means these will be deallocated last.
+ // And allocate constant operands first
+ VERBOSE(LINEAR) << "TENSORS as CONSTANT" << std::endl;
+ for (const auto &ind : constants)
+ {
+ uses_map[ind]++;
+ tensor_builder_map[ind]->notifyFirstUse(ind);
+ }
+
+ // Allocate Model's inputs
+ VERBOSE(LINEAR) << "TENSORS as MODEL INPUT" << std::endl;
+ for (const auto &ind : graph.getInputs() | ir::Remove::DUPLICATED)
+ {
+ auto tensor_builder = tensor_builder_map[ind];
+ if (!tensor_builder) // for GeneratedTests.xxx_weights_as_inputs
+ continue;
+ tensor_builder->notifyFirstUse(ind);
+ }
+
+ // At each operation,
+ // 1. Scan DEF of outputs. If the DEF, allocate it
+ // 2. Scan DEF of inputs. If variable tensor, allocate it
+ // 3. Scan USE of inputs. Decrease the USE and deallocate if the USE is 0
+ VERBOSE(LINEAR) << "TENSORS" << std::endl;
+ for (const auto op_seq_ind : order)
+ {
+ const auto &op_seq = lowered_graph.op_seqs().at(op_seq_ind);
+ for (const auto &op_idx : op_seq.operations())
+ {
+ for (const auto &ind : graph.operations().at(op_idx).getOutputs() | ir::Remove::DUPLICATED |
+ ir::Remove::UNDEFINED)
+ {
+ assert(def_map.find(ind) != def_map.end());
+ if (def_map[ind])
+ {
+ def_map[ind] = 0;
+ tensor_builder_map[ind]->notifyFirstUse(ind);
+ }
+ }
+
+ // Scan variable tensors
+ // This tensor has features like constant. But OperandInfo and LowerInfo treat them as
+ // non-constant because of less memory usage by memory planning in here
+ for (const auto &ind : graph.operations().at(op_idx).getInputs() | ir::Remove::DUPLICATED |
+ ir::Remove::UNDEFINED)
+ {
+ const auto &operand = graph.operands().at(ind);
+ if (operand.info().isVariable())
+ {
+ // The variable tensor with buffer is not supported yet
+ assert(operand.data() == nullptr);
+ assert(operand.getUses().size() == 1 && !operand.getDef().valid());
+ assert(lowered_graph.getLowerInfo(ind)->def_factors().size() == 1 &&
+ lowered_graph.getLowerInfo(ind)->use_factors().size() == 1);
+ assert(uses_map[ind] == 1 && def_map[ind] == 0);
+ tensor_builder_map[ind]->notifyFirstUse(ind);
+ }
+ }
+
+ for (const auto &ind : graph.operations().at(op_idx).getInputs() | ir::Remove::DUPLICATED |
+ ir::Remove::UNDEFINED)
+ {
+ assert(uses_map.find(ind) != uses_map.end());
+ assert(uses_map[ind] > 0);
+ uses_map[ind]--;
+ if (uses_map[ind] == 0)
+ {
+ // plan for deallocation of static tensornode
+ tensor_builder_map[ind]->notifyLastUse(ind);
+
+ // plan for deallocation of dynamic tensor
+ auto dyn_tensor_manager = tensor_builder_map[ind]->dynamicTensorManager();
+ if (dyn_tensor_manager)
+ {
+ const auto *backend =
+ lowered_graph.getLowerInfo(ind)->def_factors().getOnlyElement().backend();
+ auto &tensor_registry = lowered_graph.backend_contexts().at(backend)->tensor_registry;
+ auto *tensor = tensor_registry->getITensor(ind);
+ assert(tensor);
+ if (!io_tensors.contains(ind)) // I/O tensors cannot be deallocated
+ dyn_tensor_manager->planDealloc(op_idx, tensor);
+ }
+ }
+ }
+ }
+ }
+
+ // Dispose and validate
+ for (const auto &ind : io_tensors)
+ {
+ --uses_map[ind];
+ if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice
+ {
+ tensor_builder_map[ind]->notifyLastUse(ind);
+ }
+ }
+
+ for (const auto &ind : constants)
+ {
+ --uses_map[ind];
+ if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice
+ {
+ tensor_builder_map[ind]->notifyLastUse(ind);
+ }
+ }
+
+ assert(
+ std::all_of(uses_map.begin(), uses_map.end(),
+ [](std::pair<const ir::OperandIndex, uint32_t> it) { return it.second == 0; }));
+
+ assert(
+ std::all_of(def_map.begin(), def_map.end(),
+ [](std::pair<const ir::OperandIndex, uint32_t> it) { return it.second == 0; }));
+}
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/Linear.h b/runtime/onert/core/src/compiler/Linear.h
new file mode 100644
index 000000000..1e24cf92b
--- /dev/null
+++ b/runtime/onert/core/src/compiler/Linear.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_LINEAR_H__
+#define __ONERT_COMPILER_LINEAR_H__
+
+#include <vector>
+#include <memory>
+
+#include "ir/OpSequences.h"
+#include "ir/Index.h"
+#include "backend/ITensorBuilder.h"
+#include "compiler/LoweredGraph.h"
+
+namespace onert
+{
+namespace ir
+{
+struct OperationVisitor;
+} // namespace ir
+} // namespace onert
+
+namespace onert
+{
+namespace compiler
+{
+
+class Linear
+{
+public:
+ static std::vector<ir::OpSequenceIndex> linearize(const compiler::LoweredGraph &lowered_graph);
+ static void dump(const compiler::LoweredGraph &lowered_graph,
+ const std::vector<ir::OpSequenceIndex> &order);
+ static void planTensors(const compiler::LoweredGraph &lowered_graph,
+ const std::vector<ir::OpSequenceIndex> &order);
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_LINEAR_H__
diff --git a/runtime/onert/core/src/compiler/LoweredGraph.cc b/runtime/onert/core/src/compiler/LoweredGraph.cc
new file mode 100644
index 000000000..673d7d3e8
--- /dev/null
+++ b/runtime/onert/core/src/compiler/LoweredGraph.cc
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/LoweredGraph.h"
+
+#include <assert.h>
+#include <sstream>
+#include "util/logging.h"
+#include "compiler/pass/ConstantInsertionPass.h"
+#include "compiler/pass/ConstantLoweringPass.h"
+#include "compiler/pass/PassRunner.h"
+#include "compiler/pass/PermutationOperationPass.h"
+#include "compiler/pass/PermutationInsertionPass.h"
+#include "compiler/pass/PermutationEliminationPass.h"
+#include "ir/GraphIterator.h"
+#include "ir/verifier/Verifier.h"
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+#include "compiler/BackendResolver.h"
+#include "compiler/ManualScheduler.h"
+#include "compiler/HEScheduler.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+LoweredGraph::LoweredGraph(const ir::Graph &graph, const CompilerOptions &options) : _graph{graph}
+{
+ bool linear_executor = (options.executor == "Linear");
+
+ // Build backend contexts
+ auto &backend_manager = BackendManager::get();
+
+ // Always create Controlflow backend context
+ auto cf_backend = backend_manager.getControlflow();
+ _backend_contexts.emplace(
+ cf_backend, cf_backend->newContext(_graph, _graph.getKernelBuilder(), linear_executor));
+
+ // Create contexts for other backends
+ for (auto backend_str : options.backend_list)
+ {
+ backend_manager.loadBackend(backend_str);
+ auto backend = backend_manager.get(backend_str);
+
+ // TODO As the default value of backend list contains "cpu", "acl_cl" and "acl_neon", and some
+ // are not available on x64 or some other platforms. So this may be a workaround for x64 and
+ // we should change it back(throw if backend is not loaded) later.
+ if (!backend)
+ {
+ VERBOSE(LoweredGraph) << "Cannot load backend - " << backend_str << std::endl;
+ continue;
+ }
+
+ _backend_contexts.emplace(
+ backend, backend->newContext(_graph, _graph.getKernelBuilder(), linear_executor));
+ }
+ if (backend_manager.num_backends() == 0)
+ throw std::runtime_error{"No available backends loaded."};
+
+ // TODO Move "schedule" phase out of here
+ // Schedule
+ std::unique_ptr<BackendResolver> backend_resolver;
+ if (options.he_scheduler)
+ {
+ auto scheduler = HEScheduler(_backend_contexts, options);
+ backend_resolver = scheduler.schedule(_graph);
+ _indexed_ranks = scheduler.getIndexedRanks();
+ }
+ else
+ {
+ auto scheduler = ManualScheduler(_backend_contexts, options);
+ backend_resolver = scheduler.schedule(_graph);
+ }
+
+ {
+ // operand::LowerInfo holder
+ ir::OperandIndexMap<std::unique_ptr<ir::operand::LowerInfo>> operands_lower_info;
+
+ _graph.operands().iterate([&](const ir::OperandIndex &index, const ir::Operand &) {
+ operands_lower_info[index] = std::make_unique<ir::operand::LowerInfo>();
+ });
+
+ // Make op_seqs while checking whether a node can be merged into a op_seq.
+ makeOpSequences(operands_lower_info, options, *backend_resolver);
+
+ _op_seqs.iterate([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ assert(op_seq.operations().size() > 0);
+ std::reverse(std::begin(op_seq.operations()), std::end(op_seq.operations()));
+ });
+
+ VERBOSE(OpSequences) << "dump before permutation insertion" << std::endl;
+ dumpOpSequences(_op_seqs, _graph.operations());
+
+ // Mandatory passes
+ pass::PassRunner{}
+ .append(std::make_unique<pass::ConstantInsertionPass>(*this))
+ .append(std::make_unique<pass::ConstantLoweringPass>(*this))
+ .run();
+
+ // Set LowerInfo for each operand from the operand::LowerInfo holder
+ manipulateLowerInfo(operands_lower_info, options.is_primary_subgraph);
+
+ dumpLowerInfo();
+ }
+
+ // Mandatory passes
+ pass::PassRunner{}
+ .append(std::make_unique<pass::PermutationOperationPass>(*this))
+ .append(std::make_unique<pass::PermutationInsertionPass>(*this))
+ .run();
+
+ // Optimization passes
+ pass::PassRunner{}.append(std::make_unique<pass::PermutationEliminationPass>(*this)).run();
+
+ VERBOSE(OpSequences) << "Dump after permutation insertion" << std::endl;
+ dumpOpSequences(_op_seqs, _graph.operations());
+
+ // Graph verifications
+ {
+ assert(ir::verifier::InputOutputChecker().verify(_graph));
+ assert(ir::verifier::DAGChecker().verify(_graph));
+ assert(ir::verifier::EdgeConsistencyChecker().verify(_graph));
+ }
+}
+
+const ir::operation::LowerInfo *
+LoweredGraph::getLowerInfo(const ir::OpSequenceIndex &op_seq_index) const
+{
+ auto itr = _lower_info_map.op_seq.find(op_seq_index);
+ if (itr == _lower_info_map.op_seq.end())
+ return nullptr;
+ return itr->second.get();
+}
+
+void LoweredGraph::setLowerInfo(const ir::OpSequenceIndex &op_seq_index,
+ std::unique_ptr<ir::operation::LowerInfo> &&lower_info)
+{
+ _lower_info_map.op_seq.insert(std::make_pair(op_seq_index, std::move(lower_info)));
+}
+
+void LoweredGraph::removeLowerInfo(const ir::OpSequenceIndex &op_seq_index)
+{
+ auto &op_seq_lower_info = _lower_info_map.op_seq;
+ assert(op_seq_lower_info.find(op_seq_index) != op_seq_lower_info.end());
+ for (auto it = op_seq_lower_info.begin(); it != op_seq_lower_info.end(); ++it)
+ {
+ if (it->first == op_seq_index)
+ {
+ op_seq_lower_info.erase(it);
+ break;
+ }
+ }
+}
+
+const ir::operand::LowerInfo *LoweredGraph::getLowerInfo(const ir::OperandIndex &index) const
+{
+ auto itr = _lower_info_map.operand.find(index);
+ if (itr == _lower_info_map.operand.end())
+ return nullptr;
+ return itr->second.get();
+}
+
+ir::operand::LowerInfo *LoweredGraph::getLowerInfo(const ir::OperandIndex &index)
+{
+ auto itr = _lower_info_map.operand.find(index);
+ if (itr == _lower_info_map.operand.end())
+ return nullptr;
+ return itr->second.get();
+}
+
+void LoweredGraph::setLowerInfo(const ir::OperandIndex &index,
+ std::unique_ptr<ir::operand::LowerInfo> &&lower_info)
+{
+ _lower_info_map.operand.insert(std::make_pair(index, std::move(lower_info)));
+}
+
+void LoweredGraph::removeLowerInfo(const ir::OperandIndex &index)
+{
+ _lower_info_map.operand.erase(index);
+}
+
+void LoweredGraph::iterateTopolOpSeqs(
+ const std::function<void(const ir::OpSequenceIndex &, const ir::OpSequence &)> &fn) const
+{
+ // Topological Sorting for ir::OpSequences
+ std::vector<ir::OpSequenceIndex> topol_sorted;
+ ir::PostDfsIterator<true>{}.iterateOpSeqs(
+ *this, [&](const ir::OpSequenceIndex &index, const ir::OpSequence &) {
+ topol_sorted.emplace_back(index);
+ });
+ std::reverse(topol_sorted.begin(), topol_sorted.end());
+ for (const auto op_seq_idx : topol_sorted)
+ {
+ const auto &op_seq = _op_seqs.at(op_seq_idx);
+ fn(op_seq_idx, op_seq);
+ }
+}
+
+void LoweredGraph::iterateTopolOpSeqs(
+ const std::function<void(const ir::OpSequenceIndex &, ir::OpSequence &)> &fn)
+{
+ // Topological Sorting for ir::OpSequences
+ std::vector<ir::OpSequenceIndex> topol_sorted;
+ ir::PostDfsIterator<false>{}.iterateOpSeqs(
+ *this, [&](const ir::OpSequenceIndex &index, ir::OpSequence &) {
+ topol_sorted.emplace_back(index);
+ });
+ std::reverse(topol_sorted.begin(), topol_sorted.end());
+ for (const auto op_seq_idx : topol_sorted)
+ {
+ auto &op_seq = _op_seqs.at(op_seq_idx);
+ fn(op_seq_idx, op_seq);
+ }
+}
+
+ir::OpSequenceIndex LoweredGraph::appendFreshSingleOpSequence(const ir::OperationIndex &node_index,
+ const ir::Operation &node)
+{
+ // Create a fresh op_seq with one operation, and append it to op_seqs
+ // Create a fresh op_seq
+ auto op_seq = std::make_unique<ir::OpSequence>(_graph.layout());
+
+ // Add an operation
+ op_seq->appendOperation(node_index);
+
+ // Update input/output
+ op_seq->setOutputs(node.getOutputs());
+ op_seq->setInputs(node.getInputs());
+
+ return _op_seqs.emplace(std::move(op_seq));
+}
+
+void LoweredGraph::makeOpSequences(
+ ir::OperandIndexMap<std::unique_ptr<ir::operand::LowerInfo>> &operands_lower_info,
+ const CompilerOptions &options, const BackendResolver &backend_resolver)
+{
+ // if SUBG_MAX_NODE == 0, no limit on nodes of a op_seq
+ const int op_seq_max_node = options.op_seq_max_node;
+ assert(op_seq_max_node >= 0);
+
+ bool is_profiling = options.he_profiling_mode;
+ ir::OpSequence *op_seq = nullptr;
+ ir::OpSequenceIndex op_seq_index;
+
+ // NOTE: The below method appends nodes while making one op_seq if needed. If something better
+ // ways, happy to update this code.
+ ir::PostDfsConstIterator{}.iterate(
+ _graph, [&](const ir::OperationIndex &node_index, const ir::Operation &node) {
+ // LowerInfo for in/output operands
+ auto backend = backend_resolver.getBackend(node_index);
+
+ // Get frontend's layout
+ auto frontend_layout = _graph.layout();
+
+ // The layout of each backend should be set at another place
+ // TODO Change setting layout of each backend at another place
+ auto backend_layout = backend->config()->supportLayout(node, frontend_layout);
+
+ for (auto operand : node.getInputs() | ir::Remove::UNDEFINED)
+ {
+ auto &&lower_info = operands_lower_info.at(operand);
+ lower_info->addUsePermuteFactor(ir::operand::PermuteFactor{backend, backend_layout});
+ }
+ for (auto operand : node.getOutputs() | ir::Remove::UNDEFINED)
+ {
+ auto &&lower_info = operands_lower_info.at(operand);
+ lower_info->addDefPermuteFactor(ir::operand::PermuteFactor{backend, backend_layout});
+ }
+
+ bool new_op_seq = (op_seq == nullptr ||
+ (op_seq_max_node != 0 &&
+ op_seq->operations().size() >= static_cast<size_t>(op_seq_max_node)));
+
+ // for profiling each op_seq must contain just one node,
+ // so that we can measure a node separately
+ if (new_op_seq || is_profiling ||
+ !mergeable(op_seq_index, node_index, backend_layout, backend_resolver))
+ {
+ auto new_op_seq_index = appendFreshSingleOpSequence(node_index, node);
+
+ // ir::OpSequence LowerInfo
+ setLowerInfo(new_op_seq_index,
+ std::make_unique<ir::operation::LowerInfo>(backend, backend_layout));
+
+ op_seq_index = new_op_seq_index;
+ op_seq = &(_op_seqs.at(new_op_seq_index));
+
+ VERBOSE(Lower) << "OpSequence#" << op_seq_index.value() << " is created for "
+ << "NODE#" << node_index.value() << "(" << node.name() << ")" << std::endl;
+ }
+ else
+ {
+ op_seq->appendOperation(node_index);
+ // Set inputs
+ auto new_inputs = node.getInputs();
+ // Add inputs except outputs of the previous node
+ for (auto ind : op_seq->getInputs())
+ {
+ if (!node.getOutputs().contains(ind))
+ new_inputs.append(ind);
+ }
+ op_seq->setInputs(new_inputs);
+
+ VERBOSE(Lower) << "OpSequence#" << op_seq_index.value() << " merges "
+ << "NODE#" << node_index.value() << "(" << node.name() << ")" << std::endl;
+ }
+ });
+}
+
+void LoweredGraph::manipulateLowerInfo(
+ ir::OperandIndexMap<std::unique_ptr<ir::operand::LowerInfo>> &operands_lower_info,
+ bool is_primary)
+{
+ const auto controlflow_backend = BackendManager::get().getControlflow();
+
+ // TODO Rather than handling primary graph specially,
+ // let the permute inserted and remove it later
+ if (is_primary)
+ {
+ // TODO Rather than using NHWC Get frontend layout of this node from IR
+ auto factor = ir::operand::PermuteFactor{controlflow_backend, ir::Layout::NHWC};
+ for (auto index : _graph.getInputs() | ir::Remove::UNDEFINED)
+ {
+ auto &&lower_info = operands_lower_info.at(index);
+ assert(lower_info->def_factors().empty());
+ lower_info->addDefPermuteFactor(factor);
+ }
+ for (auto index : _graph.getOutputs() | ir::Remove::UNDEFINED)
+ {
+ auto &&lower_info = operands_lower_info.at(index);
+ lower_info->addUsePermuteFactor(factor);
+ }
+ }
+ else
+ {
+ for (auto index : _graph.getInputs() | ir::Remove::UNDEFINED)
+ {
+ auto &&lower_info = operands_lower_info.at(index);
+ if (!(lower_info->def_factors().size() == 0 && lower_info->use_factors().size() == 0))
+ {
+ // In case of not that Graph's input is not used in any operation and not the graph's
+ // output.
+ // In other words, it is not unused input in Graph.
+ lower_info->addDefPermuteFactor(*lower_info->use_factors().begin());
+ }
+ else
+ {
+ // In case of that an operand is Graph's input and not input or output of any operation
+ lower_info->addDefPermuteFactor(ir::operand::PermuteFactor{
+ controlflow_backend,
+ ir::Layout::NHWC // TODO Get frontend layout of this node from IR
+ });
+ }
+ }
+ }
+ for (auto index : _graph.getOutputs() | ir::Remove::UNDEFINED)
+ {
+ auto &&lower_info = operands_lower_info.at(index);
+ if (lower_info->def_factors().size() == 0)
+ {
+ // In case of that an operand is Graph's output and not input or output of any operation
+ lower_info->addDefPermuteFactor(ir::operand::PermuteFactor{
+ controlflow_backend,
+ ir::Layout::NHWC // TODO Get frontend layout of this node from IR
+ });
+ }
+ }
+
+ // 1. Add def of variable operand
+ // 2. Set LowerInfo for each operand from the operand::LowerInfo holder
+ _graph.operands().iterate([&](const ir::OperandIndex &index, ir::Operand &operand) {
+ // Some inputs of an operation could be non-constant, but not existed in graph inputs/outputs
+ // and not undefined operand. Those inputs must have exist as a Tensor. For example,
+ // UnidirectionalSequenceLSTM operation could have state inputs such as it.
+ if (operand.info().isVariable())
+ {
+ // The variable operand with buffer is not supported yet
+ assert(operand.data() == nullptr);
+ assert(operand.getUses().size() == 1 && !operand.getDef().valid());
+ auto &lowered_info = operands_lower_info[index];
+ assert(lowered_info->def_factors().empty());
+ lowered_info->addDefPermuteFactor(lowered_info->use_factors().getOnlyElement());
+ }
+
+ setLowerInfo(index, std::move(operands_lower_info[index]));
+ });
+}
+
+void LoweredGraph::dumpLowerInfo()
+{
+ if (::onert::util::logging::ctx.enabled() == false)
+ return;
+
+ std::map<uint32_t, std::string> dumps;
+
+ _graph.operands().iterate([&](const ir::OperandIndex &index, ir::Operand &object) {
+ std::stringstream sstream;
+ if (!getLowerInfo(index)->def_factors().empty() || !getLowerInfo(index)->use_factors().empty())
+ {
+ auto factors_to_string = [](const ir::operand::PermuteFactorSet &factors) {
+ std::string str;
+ for (auto factor : factors)
+ {
+ str += factor.backend()->config()->id();
+ str += "(" + to_string(factor.layout()) + ")";
+ str += " ";
+ }
+ return "{ " + str + "}";
+ };
+
+ auto operation_index_to_string = [](const ir::OperationIndexSet &operations) {
+ std::string str;
+ for (auto op : operations)
+ {
+ str += std::to_string(op.value());
+ str += " ";
+ }
+ return "{ " + str + "}";
+ };
+
+ const auto lower_info = getLowerInfo(index);
+ const auto &shape = object.shape();
+ std::string def_ops =
+ object.getDef().valid() ? std::to_string(object.getDef().value()) : "N/A";
+ std::string use_ops = operation_index_to_string(object.getUses());
+ std::string def_layouts = factors_to_string(lower_info->def_factors());
+ std::string use_layouts = factors_to_string(lower_info->use_factors());
+ sstream << "Operand #" << index.value() << " LowerInfo" << std::endl;
+ sstream << " - Shape : { ";
+ for (auto i = 0; i < shape.rank(); ++i)
+ {
+ sstream << (shape.dim(i)) << " ";
+ }
+ sstream << "}" << std::endl;
+ sstream << " - Def ir::Operations : " << def_ops << std::endl;
+ sstream << " - Use ir::Operations : " << use_ops << std::endl;
+ sstream << " - Lower Info" << std::endl;
+ sstream << " - Def Backends : " << def_layouts << std::endl;
+ sstream << " - Use Backends : " << use_layouts << std::endl;
+ }
+ dumps.emplace(index.value(), sstream.str());
+ });
+
+ for (const auto &e : dumps)
+ {
+ if (!e.second.empty())
+ {
+ VERBOSE(Lower) << e.second;
+ }
+ }
+}
+
+bool LoweredGraph::mergeable(const ir::OpSequenceIndex &op_seq_index,
+ const ir::OperationIndex &node_index, ir::Layout layout,
+ const BackendResolver &backend_resolver)
+{
+ // Are they mergeable?
+ // 1. the same backend id and layout?
+ // 2. Is op_seq or node branched?
+ // 3. if 1 is true, the op_seq and a node are connected?
+ const auto &op_seq = _op_seqs.at(op_seq_index);
+ const auto &node = _graph.operations().at(node_index);
+
+ // The same backend id and layout?
+ {
+ const auto op_seq_backend_layout = getLowerInfo(op_seq_index)->layout();
+ const auto &op_seq_backend_id = getLowerInfo(op_seq_index)->backend()->config()->id();
+ const auto &node_backend_id = backend_resolver.getBackend(node_index)->config()->id();
+ VERBOSE(Lower) << "OpSequence#" << op_seq_index.value() << " { " << op_seq_backend_id << "("
+ << to_string(op_seq_backend_layout) << ") } "
+ << " NODE#" << node_index.value() << " (" << node.name() << ") { "
+ << node_backend_id << "(" << to_string(layout) << ") } " << std::endl;
+ if (op_seq_backend_id != node_backend_id || op_seq_backend_layout != layout)
+ return false;
+ }
+
+ // Branched?
+ {
+ std::unordered_set<ir::OperationIndex> branched_set;
+
+ // Check for branching up
+ for (const auto &input : op_seq.getInputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ const auto &input_obj = _graph.operands().at(input);
+ auto def = input_obj.getDef();
+ if (def.valid())
+ {
+ branched_set.insert(def);
+ if (branched_set.size() > 1)
+ {
+ return false;
+ }
+ }
+ }
+ branched_set.clear();
+
+ // Check for branching down
+ for (const auto &output : node.getOutputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ // TODO Fix this workaround for the case of model outputs that are used by another operation
+ // This is needed since the branching is decided by operation, but for model outputs,
+ // there is controlflow backen(use backend) but no actual use operation exists
+ if (_graph.getOutputs().contains(output))
+ return false;
+
+ const auto &output_obj = _graph.operands().at(output);
+ for (const auto &use : output_obj.getUses())
+ {
+ branched_set.insert(use);
+ if (branched_set.size() > 1)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Connected?
+ // an input of one node is an output of the other node? or vice-versa?
+ {
+ const auto &node_inputs = node.getInputs();
+ const auto &node_outputs = node.getOutputs();
+
+ // op_seq's operations are in order so that we just check the first and the last
+ std::vector<ir::OperationIndex> op_seq_ops{op_seq.operations()[0]};
+ if (op_seq.operations().size() > 1)
+ op_seq_ops.emplace_back(op_seq.operations()[op_seq.operations().size() - 1]);
+
+ for (const auto &n_index : op_seq_ops)
+ {
+ const auto &n = _graph.operations().at(n_index);
+
+ // node's output == op_seq's input?
+ for (const auto input : n.getInputs() | ir::Remove::UNDEFINED)
+ {
+ if (node_outputs.contains(input))
+ {
+ VERBOSE(Lower) << "OpSequence#" << op_seq_index.value() << " 's NODE#" << n_index.value()
+ << "(" << n.name() << ") is connected to NODE#" << node_index.value()
+ << "(" << node.name() << ")" << std::endl;
+ return true;
+ }
+ }
+
+ // node's input == op_seq's output?
+ for (const auto output : n.getOutputs() | ir::Remove::UNDEFINED)
+ {
+ if (node_inputs.contains(output))
+ {
+ VERBOSE(Lower) << "OpSequence#" << op_seq_index.value() << " 's NODE#" << n_index.value()
+ << " (" << n.name() << ") is connected to NODE#" << node_index.value()
+ << std::endl;
+ return true;
+ }
+ }
+ }
+
+ VERBOSE(Lower) << "OpSequence#" << op_seq_index.value() << " is not connected to NODE#"
+ << node_index.value() << "(" << node.name() << ")" << std::endl;
+ }
+
+ return false;
+}
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/ManualScheduler.cc b/runtime/onert/core/src/compiler/ManualScheduler.cc
new file mode 100644
index 000000000..ed49ee56f
--- /dev/null
+++ b/runtime/onert/core/src/compiler/ManualScheduler.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ManualScheduler.h"
+#include "ir/OpCode.h"
+#include "ir/Operations.Include.h"
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+#include "compiler/BackendManager.h"
+#include "util/ConfigSource.h"
+#include "util/logging.h"
+#include "misc/string_helpers.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+ManualScheduler::ManualScheduler(const backend::BackendContexts &backend_contexts,
+ const compiler::CompilerOptions &options)
+ : _backend_contexts{backend_contexts}, _options{options}
+{
+}
+
+std::unique_ptr<BackendResolver> ManualScheduler::schedule(const ir::Graph &graph)
+{
+ const auto &manual_options = _options.manual_scheduler_options;
+ auto backend_resolver = std::make_unique<compiler::BackendResolver>();
+
+ // This fallback will be used in case that `backend_for_all` is unavailable
+ auto fallback = [&]() -> const backend::Backend * {
+ for (auto backend_id : _options.backend_list)
+ {
+ auto backend = resolveBackend(backend_id);
+ if (backend)
+ return backend;
+ }
+ return nullptr;
+ }();
+ if (fallback == nullptr)
+ throw std::runtime_error{"No loaded backends available."};
+
+ // 1. Backend for All operations
+ const backend::Backend *backend_all = resolveBackend(manual_options.backend_for_all, fallback);
+ VERBOSE(ManualScheduler) << "Default backend for all ops: " << backend_all->config()->id()
+ << std::endl;
+
+ graph.operations().iterate([&](const ir::OperationIndex &index, const ir::Operation &) {
+ backend_resolver->setBackend(index, backend_all);
+ });
+
+ // 2. Backend per operation type
+ std::unordered_map<ir::OpCode, backend::Backend *> op_type_map;
+ for (auto &pair : manual_options.opcode_to_backend)
+ {
+ op_type_map.emplace(pair.first, BackendManager::get().get(pair.second));
+ }
+ // By default, Custom uses cpu backend
+ op_type_map[ir::OpCode::Custom] = BackendManager::get().get("cpu");
+
+ graph.operations().iterate([&](const ir::OperationIndex &index, const ir::Operation &operation) {
+ auto itr = op_type_map.find(operation.opcode());
+ if (itr != op_type_map.end())
+ {
+ backend_resolver->setBackend(index, itr->second);
+ }
+ });
+
+ // 3. Backend per operation
+ for (auto &pair : manual_options.index_to_backend)
+ {
+ const auto &key = pair.first;
+ const auto &val = pair.second;
+
+ try
+ {
+ graph.operations().at(key); // Check if exist, or this will throw
+ backend_resolver->setBackend(
+ key, BackendManager::get().get(
+ val)); // TODO Ensure this backend is available in backend contexts
+ }
+ catch (...)
+ {
+ VERBOSE(ManualScheduler) << "Invalid value while OperationIndex to Backend mapping : @"
+ << key.value() << " -> \"" << val << "\"" << std::endl;
+ }
+ }
+
+ // Dump final assignment
+ backend_resolver->iterate([&](const ir::OperationIndex &index, const backend::Backend &backend) {
+ VERBOSE(ManualScheduler) << "backend for operation #" << index.value() << ": "
+ << backend.config()->id() << std::endl;
+ });
+
+ return backend_resolver;
+}
+
+const backend::Backend *ManualScheduler::resolveBackend(const std::string &id,
+ const backend::Backend *fallback)
+{
+ // Ensure if the backend is available in the current backend context
+ const backend::Backend *backend = BackendManager::get().get(id);
+ if (!backend || _backend_contexts.find(backend) == _backend_contexts.end())
+ {
+ backend = fallback;
+ }
+ return backend;
+}
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/ManualScheduler.h b/runtime/onert/core/src/compiler/ManualScheduler.h
new file mode 100644
index 000000000..41503f7ff
--- /dev/null
+++ b/runtime/onert/core/src/compiler/ManualScheduler.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_CORE_COMPILER_MANUAL_SCHEDULER_H__
+#define __ONERT_CORE_COMPILER_MANUAL_SCHEDULER_H__
+
+#include "IScheduler.h"
+#include "compiler/Compiler.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+class ManualScheduler : public IScheduler
+{
+public:
+ ManualScheduler(const backend::BackendContexts &backend_contexts,
+ const compiler::CompilerOptions &options);
+ std::unique_ptr<BackendResolver> schedule(const ir::Graph &graph) override;
+
+private:
+ const backend::Backend *resolveBackend(const std::string &id,
+ const backend::Backend *fallback = nullptr);
+
+private:
+ const backend::BackendContexts &_backend_contexts;
+ compiler::CompilerOptions _options;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_CORE_COMPILER_MANUAL_SCHEDULER_H__
diff --git a/runtime/onert/core/src/compiler/ParamChecker.cc b/runtime/onert/core/src/compiler/ParamChecker.cc
new file mode 100644
index 000000000..c4f80f087
--- /dev/null
+++ b/runtime/onert/core/src/compiler/ParamChecker.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ParamChecker.h"
+
+#include "ir/Graph.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+void ParamChecker::operator()()
+{
+ _model->operations().iterate(
+ [&](const ir::OperationIndex &, const ir::Operation &node) { node.accept(*this); });
+}
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/ParamChecker.h b/runtime/onert/core/src/compiler/ParamChecker.h
new file mode 100644
index 000000000..61429d521
--- /dev/null
+++ b/runtime/onert/core/src/compiler/ParamChecker.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ParamChecker.h
+ * @brief This file contains ParamChecker to check\n
+ * operations' parameters are compilable at machine independent phase\n
+ * ex) Check param is constant
+ */
+#ifndef __ONERT_COMPILER_PARAM_CHECKER_H__
+#define __ONERT_COMPILER_PARAM_CHECKER_H__
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+class Graph;
+} // namespace ir
+} // namespace onert
+
+namespace onert
+{
+namespace compiler
+{
+
+class ParamChecker : public ir::OperationVisitor
+{
+public:
+ /**
+ * @brief Construct a new Param Checker object (deleted)
+ */
+ ParamChecker(void) = delete;
+ /**
+ * @brief Construct a new Param Checker object
+ * @param[in] model Graph model to check
+ */
+ ParamChecker(std::shared_ptr<ir::Graph> model) : _model{model} {}
+
+public:
+ /**
+ * @brief Run parameter analysis
+ */
+ void operator()();
+ /**
+ * @brief Return analysis result if model have non-const parameter
+ * @return @c true if there is non-const parameter, otherwise @c false
+ */
+ bool haveNoneConstParam(void) { return _nonConstParam; }
+
+private:
+ const std::shared_ptr<ir::Graph> _model;
+ bool _nonConstParam{false};
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_OPERATION_VALIDATOR_H__
diff --git a/runtime/onert/core/src/compiler/ShapeValidator.cc b/runtime/onert/core/src/compiler/ShapeValidator.cc
new file mode 100644
index 000000000..c18178da9
--- /dev/null
+++ b/runtime/onert/core/src/compiler/ShapeValidator.cc
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ShapeValidator.h"
+
+#include <typeinfo>
+
+#include "ir/Graph.h"
+#include "ir/operation/LowerInfo.h"
+
+#include "util/logging.h"
+#include "util/Utils.h"
+
+#define OP_REQUIRES(EXP) \
+ do \
+ { \
+ if (!(EXP)) \
+ throw std::runtime_error("ShapeValidator failed at line " + std::to_string(__LINE__)); \
+ } while (0)
+
+namespace onert
+{
+namespace compiler
+{
+
+ShapeValidator::ShapeValidator(const ir::Graph &graph)
+ : _graph{graph}, _ctx{graph.operands()}, _current_op_seq_layout{ir::Layout::UNKNOWN}
+{
+}
+
+void ShapeValidator::checkUnaryOp(const ir::Operation &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ // Check if I/O shapes match
+ OP_REQUIRES(_ctx.at(output_index).shape() == _ctx.at(input_index).shape());
+}
+
+void ShapeValidator::operator()()
+{
+ // There is no reason for each subgraph to have subgraphs since compiler has subgraphs when
+ // creating Compiler
+ assert(_graph.subgraphs() == nullptr);
+
+ _current_op_seq_layout = _graph.layout();
+
+ _graph.operations().iterate(
+ [&](const ir::OperationIndex &, const ir::Operation &node) { node.accept(*this); });
+}
+
+void ShapeValidator::visit(const ir::operation::BatchMatMul &node)
+{
+ const auto lhs_index(node.getInputs().at(ir::operation::BatchMatMul::Input::LHS));
+ const auto rhs_index(node.getInputs().at(ir::operation::BatchMatMul::Input::RHS));
+ const auto out_index{node.getOutputs().at(0)};
+
+ if (_ctx.at(out_index).info().isDynamic())
+ return;
+
+ OP_REQUIRES(_ctx.at(lhs_index).shape().rank() <= 4);
+ OP_REQUIRES(_ctx.at(rhs_index).shape().rank() <= 4);
+ OP_REQUIRES(_ctx.at(lhs_index).shape().rank() >= 2);
+ OP_REQUIRES(_ctx.at(rhs_index).shape().rank() >= 2);
+}
+
+void ShapeValidator::visit(const ir::operation::BatchToSpaceND &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)};
+ const auto block_size_index{
+ node.getInputs().at(ir::operation::BatchToSpaceND::Input::BLOCK_SIZE)};
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto input_shape = _ctx.at(ifm_index).shape().asFeature(frontend_layout);
+ const auto output_shape = _ctx.at(ofm_index).shape().asFeature(frontend_layout);
+
+ // All requirement as per NNAPI specification.
+ OP_REQUIRES(_ctx.at(ifm_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(ofm_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(block_size_index).shape().rank() == 1);
+
+ OP_REQUIRES(_ctx.at(block_size_index).shape().dim(0) == 2);
+
+ OP_REQUIRES(input_shape.C == output_shape.C);
+}
+
+void ShapeValidator::visit(const ir::operation::BCQFullyConnected &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::BCQFullyConnected::Input::INPUT)};
+ const auto weight_scales_index{
+ node.getInputs().at(ir::operation::BCQFullyConnected::Input::WEIGHTS_SCALES)};
+ const auto weight_binary_index{
+ node.getInputs().at(ir::operation::BCQFullyConnected::Input::WEIGHTS_BINARY)};
+ const auto weight_cluster_index{
+ node.getInputs().at(ir::operation::BCQFullyConnected::Input::WEIGHTS_CLUSTERS)};
+ // const auto bias_index{node.getInputs().at(ir::operation::BCQFullyConnected::Input::BIAS)};
+
+ OP_REQUIRES(_ctx.at(ifm_index).shape().rank() == 2);
+ OP_REQUIRES(_ctx.at(ofm_index).shape().rank() == 2);
+ OP_REQUIRES(_ctx.at(weight_scales_index).shape().rank() == 1);
+ OP_REQUIRES(_ctx.at(weight_binary_index).shape().rank() == 2);
+ OP_REQUIRES(_ctx.at(weight_cluster_index).shape().rank() == 2);
+
+ OP_REQUIRES(_ctx.at(ifm_index).shape().dim(1) == _ctx.at(ofm_index).shape().dim(1));
+
+ OP_REQUIRES(_ctx.at(weight_cluster_index).shape().dim(0) > 0);
+ OP_REQUIRES(_ctx.at(weight_cluster_index).shape().dim(1) == 2);
+
+ // more shape validation will be done inside kernel.
+
+ // TODO Check bias dimension (can be null tensor)
+}
+
+void ShapeValidator::visit(const ir::operation::BCQGather &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto indices_index{node.getInputs().at(ir::operation::BCQGather::Input::INDICES)};
+ const auto input_binary_index{node.getInputs().at(ir::operation::BCQGather::Input::INPUT_BINARY)};
+ const auto input_scales_index{node.getInputs().at(ir::operation::BCQGather::Input::INPUT_SCALES)};
+ const auto input_clusters_index{
+ node.getInputs().at(ir::operation::BCQGather::Input::INPUT_CLUSTERS)};
+
+ OP_REQUIRES(_ctx.at(indices_index).shape().rank() <= 2); // TODO : support rank up to 4 or more
+ OP_REQUIRES(_ctx.at(input_binary_index).shape().rank() == 2);
+ OP_REQUIRES(_ctx.at(input_scales_index).shape().rank() == 1);
+ OP_REQUIRES(_ctx.at(input_clusters_index).shape().rank() == 2);
+
+ OP_REQUIRES(_ctx.at(input_clusters_index).shape().dim(0) > 0);
+ OP_REQUIRES(_ctx.at(input_clusters_index).shape().dim(1) == 2);
+
+ // more shape validation will be done inside kernel.
+}
+
+void ShapeValidator::visit(const ir::operation::Comparison &)
+{
+ // TODO Shape validation of comparison
+}
+
+void ShapeValidator::visit(const ir::operation::Softmax &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(0)};
+
+ OP_REQUIRES(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
+}
+
+void ShapeValidator::visit(const ir::operation::InstanceNorm &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::InstanceNorm::Input::INPUT)};
+ const auto gamma_index{node.getInputs().at(ir::operation::InstanceNorm::Input::GAMMA)};
+ const auto beta_index{node.getInputs().at(ir::operation::InstanceNorm::Input::BETA)};
+
+ OP_REQUIRES(_ctx.at(ifm_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(ifm_index).shape() == _ctx.at(ofm_index).shape());
+ OP_REQUIRES(_ctx.at(gamma_index).shape().rank() == 1);
+ OP_REQUIRES(_ctx.at(beta_index).shape().rank() == 1);
+}
+
+void ShapeValidator::visit(const ir::operation::Pool2D &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::Pool2D::Input::INPUT)};
+
+ OP_REQUIRES(_ctx.at(ifm_index).shape().rank() == 4);
+}
+
+void ShapeValidator::visit(const ir::operation::Permute &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(0)};
+
+ OP_REQUIRES(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
+}
+
+void ShapeValidator::visit(const ir::operation::Reduce &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(ir::operation::Reduce::Input::INPUT)};
+ const auto input_shape = _ctx.at(input_index).shape();
+ const auto output_shape = _ctx.at(output_index).shape();
+
+ OP_REQUIRES(input_shape.rank() <= 4);
+ OP_REQUIRES(output_shape.rank() <= input_shape.rank());
+
+ // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only
+ // supports cases reducing height and width or reducing depth.
+ // TODO We have to support all cases of dimensions up to 4.
+ // For correct permuting, we have to set output's shape to be equal in dimension position of the
+ // input. But the positions of the same dimensions in the input and output may be set differently.
+ // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original
+ // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to
+ // extend it in 4 dimensions, it should be {1,1,3,5}.
+ // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of
+ // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the
+ // next operation is not desired.
+ if (input_shape.rank() == 4 && input_shape.rank() != output_shape.rank())
+ {
+ if (output_shape.rank() == 2)
+ {
+ // Reducing HW
+ OP_REQUIRES(input_shape.dim(0) == output_shape.dim(0) &&
+ input_shape.dim(3) == output_shape.dim(1));
+ }
+ else if (output_shape.rank() == 3)
+ {
+ // Reducing C or
+ // (Reducing H and C(input and output) == 1) or (Reducing W and C(input and output) == 1)
+ OP_REQUIRES((input_shape.dim(0) == output_shape.dim(0) &&
+ input_shape.dim(1) == output_shape.dim(1) &&
+ input_shape.dim(2) == output_shape.dim(2)) ||
+ (input_shape.dim(0) == output_shape.dim(0) &&
+ (input_shape.dim(1) == output_shape.dim(1) ||
+ input_shape.dim(2) == output_shape.dim(1)) &&
+ input_shape.dim(3) == 1 && output_shape.dim(2) == 1));
+ }
+ }
+}
+
+void ShapeValidator::visit(const ir::operation::Transpose &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(ir::operation::Transpose::Input::INPUT)};
+ const auto perm_index{node.getInputs().at(ir::operation::Transpose::Input::PERMUTATION)};
+
+ const auto &output_shape = _ctx.at(output_index).shape();
+ const auto &input_shape = _ctx.at(input_index).shape();
+
+ OP_REQUIRES(_ctx.at(perm_index).shape().num_elements() == 0 ||
+ input_shape.rank() == static_cast<int>(_ctx.at(perm_index).shape().num_elements()));
+ OP_REQUIRES(input_shape.rank() == output_shape.rank());
+}
+
+void ShapeValidator::visit(const ir::operation::RNN &node)
+{
+ // NOTE This validation is for static rnn(non-dynamic shape), but not for dynamic rnn
+ // TODO Support dynamic rnn
+ const auto output_index{node.getOutputs().at(ir::operation::RNN::Output::OUTPUT)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto hidden_state_out_index{
+ node.getOutputs().at(ir::operation::RNN::Output::HIDDEN_STATE_OUT)};
+
+ const auto input_index{node.getInputs().at(ir::operation::RNN::Input::INPUT)};
+ const auto weights_index{node.getInputs().at(ir::operation::RNN::Input::WEIGHTS)};
+ const auto recurrent_weights_index{
+ node.getInputs().at(ir::operation::RNN::Input::RECURRENT_WEIGHTS)};
+ const auto bias_index{node.getInputs().at(ir::operation::RNN::Input::BIAS)};
+ const auto hidden_state_in_index{node.getInputs().at(ir::operation::RNN::Input::HIDDEN_STATE_IN)};
+
+ const auto batch_size = _ctx.at(output_index).shape().dim(0);
+ const auto num_units = _ctx.at(output_index).shape().dim(1);
+
+ OP_REQUIRES(_ctx.at(output_index).shape().rank() == 2 &&
+ _ctx.at(hidden_state_out_index).shape().rank() == 2 &&
+ _ctx.at(input_index).shape().rank() == 2 &&
+ _ctx.at(weights_index).shape().rank() == 2 &&
+ _ctx.at(recurrent_weights_index).shape().rank() == 2 &&
+ _ctx.at(hidden_state_in_index).shape().rank() == 2);
+ OP_REQUIRES(_ctx.at(bias_index).shape().rank() == 1);
+
+ OP_REQUIRES(batch_size == _ctx.at(input_index).shape().dim(0) &&
+ batch_size == _ctx.at(hidden_state_in_index).shape().dim(0) &&
+ batch_size == _ctx.at(hidden_state_out_index).shape().dim(0));
+ OP_REQUIRES(_ctx.at(input_index).shape().dim(1) == _ctx.at(weights_index).shape().dim(1));
+
+ OP_REQUIRES(num_units == _ctx.at(weights_index).shape().dim(0) &&
+ num_units == _ctx.at(recurrent_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(bias_index).shape().dim(0));
+ OP_REQUIRES(num_units == _ctx.at(output_index).shape().dim(1) &&
+ num_units == _ctx.at(recurrent_weights_index).shape().dim(1) &&
+ num_units == _ctx.at(hidden_state_in_index).shape().dim(1) &&
+ num_units == _ctx.at(hidden_state_out_index).shape().dim(1));
+}
+
+void ShapeValidator::visit(const ir::operation::SpaceToBatchND &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)};
+ const auto block_size_index{
+ node.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)};
+ const auto paddings_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)};
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto input_shape = _ctx.at(ifm_index).shape().asFeature(frontend_layout);
+ const auto output_shape = _ctx.at(ofm_index).shape().asFeature(frontend_layout);
+
+ // All requirement as per NNAPI specification.
+ OP_REQUIRES(_ctx.at(ifm_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(ofm_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(block_size_index).shape().rank() == 1);
+ OP_REQUIRES(_ctx.at(paddings_index).shape().rank() == 2);
+
+ OP_REQUIRES(_ctx.at(block_size_index).shape().dim(0) == 2);
+ OP_REQUIRES(_ctx.at(paddings_index).shape().dim(0) == 2);
+ OP_REQUIRES(_ctx.at(paddings_index).shape().dim(1) == 2);
+
+ OP_REQUIRES(input_shape.C == output_shape.C);
+}
+
+void ShapeValidator::visit(const ir::operation::SpaceToDepth &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)};
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto input_shape = _ctx.at(ifm_index).shape().asFeature(frontend_layout);
+ const auto output_shape = _ctx.at(ofm_index).shape().asFeature(frontend_layout);
+ const auto block_size = node.param().block_size;
+
+ // All assertions as per NNAPI specification.
+ OP_REQUIRES(_ctx.at(ifm_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(ofm_index).shape().rank() == 4);
+ OP_REQUIRES((input_shape.H % block_size == 0) && (input_shape.W % block_size == 0));
+ OP_REQUIRES(input_shape.N == output_shape.N);
+ OP_REQUIRES(input_shape.C * block_size * block_size == output_shape.C);
+}
+
+void ShapeValidator::visit(const ir::operation::ElementwiseActivation &node) { checkUnaryOp(node); }
+
+void ShapeValidator::visit(const ir::operation::ElementwiseBinary &)
+{
+ // TODO Shape validation of ElementwiseBinary
+}
+
+void ShapeValidator::visit(const ir::operation::ElementwiseUnary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ElementwiseUnary::Input::INPUT)};
+
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ OP_REQUIRES(_ctx.at(output_index).shape() == _ctx.at(input_index).shape());
+}
+
+void ShapeValidator::visit(const ir::operation::EmbeddingLookup &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lookups_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::LOOKUPS)};
+ const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)};
+
+ const auto &output_obj = _ctx.at(output_index);
+ const auto &lookups_obj = _ctx.at(lookups_index);
+ const auto &values_obj = _ctx.at(values_index);
+
+ // Verify operand here, not at SimpleEmbeddingLookup::configure() to avoid acl's modifying
+ // TensorShape sometimes(Issue: https://github.sec.samsung.net/STAR/nnfw/issues/729)
+ {
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto &output_shape = output_obj.shape();
+ const auto &lookups_shape = lookups_obj.shape();
+ const auto &values_shape = values_obj.shape();
+
+ OP_REQUIRES(lookups_shape.rank() == 1);
+ OP_REQUIRES(values_shape.rank() >= 2);
+
+ // output should be a n-D tensor with the same rank and shape as the values tensor, except for
+ // the first dimension which has the same size as lookups' only dimension.
+ OP_REQUIRES(output_shape.rank() == values_shape.rank());
+ OP_REQUIRES(output_shape.dim(0) == lookups_shape.dim(0));
+ for (int n = 1; n < output_shape.rank(); ++n)
+ {
+ OP_REQUIRES(output_shape.dim(n) == values_shape.dim(n));
+ }
+ }
+}
+
+void ShapeValidator::visit(const ir::operation::ExpandDims &node)
+{
+ const auto axis_index{node.getInputs().at(ir::operation::ExpandDims::Input::AXIS)};
+
+ if (_ctx.at(axis_index).info().isDynamic())
+ return;
+ OP_REQUIRES(_ctx.at(axis_index).shape().rank() <= 1);
+}
+
+void ShapeValidator::visit(const ir::operation::HashtableLookup &node)
+{
+ const auto output_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::OUTPUT)};
+ const auto lookups_index{node.getInputs().at(ir::operation::HashtableLookup::Input::LOOKUPS)};
+ const auto keys_index{node.getInputs().at(ir::operation::HashtableLookup::Input::KEYS)};
+ const auto values_index{node.getInputs().at(ir::operation::HashtableLookup::Input::VALUES)};
+
+ const auto &output_obj = _ctx.at(output_index);
+ const auto &lookups_obj = _ctx.at(lookups_index);
+ const auto &keys_obj = _ctx.at(keys_index);
+ const auto &values_obj = _ctx.at(values_index);
+
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto &output_shape = output_obj.shape();
+ const auto &lookups_shape = lookups_obj.shape();
+ const auto &keys_shape = keys_obj.shape();
+ const auto &values_shape = values_obj.shape();
+
+ OP_REQUIRES(values_shape.rank() == output_shape.rank());
+ OP_REQUIRES(lookups_shape.rank() == 1);
+ OP_REQUIRES(keys_shape.rank() == 1);
+ OP_REQUIRES(values_shape.dim(0) == keys_shape.dim(0));
+ OP_REQUIRES(lookups_shape.dim(0) == output_shape.dim(0));
+}
+
+void ShapeValidator::visit(const ir::operation::TransposeConv &node)
+{
+ // shape check
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::TransposeConv::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(ir::operation::TransposeConv::Input::KERNEL)};
+
+ // Only 4D tensors are supported
+ OP_REQUIRES(_ctx.at(ofm_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(ofm_index).shape().rank() == _ctx.at(ifm_index).shape().rank());
+ OP_REQUIRES(_ctx.at(ofm_index).shape().rank() == _ctx.at(ker_index).shape().rank());
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(frontend_layout);
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(frontend_layout);
+ // The kernel has only IHWO layout on frontend
+ // So ker_shape is treated here below
+ // I -> N
+ // H -> H
+ // W -> W
+ // O -> C
+ const auto ker_shape = _ctx.at(ker_index).shape().asFeature(ir::Layout::NHWC);
+
+ OP_REQUIRES(ifm_shape.N == ofm_shape.N);
+ OP_REQUIRES(ifm_shape.C == ker_shape.C);
+ OP_REQUIRES(ker_shape.N == ofm_shape.C);
+}
+
+void ShapeValidator::visit(const ir::operation::Gather &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)};
+ const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)};
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape();
+ const auto indices_shape = _ctx.at(indices_index).shape();
+ const auto ofm_shape = _ctx.at(ofm_index).shape();
+
+ OP_REQUIRES(ifm_shape.rank() <= 4);
+ OP_REQUIRES(indices_shape.rank() <= 3);
+ OP_REQUIRES(ofm_shape.rank() <= 4);
+}
+
+void ShapeValidator::visit(const ir::operation::DepthToSpace &node)
+{
+ int32_t block_size = node.param().block_size;
+
+ // shape check
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(ir::operation::DepthToSpace::Input::INPUT)};
+
+ const auto frontend_layout = _current_op_seq_layout;
+ const auto output_shape = _ctx.at(output_index).shape().asFeature(frontend_layout);
+ const auto input_shape = _ctx.at(input_index).shape().asFeature(frontend_layout);
+
+ OP_REQUIRES(_ctx.at(input_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(output_index).shape().rank() == 4);
+
+ {
+ OP_REQUIRES(output_shape.N == input_shape.N);
+ OP_REQUIRES(output_shape.H == input_shape.H * block_size);
+ OP_REQUIRES(output_shape.W == input_shape.W * block_size);
+ OP_REQUIRES(input_shape.C % (block_size * block_size) == 0);
+ OP_REQUIRES(output_shape.C == input_shape.C / (block_size * block_size));
+ }
+}
+
+void ShapeValidator::visit(const ir::operation::Pack &node)
+{
+ const auto axis{node.param().axis};
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ // shape check
+ const auto &output_shape = _ctx.at(output_index).shape();
+ const auto output_rank = static_cast<int32_t>(output_shape.rank());
+
+ const auto input1_index{node.getInputs().at(0)};
+ const auto input_shape = _ctx.at(input1_index).shape();
+
+ OP_REQUIRES(axis >= -output_rank && axis < output_rank);
+ for (const auto &index : node.getInputs())
+ {
+ OP_REQUIRES(input_shape == _ctx.at(index).shape());
+ }
+}
+
+void ShapeValidator::visit(const ir::operation::LSTM &node)
+{
+ // NOTE This validation is for static rnn(non-dynamic shape), but not for dynamic rnn
+ // TODO Support dynamic rnn
+ const auto output_index{node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto scratch_buffer_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)}; // Optional
+ const auto output_state_out_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)}; // Optional
+ const auto cell_state_out_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)}; // Optional
+
+ const auto input_index{node.getInputs().at(ir::operation::LSTM::Input::INPUT)};
+ const auto input_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)}; // Optional
+ const auto input_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_FORGET_WEIGHTS)};
+ const auto input_to_cell_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_CELL_WEIGHTS)};
+ const auto input_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)};
+ const auto recurrent_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)}; // Optional
+ const auto recurrent_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS)};
+ const auto recurrent_to_cell_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_CELL_WEIGHTS)};
+ const auto recurrent_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS)};
+ const auto cell_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_INPUT_WEIGHTS)}; // Optional
+ const auto cell_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_FORGET_WEIGHTS)}; // Optional
+ const auto cell_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_OUTPUT_WEIGHTS)}; // Optional
+ const auto input_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_GATE_BIAS)}; // Optional
+ const auto forget_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::FORGET_GATE_BIAS)};
+ const auto cell_bias_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_BIAS)};
+ const auto output_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_GATE_BIAS)};
+ const auto projection_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_WEIGHTS)}; // Optional
+ const auto projection_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_BIAS)}; // Optional
+ const auto output_state_in_index{
+ node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_STATE_IN)};
+ const auto cell_state_in_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_STATE_IN)};
+
+ OP_REQUIRES(_ctx.at(input_index).shape().rank() == _ctx.at(output_index).shape().rank());
+ for (int i = 0; i < _ctx.at(input_index).shape().rank() - 1; ++i)
+ {
+ OP_REQUIRES(_ctx.at(input_index).shape().dim(i) == _ctx.at(output_index).shape().dim(i));
+ }
+ OP_REQUIRES(
+ (_ctx.at(output_index).shape().rank() == 2 || _ctx.at(output_index).shape().rank() == 3) &&
+ (_ctx.at(input_index).shape().rank() == 2 || _ctx.at(input_index).shape().rank() == 3) &&
+ (!_ctx.exist(input_to_input_weights_index) ||
+ _ctx.at(input_to_input_weights_index).shape().rank() == 2) &&
+ _ctx.at(input_to_forget_weights_index).shape().rank() == 2 &&
+ _ctx.at(input_to_cell_weights_index).shape().rank() == 2 &&
+ _ctx.at(input_to_output_weights_index).shape().rank() == 2 &&
+ (!_ctx.exist(recurrent_to_input_weights_index) ||
+ _ctx.at(recurrent_to_input_weights_index).shape().rank() == 2) &&
+ _ctx.at(recurrent_to_forget_weights_index).shape().rank() == 2 &&
+ _ctx.at(recurrent_to_cell_weights_index).shape().rank() == 2 &&
+ _ctx.at(recurrent_to_output_weights_index).shape().rank() == 2 &&
+ (!_ctx.exist(projection_weights_index) ||
+ _ctx.at(projection_weights_index).shape().rank() == 2) &&
+ _ctx.at(output_state_in_index).shape().rank() == 2 &&
+ _ctx.at(cell_state_in_index).shape().rank() == 2);
+
+ OP_REQUIRES(
+ (!_ctx.exist(cell_to_input_weights_index) ||
+ _ctx.at(cell_to_input_weights_index).shape().rank() == 1) &&
+ (!_ctx.exist(cell_to_forget_weights_index) ||
+ _ctx.at(cell_to_forget_weights_index).shape().rank() == 1) &&
+ (!_ctx.exist(cell_to_output_weights_index) ||
+ _ctx.at(cell_to_output_weights_index).shape().rank() == 1) &&
+ (!_ctx.exist(input_gate_bias_index) || _ctx.at(input_gate_bias_index).shape().rank() == 1) &&
+ _ctx.at(forget_gate_bias_index).shape().rank() == 1 &&
+ _ctx.at(cell_bias_index).shape().rank() == 1 &&
+ _ctx.at(output_gate_bias_index).shape().rank() == 1 &&
+ (!_ctx.exist(projection_bias_index) || _ctx.at(projection_bias_index).shape().rank() == 1));
+
+ // CIFG assertion
+ OP_REQUIRES(
+ ((!_ctx.exist(input_to_input_weights_index) ||
+ (_ctx.at(input_to_input_weights_index).shape().dim(0) == 0 &&
+ _ctx.at(input_to_input_weights_index).shape().dim(1) == 0)) &&
+ (!_ctx.exist(recurrent_to_input_weights_index) ||
+ (_ctx.at(recurrent_to_input_weights_index).shape().dim(0) == 0 &&
+ _ctx.at(recurrent_to_input_weights_index).shape().dim(1) == 0)) &&
+ (!_ctx.exist(input_gate_bias_index) || _ctx.at(input_gate_bias_index).shape().dim(0) == 0) &&
+ (!_ctx.exist(cell_to_input_weights_index) ||
+ _ctx.at(cell_to_input_weights_index).shape().dim(0) == 0)) ||
+ ((_ctx.exist(input_to_input_weights_index) &&
+ (_ctx.at(input_to_input_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(input_to_input_weights_index).shape().dim(1) != 0)) &&
+ (_ctx.exist(recurrent_to_input_weights_index) &&
+ (_ctx.at(recurrent_to_input_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(recurrent_to_input_weights_index).shape().dim(1) != 0)) &&
+ (_ctx.exist(input_gate_bias_index) && _ctx.at(input_gate_bias_index).shape().dim(0) != 0)));
+
+ // Peephole assertion
+ OP_REQUIRES(((!_ctx.exist(cell_to_forget_weights_index) ||
+ _ctx.at(cell_to_forget_weights_index).shape().dim(0) == 0) &&
+ (!_ctx.exist(cell_to_output_weights_index) ||
+ _ctx.at(cell_to_output_weights_index).shape().dim(0) == 0)) ||
+ ((_ctx.exist(cell_to_forget_weights_index) &&
+ _ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0) &&
+ (_ctx.exist(cell_to_output_weights_index) &&
+ _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0)));
+
+ bool has_input_to_input_weights = _ctx.exist(input_to_input_weights_index) &&
+ (_ctx.at(input_to_input_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(input_to_input_weights_index).shape().dim(1) != 0);
+ bool has_recurrent_to_input_weights =
+ _ctx.exist(recurrent_to_input_weights_index) &&
+ (_ctx.at(recurrent_to_input_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(recurrent_to_input_weights_index).shape().dim(1) != 0);
+ bool has_input_gate_bias =
+ _ctx.exist(input_gate_bias_index) && _ctx.at(input_gate_bias_index).shape().dim(0) != 0;
+ bool has_cell_to_input_weights = _ctx.exist(cell_to_input_weights_index) &&
+ _ctx.at(cell_to_input_weights_index).shape().dim(0) != 0;
+ bool has_cell_to_forget_weights = _ctx.exist(cell_to_forget_weights_index) &&
+ _ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0;
+ bool has_cell_to_output_weights = _ctx.exist(cell_to_output_weights_index) &&
+ _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0;
+ bool has_projection_weights = _ctx.exist(projection_weights_index) &&
+ (_ctx.at(projection_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(projection_weights_index).shape().dim(1) != 0);
+ bool has_projection_bias =
+ _ctx.exist(projection_bias_index) && _ctx.at(projection_bias_index).shape().dim(0) != 0;
+
+ // NOTE The cell_to_input_weights do not exist in non-peephole although regular LSTM(non-CIFG).
+ // true: no CIFG
+ // false: CIFG
+ bool has_cifg_param = has_input_to_input_weights && has_recurrent_to_input_weights;
+
+ // NOTE The cell_to_input_weights do not exist in regular CIFG although peephole.
+ // true: peephole
+ // false: no peephole
+ bool has_peephole_param = has_cell_to_forget_weights && has_cell_to_output_weights;
+
+ // NOTE The projection weights may have data but the projection bias may not.
+ bool has_projection_param = has_projection_weights;
+
+ const auto batch_size = (_ctx.at(input_index).shape().rank() == 3 && node.param().time_major)
+ ? _ctx.at(input_index).shape().dim(1)
+ : _ctx.at(input_index).shape().dim(0);
+ OP_REQUIRES(batch_size == _ctx.at(output_state_in_index).shape().dim(0) &&
+ batch_size == _ctx.at(cell_state_in_index).shape().dim(0));
+
+ const auto input_size = _ctx.at(input_index).shape().dim(_ctx.at(input_index).shape().rank() - 1);
+ OP_REQUIRES(input_size == _ctx.at(input_to_forget_weights_index).shape().dim(1) &&
+ input_size == _ctx.at(input_to_cell_weights_index).shape().dim(1) &&
+ input_size == _ctx.at(input_to_output_weights_index).shape().dim(1));
+
+ const auto num_units = _ctx.at(input_to_output_weights_index).shape().dim(0);
+ OP_REQUIRES(num_units == _ctx.at(input_to_cell_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(input_to_output_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(recurrent_to_forget_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(recurrent_to_cell_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(recurrent_to_output_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(forget_gate_bias_index).shape().dim(0) &&
+ num_units == _ctx.at(cell_bias_index).shape().dim(0) &&
+ num_units == _ctx.at(output_gate_bias_index).shape().dim(0) &&
+ num_units == _ctx.at(cell_state_in_index).shape().dim(1));
+
+ const auto output_size =
+ _ctx.at(output_index).shape().dim(_ctx.at(output_index).shape().rank() - 1);
+ OP_REQUIRES(output_size == _ctx.at(recurrent_to_forget_weights_index).shape().dim(1) &&
+ output_size == _ctx.at(recurrent_to_cell_weights_index).shape().dim(1) &&
+ output_size == _ctx.at(recurrent_to_output_weights_index).shape().dim(1) &&
+ output_size == _ctx.at(output_state_in_index).shape().dim(1));
+
+ if (has_cifg_param)
+ {
+ OP_REQUIRES(input_size == _ctx.at(input_to_input_weights_index).shape().dim(1));
+ OP_REQUIRES(num_units == _ctx.at(input_to_input_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(recurrent_to_input_weights_index).shape().dim(0) &&
+ ((_ctx.exist(cell_to_input_weights_index) &&
+ num_units == _ctx.at(cell_to_input_weights_index).shape().dim(0)) ||
+ (!_ctx.exist(cell_to_input_weights_index) ||
+ _ctx.at(cell_to_input_weights_index).shape().dim(0) == 0) /* non-peephole */) &&
+ num_units == _ctx.at(input_gate_bias_index).shape().dim(0));
+ OP_REQUIRES(output_size == _ctx.at(recurrent_to_input_weights_index).shape().dim(1));
+ OP_REQUIRES(has_input_to_input_weights && has_recurrent_to_input_weights &&
+ has_input_gate_bias);
+ if (has_cell_to_input_weights)
+ {
+ // NOTE The cell_to_input_weights exist only in case of non-CIFG and peephole.
+ OP_REQUIRES(has_peephole_param);
+ }
+ if (_ctx.exist(scratch_buffer_index))
+ OP_REQUIRES(_ctx.at(scratch_buffer_index).shape().dim(1) == num_units * 4);
+ }
+ else
+ {
+ if (_ctx.exist(scratch_buffer_index))
+ OP_REQUIRES(_ctx.at(scratch_buffer_index).shape().dim(1) == num_units * 3);
+ }
+
+ if (has_peephole_param)
+ {
+ OP_REQUIRES(num_units == _ctx.at(cell_to_forget_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(cell_to_output_weights_index).shape().dim(0) &&
+ (num_units == _ctx.at(cell_to_input_weights_index).shape().dim(0) ||
+ _ctx.at(cell_to_input_weights_index).shape().dim(0) == 0 /* CIFG */));
+ }
+
+ if (has_projection_param)
+ {
+ OP_REQUIRES(num_units == _ctx.at(projection_weights_index).shape().dim(1));
+ OP_REQUIRES(output_size == _ctx.at(projection_weights_index).shape().dim(0));
+ if (has_projection_bias)
+ {
+ OP_REQUIRES(output_size == _ctx.at(projection_bias_index).shape().dim(0));
+ }
+ }
+
+ if (_ctx.exist(scratch_buffer_index))
+ {
+ OP_REQUIRES(_ctx.at(scratch_buffer_index).shape().rank() == 2);
+ OP_REQUIRES(batch_size == _ctx.at(scratch_buffer_index).shape().dim(0));
+ }
+
+ if (_ctx.exist(output_state_out_index))
+ {
+ OP_REQUIRES(_ctx.at(output_state_out_index).shape().rank() == 2);
+ OP_REQUIRES(batch_size == _ctx.at(output_state_out_index).shape().dim(0));
+ OP_REQUIRES(output_size == _ctx.at(output_state_out_index).shape().dim(1));
+ }
+
+ if (_ctx.exist(cell_state_out_index))
+ {
+ OP_REQUIRES(_ctx.at(cell_state_out_index).shape().rank() == 2);
+ OP_REQUIRES(batch_size == _ctx.at(cell_state_out_index).shape().dim(0));
+ OP_REQUIRES(num_units == _ctx.at(cell_state_out_index).shape().dim(1));
+ }
+}
+
+void ShapeValidator::visit(const ir::operation::L2Normalization &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ if (_ctx.at(ofm_index).info().isDynamic())
+ return;
+
+ const auto ifm_index{node.getInputs().at(ir::operation::L2Normalization::Input::INPUT)};
+
+ auto ifm_shape = _ctx.at(ifm_index).shape();
+ auto ofm_shape = _ctx.at(ofm_index).shape();
+
+ OP_REQUIRES(ifm_shape.rank() == ofm_shape.rank());
+
+ for (auto i = 0; i < ifm_shape.rank(); i++)
+ {
+ OP_REQUIRES(ifm_shape.dim(i) == ofm_shape.dim(i));
+ }
+}
+
+void ShapeValidator::visit(const ir::operation::Unpack &node)
+{
+ const auto axis{node.param().axis};
+ const auto output_index{node.getInputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)};
+
+ const auto &input_shape = _ctx.at(input_index).shape();
+ const auto input_rank = static_cast<int32_t>(input_shape.rank());
+
+ OP_REQUIRES(axis >= -input_rank && axis < input_rank);
+}
+
+void ShapeValidator::visit(const ir::operation::Pad &node)
+{
+ const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)};
+ OP_REQUIRES(_ctx.at(pad_index).typeInfo().type() == ir::DataType::INT32);
+
+ const auto output_index{node.getInputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)};
+
+ const auto &pad_shape = _ctx.at(pad_index).shape();
+ const auto input_rank = static_cast<int32_t>(_ctx.at(input_index).shape().rank());
+
+ OP_REQUIRES(pad_shape.rank() == 2);
+ OP_REQUIRES(pad_shape.dim(0) == input_rank);
+ OP_REQUIRES(pad_shape.dim(1) == 2);
+ OP_REQUIRES(_ctx.at(input_index).shape().rank() == _ctx.at(output_index).shape().rank());
+}
+
+void ShapeValidator::visit(const ir::operation::Select &)
+{
+ // TODO Shape validation of select
+}
+
+void ShapeValidator::visit(const ir::operation::StridedSlice &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)};
+
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ OP_REQUIRES(_ctx.at(input_index).shape().rank() <= 4);
+}
+
+void ShapeValidator::visit(const ir::operation::Split &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(ir::operation::Split::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(ir::operation::Split::Input::AXIS)};
+
+ const auto num_splits = node.param().num_splits;
+ const auto input_rank = _ctx.at(input_index).shape().rank();
+ auto axis = *reinterpret_cast<const int32_t *>(_ctx.at(axis_index).data()->base());
+ axis = axis < 0 ? axis + input_rank : axis;
+
+ OP_REQUIRES(axis >= 0 && axis < input_rank);
+ OP_REQUIRES(_ctx.at(input_index).shape().dim(axis) % num_splits == 0);
+}
+
+void ShapeValidator::visit(const ir::operation::Shape &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(0)};
+ UNUSED_RELEASE(input_index);
+ OP_REQUIRES(_ctx.at(output_index).shape().rank() == 1);
+}
+
+void ShapeValidator::visit(const ir::operation::ResizeBilinear &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ResizeBilinear::Input::INPUT)};
+
+ if (_ctx.at(output_index).info().isDynamic())
+ {
+ return;
+ }
+ OP_REQUIRES(_ctx.at(input_index).shape().rank() == 4);
+ OP_REQUIRES(_ctx.at(output_index).shape().rank() == 4);
+}
+
+void ShapeValidator::visit(const ir::operation::Reverse &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Reverse::Input::INPUT)};
+
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+ OP_REQUIRES(_ctx.at(output_index).shape() == _ctx.at(input_index).shape());
+}
+
+void ShapeValidator::visit(const ir::operation::If &)
+{
+ // TODO Add to validate with subgraphs
+}
+
+void ShapeValidator::visit(const ir::operation::While &)
+{
+ // This validator does not check shape. So checking isDynamic() is skipped.
+ // TODO Add to validate with subgraphs
+}
+
+void ShapeValidator::visit(const ir::operation::SquaredDifference &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::RHS)};
+
+ // Check for dimension constraints
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ auto output_shape = _ctx.at(output_index).shape();
+ auto lhs_shape = _ctx.at(lhs_index).shape();
+ auto rhs_shape = _ctx.at(rhs_index).shape();
+ // Check for output rank
+ OP_REQUIRES(output_shape.rank() == std::max(lhs_shape.rank(), rhs_shape.rank()));
+ auto min_rank = std::min(lhs_shape.rank(), rhs_shape.rank());
+
+ for (int idx = 1; idx <= min_rank; idx++)
+ {
+ int l_idx = lhs_shape.rank() - idx;
+ int r_idx = rhs_shape.rank() - idx;
+ int out_idx = output_shape.rank() - idx;
+
+ OP_REQUIRES((l_idx >= 0) && (r_idx >= 0) && (out_idx >= 0));
+
+ auto l_dims = lhs_shape.dim(l_idx);
+ auto r_dims = rhs_shape.dim(r_idx);
+ auto out_dims = output_shape.dim(out_idx);
+
+ OP_REQUIRES(((l_dims == r_dims) && (out_dims == l_dims)) ||
+ ((l_dims == 1) && (out_dims == r_dims)) || ((r_dims == 1) && (out_dims == l_dims)));
+ }
+ auto &tmp_shape = (lhs_shape.rank() > rhs_shape.rank()) ? lhs_shape : rhs_shape;
+ for (int idx = min_rank + 1; idx <= output_shape.rank(); idx++)
+ {
+ int out_idx = output_shape.rank() - idx;
+ int tmp_idx = tmp_shape.rank() - idx;
+
+ OP_REQUIRES((out_idx >= 0) && (tmp_idx >= 0) &&
+ (output_shape.dim(out_idx) == tmp_shape.dim(tmp_idx)));
+ }
+}
+void ShapeValidator::visit(const ir::operation::Tile &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(0)};
+ const auto multiple_index{node.getInputs().at(1)};
+
+ OP_REQUIRES(_ctx.at(multiple_index).shape().rank() == 1);
+ OP_REQUIRES(_ctx.at(multiple_index).shape().dim(0) == _ctx.at(input_index).shape().rank());
+ OP_REQUIRES(_ctx.at(input_index).shape().rank() == _ctx.at(output_index).shape().rank());
+}
+
+void ShapeValidator::visit(const ir::operation::Range &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto start_index{node.getInputs().at(ir::operation::Range::Input::START)};
+ const auto limit_index{node.getInputs().at(ir::operation::Range::Input::LIMIT)};
+ const auto delta_index{node.getInputs().at(ir::operation::Range::Input::DELTA)};
+
+ // Check for dimension constraints
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ OP_REQUIRES(_ctx.at(start_index).shape().rank() == 0);
+ OP_REQUIRES(_ctx.at(limit_index).shape().rank() == 0);
+ OP_REQUIRES(_ctx.at(delta_index).shape().rank() == 0);
+}
+
+void ShapeValidator::visit(const ir::operation::MatrixBandPart &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::MatrixBandPart::Input::INPUT)};
+ const auto num_lower_index{
+ node.getInputs().at(ir::operation::MatrixBandPart::Input::NUM_LOWER_DIAG)};
+ const auto num_upper_index{
+ node.getInputs().at(ir::operation::MatrixBandPart::Input::NUM_UPPER_DIAG)};
+
+ // Check for dimension constraints
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ OP_REQUIRES(_ctx.at(input_index).shape().rank() >= 2); // input must be more than 2 dim matrix
+ OP_REQUIRES(_ctx.at(num_upper_index).shape().rank() == 0); // num_lower must be scalar
+ OP_REQUIRES(_ctx.at(num_lower_index).shape().rank() == 0); // num_upper must be scalar
+}
+
+void ShapeValidator::visit(const ir::operation::LogSoftmax &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ if (_ctx.at(output_index).info().isDynamic())
+ return;
+
+ const auto input_index{node.getInputs().at(0)};
+
+ OP_REQUIRES(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
+}
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/ShapeValidator.h b/runtime/onert/core/src/compiler/ShapeValidator.h
new file mode 100644
index 000000000..f40c098d5
--- /dev/null
+++ b/runtime/onert/core/src/compiler/ShapeValidator.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_SHAPE_VALIDATOR_H__
+#define __ONERT_COMPILER_SHAPE_VALIDATOR_H__
+
+#include "ir/Layout.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+class Graph;
+class Operands;
+} // namespace ir
+} // namespace onert
+
+namespace onert
+{
+namespace compiler
+{
+
+class ShapeValidator : public ir::OperationVisitor
+{
+public:
+ ShapeValidator(void) = delete;
+ ShapeValidator(const ir::Graph &graph);
+
+public:
+ void operator()();
+
+public:
+ void visit(const ir::operation::BatchMatMul &node) override;
+ void visit(const ir::operation::BatchToSpaceND &node) override;
+ void visit(const ir::operation::BCQFullyConnected &node) override;
+ void visit(const ir::operation::BCQGather &node) override;
+ void visit(const ir::operation::Comparison &node) override;
+ void visit(const ir::operation::Softmax &node) override;
+ void visit(const ir::operation::InstanceNorm &node) override;
+ void visit(const ir::operation::Permute &node) override;
+ void visit(const ir::operation::Pool2D &node) override;
+ void visit(const ir::operation::Reduce &node) override;
+ void visit(const ir::operation::Transpose &node) override;
+ void visit(const ir::operation::RNN &node) override;
+ void visit(const ir::operation::SpaceToBatchND &node) override;
+ void visit(const ir::operation::SpaceToDepth &node) override;
+ void visit(const ir::operation::ElementwiseActivation &node) override;
+ void visit(const ir::operation::ElementwiseBinary &node) override;
+ void visit(const ir::operation::ElementwiseUnary &node) override;
+ void visit(const ir::operation::EmbeddingLookup &node) override;
+ void visit(const ir::operation::ExpandDims &node) override;
+ void visit(const ir::operation::HashtableLookup &node) override;
+ void visit(const ir::operation::TransposeConv &node) override;
+ void visit(const ir::operation::Gather &node) override;
+ void visit(const ir::operation::DepthToSpace &node) override;
+ void visit(const ir::operation::Pack &node) override;
+ void visit(const ir::operation::LSTM &node) override;
+ void visit(const ir::operation::L2Normalization &node) override;
+ void visit(const ir::operation::Unpack &node) override;
+ void visit(const ir::operation::Pad &node) override;
+ void visit(const ir::operation::Select &node) override;
+ void visit(const ir::operation::StridedSlice &node) override;
+ void visit(const ir::operation::Split &node) override;
+ void visit(const ir::operation::Shape &node) override;
+ void visit(const ir::operation::ResizeBilinear &node) override;
+ void visit(const ir::operation::Reverse &node) override;
+ void visit(const ir::operation::If &node) override;
+ void visit(const ir::operation::While &node) override;
+ void visit(const ir::operation::SquaredDifference &node) override;
+ void visit(const ir::operation::Tile &node) override;
+ void visit(const ir::operation::Range &node) override;
+ void visit(const ir::operation::MatrixBandPart &node) override;
+ void visit(const ir::operation::LogSoftmax &node) override;
+
+private:
+ void checkUnaryOp(const ir::Operation &node);
+
+private:
+ // TODO Remove _ctx field
+ const ir::Graph &_graph;
+ const ir::Operands &_ctx;
+ ir::Layout _current_op_seq_layout;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_SHAPE_VALIDATOR_H__
diff --git a/runtime/onert/core/src/compiler/StaticShapeInferer.cc b/runtime/onert/core/src/compiler/StaticShapeInferer.cc
new file mode 100644
index 000000000..d3b083b78
--- /dev/null
+++ b/runtime/onert/core/src/compiler/StaticShapeInferer.cc
@@ -0,0 +1,1302 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/StaticShapeInferer.h"
+#include "util/ShapeInference.h"
+#include "util/logging.h"
+
+#include <sstream>
+
+namespace onert
+{
+namespace compiler
+{
+
+bool StaticShapeInferer::infer(const ir::OpSequence &op_seq)
+{
+ bool has_dynamic_tensor = false;
+
+ for (const auto &operation_idx : op_seq.operations())
+ {
+ auto &op = _operations.at(operation_idx);
+ auto opcode = op.opcode();
+
+ _return_has_dynamic_tensor = false; // this is used as a return value inside operation's visit()
+
+ // IF: need shape inference for then, else
+ // While: need shape inference for condition, body
+ if (opcode == ir::OpCode::If || opcode == ir::OpCode::While)
+ {
+ op.accept(*this);
+ }
+ else
+ {
+ _return_has_dynamic_tensor = checkDynamicInput(op);
+
+ if (_return_has_dynamic_tensor)
+ {
+ setDynamicOutput(op);
+ }
+ else
+ {
+ op.accept(*this);
+ }
+ }
+
+ has_dynamic_tensor = has_dynamic_tensor || _return_has_dynamic_tensor;
+ }
+
+ return has_dynamic_tensor;
+}
+
+bool StaticShapeInferer::checkDynamicInput(const ir::Operation &op)
+{
+ for (auto input_idx : op.getInputs() | ir::Remove::UNDEFINED | ir::Remove::DUPLICATED)
+ {
+ if (_operands.at(input_idx).info().isDynamic())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void StaticShapeInferer::setDynamicOutput(const ir::Operation &op)
+{
+ for (auto output_idx : op.getOutputs() | ir::Remove::UNDEFINED)
+ {
+ _operands.at(output_idx).info().setDynamic();
+ }
+}
+
+void StaticShapeInferer::handleBinaryArithmeticOp(const ir::Operation &op,
+ const ir::OperandIndex lhs_idx,
+ const ir::OperandIndex rhs_idx)
+{
+ const auto &lhs = _operands.at(lhs_idx);
+ const auto &rhs = _operands.at(rhs_idx);
+
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferEltwiseShape(lhs.info().shape(), rhs.info().shape());
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::handleSimpleUnaryOp(const ir::Operation &op,
+ const ir::OperandIndex input_idx)
+{
+ const auto &input = _operands.at(input_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // re-sizing output shape
+ ir::Shape new_shape = input.info().shape();
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::dump()
+{
+ auto get_shape_str = [](const ir::Shape &shape) {
+ std::stringstream sstream;
+ sstream << "shape : {";
+ for (int i = 0; i < shape.rank(); i++)
+ {
+ if (i == 0)
+ sstream << shape.dim(i);
+ else
+ sstream << " " << shape.dim(i);
+ }
+ sstream << "}";
+ return sstream.str();
+ };
+
+ for (const auto &pair : _lowered_subgs)
+ {
+ const auto index = pair.first;
+ const auto &lowered_subg = pair.second;
+ VERBOSE(StaticShapeInferer) << "SubGraph #" << index.value() << std::endl;
+ lowered_subg->graph().operands().iterate(
+ [&](const ir::OperandIndex &ind, const ir::Operand &operand) {
+ VERBOSE(StaticShapeInferer) << "Operand #" << ind.value() << ", "
+ << (operand.info().isDynamic() ? "Dynamic" : "Static") << ", "
+ << get_shape_str(operand.info().shape()) << std::endl;
+ });
+ }
+}
+
+void StaticShapeInferer::visit(const ir::operation::ArgMax &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::ArgMax::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto axis_idx{op.getInputs().at(ir::operation::ArgMax::Input::AXIS)};
+ const auto &axis = _operands.at(axis_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ if (!axis.isConstant())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ const auto rank = input.info().shape().rank();
+ auto axis_value = axis.asScalar<int32_t>();
+ axis_value = axis_value < 0 ? axis_value + rank : axis_value;
+
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferArgMaxShape(input.info().shape(), axis_value, rank);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::BatchMatMul &op)
+{
+ const auto lhs_index = op.getInputs().at(ir::operation::BatchMatMul::Input::LHS);
+ const auto rhs_index = op.getInputs().at(ir::operation::BatchMatMul::Input::RHS);
+ const auto output_index = op.getOutputs().at(0);
+ const auto &lhs = _operands.at(lhs_index);
+ const auto &rhs = _operands.at(rhs_index);
+ auto &output = _operands.at(output_index);
+ auto new_shape = shape_inference::inferBatchMatMulShape(lhs.shape(), rhs.shape(), op.param());
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::BCQFullyConnected &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::BCQFullyConnected::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto cluster_idx{
+ op.getInputs().at(ir::operation::BCQFullyConnected::Input::WEIGHTS_CLUSTERS)};
+ const auto &cluster = _operands.at(cluster_idx);
+
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ auto cluster_buf = reinterpret_cast<const int32_t *>(cluster.data()->base());
+ assert(cluster_buf);
+
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferBCQFullyConnectedShape(
+ input.info().shape(), cluster.info().shape(), cluster_buf);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::BCQGather &op)
+{
+ const auto indices_idx{op.getInputs().at(ir::operation::BCQGather::Input::INDICES)};
+ const auto &indices = _operands.at(indices_idx);
+
+ const auto input_binary_idx{op.getInputs().at(ir::operation::BCQGather::Input::INPUT_BINARY)};
+ const auto &input_binary = _operands.at(input_binary_idx);
+
+ const auto cluster_idx{op.getInputs().at(ir::operation::BCQGather::Input::INPUT_CLUSTERS)};
+ const auto &cluster = _operands.at(cluster_idx);
+
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ auto cluster_buf = reinterpret_cast<const int32_t *>(cluster.data()->base());
+ assert(cluster_buf);
+
+ auto rank = input_binary.shape().rank();
+
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferBCQGatherShape(
+ indices.info().shape(), cluster.info().shape(), cluster_buf, rank, op.param());
+
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::BinaryArithmetic &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::BinaryArithmetic::Input::LHS),
+ op.getInputs().at(ir::operation::BinaryArithmetic::Input::RHS));
+}
+
+void StaticShapeInferer::visit(const ir::operation::BroadcastTo &op)
+{
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ const auto shape_idx{op.getInputs().at(ir::operation::BroadcastTo::Input::SHAPE)};
+ const auto &shape = _operands.at(shape_idx);
+
+ if (!shape.isConstant())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ // assert(shape.typeInfo().type() == ir::DataType::INT32);
+ auto shape_buffer = reinterpret_cast<const int32_t *>(shape.data()->base());
+
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferBroadcastToShape(shape.info().shape(), shape_buffer);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Comparison &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::Comparison::Input::INPUT0),
+ op.getInputs().at(ir::operation::Comparison::Input::INPUT1));
+}
+
+void StaticShapeInferer::visit(const ir::operation::Concat &op)
+{
+ const auto input_count = op.getInputs().size();
+
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ shape_inference::Shapes input_shapes;
+ for (uint32_t i = 0; i < input_count; i++)
+ {
+ const auto input_idx{op.getInputs().at(i)};
+ const auto &input = _operands.at(input_idx);
+ input_shapes.emplace_back(input.shape());
+ }
+
+ ir::Shape out_shape = shape_inference::inferConcatShape(input_shapes, op.param());
+
+ // re-sizing output shape
+ output.info().shape(out_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Conv2D &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Conv2D::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+ const auto ker_idx{op.getInputs().at(ir::operation::Conv2D::Input::KERNEL)};
+ const auto &ker = _operands.at(ker_idx);
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // re-sizing output shape
+ ir::Shape new_shape =
+ shape_inference::inferConv2DShape(input.info().shape(), ker.info().shape(), op.param());
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::ElementwiseActivation &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::ElementwiseActivation::Input::INPUT));
+}
+
+void StaticShapeInferer::visit(const ir::operation::ElementwiseBinary &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::ElementwiseBinary::Input::LHS),
+ op.getInputs().at(ir::operation::ElementwiseBinary::Input::RHS));
+}
+
+void StaticShapeInferer::visit(const ir::operation::ElementwiseUnary &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::ElementwiseUnary::Input::INPUT));
+}
+
+void StaticShapeInferer::visit(const ir::operation::ExpandDims &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::ExpandDims::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+ const auto axis_idx{op.getInputs().at(ir::operation::ExpandDims::Input::AXIS)};
+ const auto &axis = _operands.at(axis_idx);
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ if (!axis.isConstant())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ // even when axis is constant, output shape should be recalculated since user might call
+ // nnfw_set_input_tensorinfo(input, some_new_shape)
+ auto axis_buf = reinterpret_cast<const int32_t *>(axis.data()->base());
+ assert(axis_buf);
+
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferExpandDimsShape(input.info().shape(), axis_buf[0]);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Fill &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Fill::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ if (!input.isConstant())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ assert(input.typeInfo().type() == ir::DataType::INT32);
+
+ auto input_buf = reinterpret_cast<const int32_t *>(input.data()->base());
+ assert(input_buf);
+
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferFillShape(input.info().shape(), input_buf);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::FullyConnected &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::FullyConnected::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto ker_idx{op.getInputs().at(ir::operation::FullyConnected::Input::WEIGHT)};
+ const auto &ker = _operands.at(ker_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+ // re-sizing output shape
+ ir::Shape new_shape =
+ shape_inference::inferFullyConnectedShape(input.info().shape(), ker.info().shape());
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::FusedBatchNorm &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::FusedBatchNorm::Input::INPUT));
+}
+
+void StaticShapeInferer::visit(const ir::operation::Gather &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Gather::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ const auto indices_idx{op.getInputs().at(ir::operation::Gather::Input::INDICES)};
+ const auto &indices = _operands.at(indices_idx);
+ const auto rank = input.info().shape().rank();
+ const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
+
+ assert(0 <= axis && axis < rank);
+
+ // re-sizing output shape
+ ir::Shape new_shape =
+ shape_inference::inferGatherShape(input.info().shape(), indices.info().shape(), axis, rank);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::If &op)
+{
+ auto &then_graph = _lowered_subgs.at(op.param().then_subg_index)->graph();
+ auto &else_graph = _lowered_subgs.at(op.param().else_subg_index)->graph();
+ const std::vector<ir::OperandIndex> inputs{op.getInputs().begin() + 1, op.getInputs().end()};
+ const auto &outputs = op.getOutputs();
+
+ // re-sizing input shapes of then subgraph
+ const auto &then_inputs = then_graph.getInputs();
+ assert(inputs.size() == then_inputs.size());
+ for (size_t i = 0; i < inputs.size(); ++i)
+ {
+ auto &then_input = then_graph.operands().at(then_inputs.at(i));
+ if (_operands.at(inputs.at(i)).info().isDynamic())
+ {
+ then_input.info().setDynamic();
+ }
+ else
+ {
+ auto new_shape = _operands.at(inputs.at(i)).info().shape();
+ then_input.info().shape(new_shape);
+ }
+ }
+
+ // re-sizing input shapes of else subgraph
+ const auto &else_inputs = else_graph.getInputs();
+ assert(inputs.size() == else_inputs.size());
+ for (size_t i = 0; i < inputs.size(); ++i)
+ {
+ auto &else_input = else_graph.operands().at(else_inputs.at(i));
+ if (_operands.at(inputs.at(i)).info().isDynamic())
+ {
+ else_input.info().setDynamic();
+ }
+ else
+ {
+ const auto &new_shape = _operands.at(inputs.at(i)).info().shape();
+ else_input.info().shape(new_shape);
+ }
+ }
+
+ // re-sizing operands of then subgraph
+ StaticShapeInferer then_inferer(op.param().then_subg_index, _lowered_subgs);
+ _lowered_subgs.at(op.param().then_subg_index)
+ ->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ bool has_dynamic_tensor = then_inferer.infer(op_seq);
+ op_seq.has_dynamic_tensor(has_dynamic_tensor);
+ });
+
+ // re-sizing operands of else subgraph
+ StaticShapeInferer else_inferer(op.param().else_subg_index, _lowered_subgs);
+ _lowered_subgs.at(op.param().else_subg_index)
+ ->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ bool has_dynamic_tensor = else_inferer.infer(op_seq);
+ op_seq.has_dynamic_tensor(has_dynamic_tensor);
+ });
+
+ // re-sizing output shapes
+ const auto &then_outputs = _lowered_subgs.at(op.param().then_subg_index)->graph().getOutputs();
+ const auto &else_outputs = _lowered_subgs.at(op.param().else_subg_index)->graph().getOutputs();
+ assert(outputs.size() == then_outputs.size());
+ assert(outputs.size() == else_outputs.size());
+ for (size_t i = 0; i < outputs.size(); ++i)
+ {
+ const auto &then_output = then_graph.operands().at(then_outputs.at(i));
+ const auto &else_output = else_graph.operands().at(else_outputs.at(i));
+ auto &output = _operands.at(outputs.at(i));
+ if (!then_output.info().isDynamic() && !else_output.info().isDynamic() &&
+ then_output.shape() == else_output.shape())
+ {
+ output.info().shape(then_output.shape());
+ }
+ else
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ }
+ }
+}
+
+void StaticShapeInferer::visit(const ir::operation::L2Normalization &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::L2Normalization::Input::INPUT));
+}
+
+void StaticShapeInferer::visit(const ir::operation::LSTM &op)
+{
+ const auto output_index{op.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)};
+ auto &output = _operands.at(output_index);
+
+ const auto output_state_out_index{
+ op.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)};
+
+ const auto cell_state_out_index{op.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)};
+
+ const auto scratch_buffer_index{op.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)};
+
+ if (output.info().isDynamic() || (_operands.exist(output_state_out_index) &&
+ _operands.at(output_state_out_index).info().isDynamic()) ||
+ (_operands.exist(cell_state_out_index) &&
+ _operands.at(cell_state_out_index).info().isDynamic()) ||
+ (_operands.exist(scratch_buffer_index) &&
+ _operands.at(scratch_buffer_index).info().isDynamic()))
+ return;
+
+ const auto input_index{op.getInputs().at(ir::operation::LSTM::Input::INPUT)};
+ const auto &input = _operands.at(input_index);
+
+ const auto input_to_output_weights_index{
+ op.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)};
+ const auto &input_to_output_weights = _operands.at(input_to_output_weights_index);
+
+ const auto recurrent_to_output_weights_index{
+ op.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS)};
+ const auto &recurrent_to_output_weights = _operands.at(recurrent_to_output_weights_index);
+
+ // re-sizing outputs
+ const int n_batch = (input.shape().rank() == 3 && op.param().time_major) ? input.shape().dim(1)
+ : input.shape().dim(0);
+ const int n_cell = input_to_output_weights.shape().dim(0);
+ const int n_output = recurrent_to_output_weights.shape().dim(1);
+ if (input.shape().rank() == 3)
+ {
+ if (op.param().time_major)
+ output.info().shape(ir::Shape{input.shape().dim(0), n_batch, n_output});
+ else
+ output.info().shape(ir::Shape{n_batch, input.shape().dim(1), n_output});
+ }
+ else
+ {
+ assert(input.shape().rank() == 2);
+ output.info().shape(ir::Shape{n_batch, n_output});
+ }
+
+ if (_operands.exist(output_state_out_index))
+ {
+ auto &output_state_out = _operands.at(output_state_out_index);
+ output_state_out.info().shape(ir::Shape{n_batch, n_output});
+ }
+
+ if (_operands.exist(cell_state_out_index))
+ {
+ auto &cell_state_out = _operands.at(cell_state_out_index);
+ cell_state_out.info().shape(ir::Shape{n_batch, n_cell});
+ }
+
+ if (_operands.exist(scratch_buffer_index))
+ {
+ auto &scratch_buffer = _operands.at(scratch_buffer_index);
+
+ const auto input_to_input_weights_index{
+ op.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)};
+ const auto recurrent_to_input_weights_index{
+ op.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)};
+
+ bool has_input_to_input_weights =
+ _operands.at(input_to_input_weights_index).shape().dim(0) != 0 &&
+ _operands.at(input_to_input_weights_index).shape().dim(1) != 0;
+ bool has_recurrent_to_input_weights =
+ _operands.at(recurrent_to_input_weights_index).shape().dim(0) != 0 &&
+ _operands.at(recurrent_to_input_weights_index).shape().dim(1) != 0;
+
+ // NOTE The cell_to_input_weights do not exist in non-peephole although regular LSTM(non-CIFG).
+ // true: no CIFG
+ // false: CIFG
+ bool has_cifg_param = has_input_to_input_weights && has_recurrent_to_input_weights;
+ if (has_cifg_param)
+ {
+ scratch_buffer.info().shape(ir::Shape{n_batch, n_cell * 4});
+ }
+ else
+ {
+ scratch_buffer.info().shape(ir::Shape{n_batch, n_cell * 3});
+ }
+ }
+}
+
+void StaticShapeInferer::visit(const ir::operation::MatrixBandPart &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::MatrixBandPart::Input::INPUT));
+}
+
+void StaticShapeInferer::visit(const ir::operation::OneHot &op)
+{
+ const auto indice_idx{op.getInputs().at(ir::operation::OneHot::Input::INDICES)};
+ const auto &indice = _operands.at(indice_idx);
+ const auto depth_idx{op.getInputs().at(ir::operation::OneHot::Input::DEPTH)};
+ const auto &depth = _operands.at(depth_idx);
+
+ const auto axis = op.param().axis;
+
+ auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ if (!depth.isConstant())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ const auto *depth_buf = reinterpret_cast<const int32_t *>(depth.data()->base());
+ assert(depth_buf);
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferOnehotShape(indice.info().shape(), *depth_buf, axis);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Pack &op)
+{
+ const auto input_idx{op.getInputs().at(0)};
+ const auto &input = _operands.at(input_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ const auto rank = input.shape().rank() + 1;
+ const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
+ const auto num = op.param().num;
+
+ assert(0 <= axis && axis < rank);
+
+ // re-sizing output shape
+ ir::Shape new_shape = shape_inference::inferPackShape(input.info().shape(), axis, rank, num);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Pad &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Pad::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto pad_idx{op.getInputs().at(ir::operation::Pad::Input::PAD)};
+ const auto &pad = _operands.at(pad_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // if pad is not constant, output also becomes dynamic
+ if (!pad.isConstant())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ // re-sizing output shape
+ const auto new_shape = shape_inference::inferPadShape(
+ input.shape(), reinterpret_cast<const int32_t *>(pad.data()->base()),
+ pad.shape().num_elements());
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Permute &op)
+{
+ const auto input_idx{op.getInputs().at(0)};
+ const auto &input = _operands.at(input_idx);
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // re-sizing output shape
+ // Permute is a special operation that layouts of input/output may be different on backend
+ // However, it is not applied here, so input/output have the same layout of frontend. Because
+ // "ExecutorFactory" would convert shape of input/output accoding to the layouts when registering
+ // operand info to "TensorBuilder" after calling "StaticShapeInferer"
+ const auto new_shape = input.info().shape();
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Pow &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::Pow::Input::LHS),
+ op.getInputs().at(ir::operation::Pow::Input::RHS));
+}
+
+void StaticShapeInferer::visit(const ir::operation::Range &op)
+{
+ const auto start_idx{op.getInputs().at(ir::operation::Range::Input::START)};
+ const auto limit_idx{op.getInputs().at(ir::operation::Range::Input::LIMIT)};
+ const auto delta_idx{op.getInputs().at(ir::operation::Range::Input::DELTA)};
+ const auto &start_op = _operands.at(start_idx);
+ const auto &limit_op = _operands.at(limit_idx);
+ const auto &delta_op = _operands.at(delta_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ ir::Shape new_shape;
+ if (start_op.isConstant() && limit_op.isConstant() && delta_op.isConstant())
+ {
+ assert(start_op.typeInfo().type() == limit_op.typeInfo().type() &&
+ start_op.typeInfo().type() == delta_op.typeInfo().type());
+ if (output.typeInfo().type() == ir::DataType::FLOAT32)
+ {
+ new_shape = shape_inference::inferRangeShape<float>(
+ start_op.asScalar<float>(), limit_op.asScalar<float>(), delta_op.asScalar<float>());
+ }
+ else if (output.typeInfo().type() == ir::DataType::INT32)
+ {
+ new_shape = shape_inference::inferRangeShape<int32_t>(
+ start_op.asScalar<int32_t>(), limit_op.asScalar<int32_t>(), delta_op.asScalar<int32_t>());
+ }
+ assert(output.shape() == new_shape);
+ }
+ else
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ }
+}
+
+void StaticShapeInferer::visit(const ir::operation::Reduce &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Reduce::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto axes_idx{op.getInputs().at(ir::operation::Reduce::Input::AXES)};
+ const auto &axes = _operands.at(axes_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ std::vector<int32_t> axes_vec;
+ for (size_t i = 0; i < axes.shape().num_elements(); ++i)
+ {
+ switch (axes.typeInfo().type())
+ {
+ case ir::DataType::INT32:
+ {
+ axes_vec.emplace_back(reinterpret_cast<const int32_t *>(axes.data()->base())[i]);
+ break;
+ }
+ case ir::DataType::INT64:
+ {
+ axes_vec.emplace_back(reinterpret_cast<const int64_t *>(axes.data()->base())[i]);
+ break;
+ }
+ default:
+ throw std::runtime_error("StaticShapeInferer " + op.name() + ": Not supported data type");
+ break;
+ }
+ }
+ const auto keep_dims = op.param().keep_dims;
+
+ // re-sizing output shape
+ ir::Shape new_shape =
+ shape_inference::inferReduceShape(input.info().shape(), axes_vec, keep_dims);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Reshape &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Reshape::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // New shape is given by second input tensor
+ if (op.getInputs().size() == 2)
+ {
+ // Let's check the second input
+ const auto shape_idx{op.getInputs().at(ir::operation::Reshape::Input::SHAPE)};
+ const auto &shape = _operands.at(shape_idx);
+
+ if (shape.isConstant())
+ {
+ const auto *shape_buf = reinterpret_cast<const int32_t *>(shape.data()->base());
+ assert(shape_buf);
+
+ ir::Shape new_shape = shape_inference::inferReshapeShape(
+ shape_buf, shape.shape().num_elements(), input.shape().num_elements());
+
+ // if shape is from Const, TFLC put the shape of output into tensor
+ if (new_shape != output.shape())
+ {
+ // change on output shape
+ output.info().shape(new_shape);
+ }
+ }
+ else
+ {
+ // if shape is NOT Const, set output shape to be dynamic_
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ }
+ }
+ // New shape is given by option
+ else if (op.param().new_shape.size() != 0)
+ {
+ // Let's check the new_shape option
+ auto shape = op.param().new_shape;
+ ir::Shape new_shape = shape_inference::inferReshapeShape(shape.data(), shape.size(),
+ input.shape().num_elements());
+
+ if (new_shape != output.shape())
+ {
+ // change on output shape
+ output.info().shape(new_shape);
+ }
+ }
+ else
+ {
+ throw std::runtime_error("Reshape: new shape is missing");
+ }
+}
+
+void StaticShapeInferer::visit(const ir::operation::ResizeBilinear &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::ResizeBilinear::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ int32_t height_out, width_out;
+ if (op.getInputs().size() == 2)
+ {
+ auto &size = _operands.at(op.getInputs().at(ir::operation::ResizeBilinear::Input::SIZE));
+ if (!size.isConstant())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+ const auto size_v = size.asVector<std::int32_t>();
+ height_out = size_v[0];
+ width_out = size_v[1];
+ }
+ else
+ {
+ height_out = op.param().height_out;
+ width_out = op.param().width_out;
+ }
+
+ // Shape inferencing logic based on Params
+ ir::Shape new_shape =
+ shape_inference::inferResizeBilinearShape(input.shape(), height_out, width_out);
+
+ // if size_op is from Const, TFLC put the shape of output into tensor
+ if (new_shape != output.shape())
+ {
+ // change on output shape
+ output.info().shape(new_shape);
+ }
+}
+
+void StaticShapeInferer::visit(const ir::operation::Reverse &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::Reverse::Input::INPUT));
+}
+
+void StaticShapeInferer::visit(const ir::operation::Select &op)
+{
+ const auto input_cond_idx{op.getInputs().at(ir::operation::Select::Input::CONDITION)};
+ const auto &input_cond = _operands.at(input_cond_idx);
+
+ const auto input_true_idx{op.getInputs().at(ir::operation::Select::Input::INPUT_TRUE)};
+ const auto &input_true = _operands.at(input_true_idx);
+
+ const auto input_false_idx{op.getInputs().at(ir::operation::Select::Input::INPUT_FALSE)};
+ const auto &input_false = _operands.at(input_false_idx);
+
+ auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // Select output shpae
+ ir::Shape new_shape = shape_inference::inferSelectShape(
+ input_cond.info().shape(), input_true.info().shape(), input_false.info().shape());
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Shape &op)
+{
+ const auto input_idx{op.getInputs().at(0)};
+ const auto &input = _operands.at(input_idx);
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // re-sizing output shape
+ ir::Shape output_shape;
+ output_shape.append(input.info().shape().rank());
+
+ output.info().shape(output_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Slice &op)
+{
+ const auto input_index{op.getInputs().at(ir::operation::Slice::Input::INPUT)};
+ const auto &input = _operands.at(input_index);
+ const auto begins_index{op.getInputs().at(ir::operation::Slice::Input::BEGINS)};
+ const auto &begins = _operands.at(begins_index);
+ const auto sizes_index{op.getInputs().at(ir::operation::Slice::Input::SIZES)};
+ const auto &sizes = _operands.at(sizes_index);
+ const auto output_index = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_index);
+
+ // Whether input is constant or not does not affect whether output is dynamic or not
+ if (!(begins.isConstant() && sizes.isConstant()))
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ auto begins_buf = reinterpret_cast<const int32_t *>(begins.data()->base());
+ auto sizes_buf = reinterpret_cast<const int32_t *>(sizes.data()->base());
+
+ ir::Shape new_shape =
+ shape_inference::inferSliceShape(input.info().shape(), begins_buf, sizes_buf);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Softmax &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::Softmax::Input::INPUT));
+}
+
+void StaticShapeInferer::visit(const ir::operation::SpaceToBatchND &op)
+{
+ const auto output_index = op.getOutputs().at(0);
+ const auto input_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)};
+ const auto block_shape_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)};
+ const auto padding_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)};
+
+ ir::Operand &output = _operands.at(output_index);
+ const auto &input = _operands.at(input_idx);
+ const auto &block_shape = _operands.at(block_shape_idx);
+ const auto &padding = _operands.at(padding_idx);
+
+ // Whether input is constant or not does not affect whether output is dynamic or not
+ if (!(block_shape.isConstant() && padding.isConstant()))
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ auto input_shape = input.info().shape();
+ auto block_shape_shape = block_shape.info().shape();
+ auto padding_shape = padding.info().shape();
+
+ auto block_shape_data = reinterpret_cast<const int32_t *>(block_shape.data()->base());
+ auto padding_data = reinterpret_cast<const int32_t *>(padding.data()->base());
+
+ ir::Shape new_shape = shape_inference::inferSpaceToBatchNDShape(
+ input_shape, block_shape_shape, padding_shape, block_shape_data, padding_data);
+
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Split &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Split::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto axis_idx{op.getInputs().at(ir::operation::Split::Input::AXIS)};
+ const auto &axis = _operands.at(axis_idx);
+
+ auto outputs = op.getOutputs();
+ if (!axis.isConstant())
+ {
+ for (auto output_idx : outputs)
+ {
+ ir::Operand &output = _operands.at(output_idx);
+ output.info().setDynamic();
+ }
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ const auto num_splits = op.param().num_splits;
+
+ const auto rank = input.info().shape().rank();
+ auto axis_value = axis.asScalar<int32_t>();
+ axis_value = axis_value < 0 ? axis_value + rank : axis_value;
+
+ assert(0 <= axis_value && axis_value < rank);
+
+ ir::Shape new_shape =
+ shape_inference::inferSplitShape(input.info().shape(), axis_value, num_splits);
+ for (auto output_idx : outputs)
+ {
+ ir::Operand &output = _operands.at(output_idx);
+ output.info().shape(new_shape);
+ }
+}
+
+void StaticShapeInferer::visit(const ir::operation::SquaredDifference &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::SquaredDifference::Input::LHS),
+ op.getInputs().at(ir::operation::SquaredDifference::Input::RHS));
+}
+
+void StaticShapeInferer::visit(const ir::operation::Squeeze &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Squeeze::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ // Squeeze output shpae
+ ir::Shape new_shape = shape_inference::inferSqueezeShape(input.info().shape(), op.param());
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::StridedSlice &op)
+{
+ const auto input_index{op.getInputs().at(ir::operation::StridedSlice::Input::INPUT)};
+ const auto &input = _operands.at(input_index);
+ const auto starts_index{op.getInputs().at(ir::operation::StridedSlice::Input::STARTS)};
+ const auto &starts = _operands.at(starts_index);
+ const auto ends_index{op.getInputs().at(ir::operation::StridedSlice::Input::ENDS)};
+ const auto &ends = _operands.at(ends_index);
+ const auto strides_index{op.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)};
+ const auto &strides = _operands.at(strides_index);
+ const auto output_index = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_index);
+
+ if (!(starts.isConstant() && ends.isConstant() && strides.isConstant()))
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ const auto begin_mask = op.param().begin_mask;
+ const auto end_mask = op.param().end_mask;
+ const auto shrink_axis_mask = op.param().shrink_axis_mask;
+ const auto rank = input.info().shape().rank();
+
+ auto starts_buf = reinterpret_cast<const uint32_t *>(starts.data()->base());
+ auto ends_buf = reinterpret_cast<const uint32_t *>(ends.data()->base());
+ auto strides_buf = reinterpret_cast<const uint32_t *>(strides.data()->base());
+
+ auto op_params = shape_inference::buildStridedSliceParams(
+ starts_buf, ends_buf, strides_buf, begin_mask, end_mask, shrink_axis_mask, rank);
+
+ ir::Shape new_shape =
+ shape_inference::inferStridedSliceShape(input.info().shape(), op_params, rank);
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Tile &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Tile::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto multiplier_idx{op.getInputs().at(ir::operation::Tile::Input::MULTIPLES)};
+ const auto &multiplier = _operands.at(multiplier_idx);
+
+ const auto output_idx = op.getOutputs().at(0);
+ ir::Operand &output = _operands.at(output_idx);
+
+ if (!multiplier.isConstant())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ auto multiplier_buffer = reinterpret_cast<const int32_t *>(multiplier.data()->base());
+ assert(multiplier_buffer);
+
+ // re-sizing output shape
+ auto new_shape = shape_inference::inferTileShape(input.info().shape(), multiplier_buffer,
+ multiplier.shape().num_elements());
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Transpose &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Transpose::Input::INPUT)};
+ const auto &input = _operands.at(input_idx);
+
+ const auto perm_idx{op.getInputs().at(ir::operation::Transpose::Input::PERMUTATION)};
+ const auto &perm = _operands.at(perm_idx);
+
+ // perm.shape() != ir::Shape{0} means that perm is (n-1...0)
+ // TODO This condition changes to perm.num_elements() == 0
+ const auto is_regular_transpose = perm.shape() == ir::Shape{0};
+
+ // get mutable output operand
+ const auto output_idx = op.getOutputs().at(0);
+ auto &output = _operands.at(output_idx);
+ if (!perm.isConstant() && !is_regular_transpose)
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ ir::Shape new_shape;
+ if (is_regular_transpose)
+ {
+ // Call by (n-1...0)
+ new_shape = shape_inference::inferTransposeShape(input.info().shape(), nullptr, 0);
+ }
+ else
+ {
+ // Check rank
+ if (input.info().shape().rank() != static_cast<int>(perm.info().shape().num_elements()))
+ {
+ throw std::runtime_error("StaticShapeInferer failed, bad rank size: " +
+ std::to_string(perm.info().shape().num_elements()));
+ }
+
+ // set output shape, based on input and params
+ const auto perm_buf = reinterpret_cast<const int32_t *>(perm.data()->base());
+ new_shape = shape_inference::inferTransposeShape(input.info().shape(), perm_buf,
+ perm.shape().num_elements());
+ }
+ output.info().shape(new_shape);
+}
+
+void StaticShapeInferer::visit(const ir::operation::Unpack &op)
+{
+ const auto input_idx{op.getInputs().at(0)};
+ const auto &input = _operands.at(input_idx);
+ const auto num = op.param().num;
+ const auto rank = input.shape().rank();
+ const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
+
+ assert(axis < rank);
+ if (axis < 0)
+ {
+ for (int out_tensor_idx = 0; out_tensor_idx < num; out_tensor_idx++)
+ {
+ const auto output_idx = op.getOutputs().at(out_tensor_idx);
+ ir::Operand &output = _operands.at(output_idx);
+ output.info().setDynamic();
+ }
+ _return_has_dynamic_tensor = true;
+ return;
+ }
+
+ ir::Shape new_shape = shape_inference::inferUnpackShape(input.info().shape(), axis, rank);
+
+ // re-sizing output shape
+ for (int out_tensor_idx = 0; out_tensor_idx < num; out_tensor_idx++)
+ {
+ const auto output_idx = op.getOutputs().at(out_tensor_idx);
+ ir::Operand &output = _operands.at(output_idx);
+ output.info().shape(new_shape);
+ }
+}
+
+void StaticShapeInferer::visit(const ir::operation::While &op)
+{
+ auto &cond_graph = _lowered_subgs.at(op.param().cond_subg_index)->graph();
+ auto &body_graph = _lowered_subgs.at(op.param().body_subg_index)->graph();
+ const auto inputs = op.getInputs();
+ const auto &outputs = op.getOutputs();
+
+ // re-sizing input shapes of then subgraph
+ const auto &cond_inputs = cond_graph.getInputs();
+ assert(inputs.size() == cond_inputs.size());
+ for (size_t i = 0; i < inputs.size(); ++i)
+ {
+ const auto &input = _operands.at(inputs.at(i));
+ auto &cond_input = cond_graph.operands().at(cond_inputs.at(i));
+ if (input.info().isDynamic())
+ {
+ cond_input.info().setDynamic();
+ }
+ else
+ {
+ auto new_shape = input.info().shape();
+ cond_input.info().shape(new_shape);
+ }
+ }
+
+ // re-sizing input shapes of body subgraph
+ const auto &body_inputs = body_graph.getInputs();
+ assert(cond_inputs.size() == body_inputs.size());
+ for (size_t i = 0; i < cond_inputs.size(); ++i)
+ {
+ const auto &cond_input = cond_graph.operands().at(cond_inputs.at(i));
+ auto &body_input = body_graph.operands().at(body_inputs.at(i));
+ if (cond_input.info().isDynamic())
+ {
+ body_input.info().setDynamic();
+ }
+ else
+ {
+ const auto &new_shape = cond_input.info().shape();
+ body_input.info().shape(new_shape);
+ }
+ }
+
+ // re-sizing operands of body subgraph
+ StaticShapeInferer body_inferer(op.param().body_subg_index, _lowered_subgs);
+ _lowered_subgs.at(op.param().body_subg_index)
+ ->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ bool has_dynamic_tensor = body_inferer.infer(op_seq);
+ op_seq.has_dynamic_tensor(has_dynamic_tensor);
+ });
+
+ // Check whether while operation's shapes are predictable
+ // If any of shape of body outputs and cond inputs are different, non-constant operands would be
+ // set to dynamic
+ bool check_unpredictable_dynamic = false;
+ const auto &body_outputs = body_graph.getOutputs();
+ assert(body_outputs.size() == cond_inputs.size());
+ for (size_t i = 0; i < body_outputs.size(); ++i)
+ {
+ const auto &body_output = body_graph.operands().at(body_outputs.at(i));
+ auto &cond_input = cond_graph.operands().at(cond_inputs.at(i));
+ if ((cond_input.info().isDynamic() != body_output.info().isDynamic()) ||
+ (cond_input.shape() != body_output.shape()))
+ {
+ check_unpredictable_dynamic = true;
+ break;
+ }
+ }
+
+ if (check_unpredictable_dynamic)
+ {
+ // Set inputs of body subgraph
+ for (const auto &input_index : body_inputs)
+ {
+ auto &input = body_graph.operands().at(input_index);
+ if (!input.isConstant())
+ {
+ input.info().setDynamic();
+ }
+ }
+
+ // Set inputs of cond subgraph
+ for (const auto &input_index : cond_inputs)
+ {
+ auto &input = cond_graph.operands().at(input_index);
+ if (!input.isConstant())
+ {
+ input.info().setDynamic();
+ }
+ }
+
+ // Set non-constant operands of body subgraph to dynamic
+ StaticShapeInferer body_inferer(op.param().body_subg_index, _lowered_subgs);
+ _lowered_subgs.at(op.param().body_subg_index)
+ ->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ bool has_dynamic_tensor = body_inferer.infer(op_seq);
+ op_seq.has_dynamic_tensor(has_dynamic_tensor);
+ });
+ }
+
+ // re-sizing operands of cond subgraph
+ // If check_unpredictable_dynamic is true, non-constant operands of cond subgraph would be set to
+ // dynamic
+ StaticShapeInferer cond_inferer(op.param().cond_subg_index, _lowered_subgs);
+ _lowered_subgs.at(op.param().cond_subg_index)
+ ->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ bool has_dynamic_tensor = cond_inferer.infer(op_seq);
+ op_seq.has_dynamic_tensor(has_dynamic_tensor);
+ });
+
+ // re-sizing outputs of while operation
+ // If check_unpredictable_dynamic is true, outputs of while operation would be set to dynamic
+ assert(cond_inputs.size() == outputs.size());
+ for (size_t i = 0; i < cond_inputs.size(); ++i)
+ {
+ const auto &cond_input = cond_graph.operands().at(cond_inputs.at(i));
+ auto &output = _operands.at(outputs.at(i));
+ if (cond_input.info().isDynamic())
+ {
+ output.info().setDynamic();
+ _return_has_dynamic_tensor = true;
+ }
+ else
+ {
+ const auto new_shape = cond_input.info().shape();
+ output.info().shape(new_shape);
+ }
+ }
+}
+
+} // namespace compiler
+
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/TensorBuilders.h b/runtime/onert/core/src/compiler/TensorBuilders.h
new file mode 100644
index 000000000..3b0360b4b
--- /dev/null
+++ b/runtime/onert/core/src/compiler/TensorBuilders.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_TENSOR_BUILDERS_H__
+#define __ONERT_COMPILER_TENSOR_BUILDERS_H__
+
+#include <unordered_set>
+#include <memory>
+#include "backend/BackendContext.h"
+#include "backend/Backend.h"
+#include "backend/controlflow/Config.h"
+#include "backend/controlflow/TensorBuilder.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+class TensorBuilders
+{
+public:
+ TensorBuilders() = default;
+
+ TensorBuilders(const onert::backend::BackendContexts &backend_contexts, bool include_controlflow)
+ {
+ for (const auto &e : backend_contexts)
+ {
+ if (e.first->config()->id() == backend::controlflow::Config::ID)
+ {
+ _cf_tensor_builder = std::dynamic_pointer_cast<backend::controlflow::TensorBuilder>(
+ e.second->tensor_builder);
+ if (include_controlflow)
+ _tensor_builders.insert(e.second->tensor_builder);
+ }
+ else
+ {
+ _tensor_builders.insert(e.second->tensor_builder);
+ }
+ }
+ }
+
+ std::unordered_set<std::shared_ptr<onert::backend::ITensorBuilder>>::const_iterator begin() const
+ {
+ return _tensor_builders.cbegin();
+ }
+ std::unordered_set<std::shared_ptr<onert::backend::ITensorBuilder>>::const_iterator end() const
+ {
+ return _tensor_builders.cend();
+ }
+
+ std::shared_ptr<backend::controlflow::TensorBuilder> getControlflowTensorBuilder() const
+ {
+ return _cf_tensor_builder;
+ }
+
+private:
+ std::unordered_set<std::shared_ptr<backend::ITensorBuilder>> _tensor_builders;
+ std::shared_ptr<backend::controlflow::TensorBuilder> _cf_tensor_builder;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_TENSOR_BUILDERS_H__
diff --git a/runtime/onert/core/src/compiler/TensorRegistries.h b/runtime/onert/core/src/compiler/TensorRegistries.h
new file mode 100644
index 000000000..e42225cbf
--- /dev/null
+++ b/runtime/onert/core/src/compiler/TensorRegistries.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_TENSOR_REGISTRIES_H__
+#define __ONERT_COMPILER_TENSOR_REGISTRIES_H__
+
+#include <unordered_set>
+#include <memory>
+#include "backend/BackendContext.h"
+#include "backend/Backend.h"
+#include "backend/controlflow/Config.h"
+#include "backend/controlflow/TensorBuilder.h"
+#include "backend/controlflow/TensorRegistry.h"
+
+namespace onert
+{
+namespace compiler
+{
+
+class TensorRegistries
+{
+public:
+ TensorRegistries() = default;
+
+ TensorRegistries(const onert::backend::BackendContexts &backend_contexts,
+ bool include_controlflow)
+ {
+ for (const auto &e : backend_contexts)
+ {
+ auto tensor_reg = e.second->tensor_registry;
+ if (e.first->config()->id() == backend::controlflow::Config::ID)
+ {
+ _cf_tensor_reg =
+ std::dynamic_pointer_cast<backend::controlflow::TensorRegistry>(tensor_reg);
+ if (include_controlflow)
+ _tensor_regs.insert(tensor_reg);
+ }
+ else
+ {
+ _tensor_regs.insert(tensor_reg);
+ }
+ }
+ }
+
+ std::unordered_set<std::shared_ptr<onert::backend::ITensorRegistry>>::const_iterator begin() const
+ {
+ return _tensor_regs.cbegin();
+ }
+ std::unordered_set<std::shared_ptr<onert::backend::ITensorRegistry>>::const_iterator end() const
+ {
+ return _tensor_regs.cend();
+ }
+
+ std::shared_ptr<backend::controlflow::TensorRegistry> getControlflowTensorRegistry() const
+ {
+ return _cf_tensor_reg;
+ }
+
+ backend::ITensor *getITensor(ir::OperandIndex ind) const
+ {
+ for (auto &tensor_reg : _tensor_regs)
+ {
+ auto tensor = tensor_reg->getITensor(ind);
+ if (tensor)
+ return tensor;
+ }
+ return nullptr;
+ }
+
+private:
+ std::unordered_set<std::shared_ptr<backend::ITensorRegistry>> _tensor_regs;
+ std::shared_ptr<backend::controlflow::TensorRegistry> _cf_tensor_reg;
+};
+
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_TENSOR_REGISTRIES_H__
diff --git a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc
new file mode 100644
index 000000000..ef6240894
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConstantInsertionPass.h"
+
+#include "backend/Backend.h"
+#include <ir/Graph.h>
+#include <util/Utils.h>
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+void ConstantInsertionPass::callback(const ir::OperationIndex &node_index, ir::Operation &node)
+{
+ const auto &op_sequence_index = _lowered_graph.op_seqs().getOperation(node_index);
+ const auto op_seq_lower_info = _lowered_graph.getLowerInfo(op_sequence_index);
+ const auto backend = op_seq_lower_info->backend();
+ const auto layout = op_seq_lower_info->layout();
+ const auto factor = ir::operand::PermuteFactor{backend, layout};
+
+ for (const auto input : node.getInputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ auto &object = _graph.operands().at(input);
+
+ if (object.isConstant())
+ {
+ const auto key = ReplaceKey{input, factor};
+ if (_replace_operands_map.count(key) == 0)
+ {
+ ir::Operand new_object(object);
+ new_object.unsetDef();
+ // TODO Remove const_case
+ const_cast<ir::OperationIndexSet &>(new_object.getUses()).clear();
+ const auto new_index = _graph.operands().emplace(new_object);
+ _replace_operands_map[key] = new_index;
+ }
+
+ const auto replaced_input = _replace_operands_map[key];
+ // Update op_seq
+ if (_lowered_graph.op_seqs().at(op_sequence_index).getInputs().contains(input))
+ {
+ // All inputs of op_seq have the same PermuteFactor because those inputs are inputs of first
+ // operation
+ _lowered_graph.op_seqs().at(op_sequence_index).replaceInputs(input, replaced_input);
+ }
+
+ // Update the same inputs of a node at once because inputs of an operation have the same
+ // PermuteFactor
+ node.replaceInputs(input, replaced_input);
+
+ // Update operand
+ auto &replaced_object = _graph.operands().at(replaced_input);
+ replaced_object.insertUse(node_index);
+
+ // Remove this node from uses of origin operand
+ // Constant operand has no def.
+ assert(!object.getDef().valid());
+ object.removeUse(node_index);
+
+ // Remove origin operand
+ if (object.getUses().size() == 0)
+ _graph.removeOperand(input);
+ }
+ }
+
+ // Now this runtime does not support the node making output as constant
+ for (const auto &output : node.getOutputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ UNUSED_RELEASE(output);
+ assert(!_graph.operands().at(output).isConstant());
+ }
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h
new file mode 100644
index 000000000..052883c92
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_CONSTANT_INSERTION_PASS_H__
+#define __ONERT_COMPILER_PASS_CONSTANT_INSERTION_PASS_H__
+
+#include <ir/operand/PermuteFactor.h>
+#include <ir/Index.h>
+#include "LoweredOperationPass.h"
+#include <unordered_map>
+#include <utility>
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+class ConstantInsertionPass : public LoweredOperationPass
+{
+public:
+ using LoweredOperationPass::LoweredOperationPass;
+
+public:
+ std::string id() final { return "ConstantInsertionPass"; }
+
+public:
+ void callback(const ir::OperationIndex &index, ir::Operation &node) final;
+
+private:
+ struct ReplaceKey
+ {
+ ir::OperandIndex index;
+ ir::operand::PermuteFactor factor;
+
+ bool operator==(const ReplaceKey &other) const
+ {
+ return index == other.index && factor == other.factor;
+ }
+ };
+
+ /**
+ * @brief Structure that provides hash function of ReplaceKey
+ */
+ struct KeyHasher
+ {
+ std::size_t operator()(const ReplaceKey &key) const noexcept
+ {
+ using std::hash;
+ return hash<ir::OperandIndex>()(key.index) ^
+ (hash<ir::operand::PermuteFactor>()(key.factor) << 1);
+ }
+ };
+
+ std::unordered_map<ReplaceKey, ir::OperandIndex, KeyHasher> _replace_operands_map;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_CONSTANT_INSERTION_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc b/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc
new file mode 100644
index 000000000..1c1dbe0ee
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConstantLoweringPass.h"
+
+#include "backend/Backend.h"
+#include <ir/Graph.h>
+#include <ir/operand/PermuteFactor.h>
+#include <util/Utils.h>
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+void ConstantLoweringPass::callback(const ir::OperationIndex &node_index, ir::Operation &node)
+{
+ const auto &op_sequence_index = _lowered_graph.op_seqs().getOperation(node_index);
+ const auto op_seq_lower_info = _lowered_graph.getLowerInfo(op_sequence_index);
+ const auto backend = op_seq_lower_info->backend();
+ const auto layout = op_seq_lower_info->layout();
+ const auto factor = ir::operand::PermuteFactor{backend, layout};
+
+ // Now this runtime does not support the node making output of operation as constant
+ for (const auto input : node.getInputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED)
+ {
+ auto &object = _graph.operands().at(input);
+ if (object.isConstant())
+ {
+ // All constant operand are already assinged at each backend by ContantInsertionPass. So a
+ // constant has `def` and `use` as the same PermuteFactor
+ _lowered_graph.setLowerInfo(input, std::make_unique<ir::operand::LowerInfo>());
+ _lowered_graph.getLowerInfo(input)->addDefPermuteFactor(factor);
+ _lowered_graph.getLowerInfo(input)->addUsePermuteFactor(factor);
+ }
+ }
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.h b/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.h
new file mode 100644
index 000000000..e17d776d1
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_CONSTANT_LOWERING_PASS_H__
+#define __ONERT_COMPILER_PASS_CONSTANT_LOWERING_PASS_H__
+
+#include <ir/Index.h>
+#include "LoweredOperationPass.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+class ConstantLoweringPass : public LoweredOperationPass
+{
+public:
+ using LoweredOperationPass::LoweredOperationPass;
+
+public:
+ std::string id() final { return "ConstantLoweringPass"; }
+
+public:
+ void callback(const ir::OperationIndex &index, ir::Operation &node) final;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_CONSTANT_LOWERING_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc b/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc
new file mode 100644
index 000000000..c176f6ffb
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConstantOutputPass.h"
+
+#include "ir/Graph.h"
+#include "ir/operation/Permute.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+void ConstantOutputPass::callback(const ir::OperandIndex &ind, ir::Operand &obj)
+{
+ if (!_graph.getOutputs().contains(ind) || !obj.isConstant())
+ return;
+
+ auto permute_input_ind = _graph.addOperand(obj.shape(), obj.typeInfo());
+ auto &permute_input_obj = _graph.operands().at(permute_input_ind);
+
+ // Move the const data
+ permute_input_obj.data(obj.shareData());
+ obj.releaseData();
+ obj.info().setAsNonConst();
+
+ using ir::operation::Permute;
+ auto permute_obj = std::make_unique<Permute>(permute_input_ind, ind, Permute::Type::COPY);
+ auto permute_ind = _graph.operations().push(std::move(permute_obj));
+
+ permute_input_obj.insertUse(permute_ind);
+ obj.setDef(permute_ind);
+
+ // Make the operations that uses this operand to use the generated operand
+ auto orig_uses = obj.getUses();
+ for (auto use : orig_uses)
+ {
+ permute_input_obj.insertUse(use);
+ obj.removeUse(use);
+ _graph.operations().at(use).replaceInputs(ind, permute_input_ind);
+ }
+
+ VERBOSE(ConstantOutputPass) << "Permute Op inserted for a constant ouput, node index : "
+ << permute_ind << std::endl;
+ VERBOSE(ConstantOutputPass) << " - Input (inserted) Operand : " << permute_input_ind
+ << std::endl;
+ VERBOSE(ConstantOutputPass) << " - Output(original) Operand : " << ind << std::endl;
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/ConstantOutputPass.h b/runtime/onert/core/src/compiler/pass/ConstantOutputPass.h
new file mode 100644
index 000000000..193dd3a68
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/ConstantOutputPass.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_CONSTANT_OUTPUT_PASS_H__
+#define __ONERT_COMPILER_PASS_CONSTANT_OUTPUT_PASS_H__
+
+#include "OperandPass.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+/**
+ * @brief Pass to specially handle constant model outputs
+ *
+ * As an output buffer is given right before an execution but constant initialization is done at
+ * prepare phase, the current runtime structure cannot handle when an output is constant.
+ * To resolve this problem, this pass inserts a Permute layer with a const input and make the model
+ * output tensor to be its output.
+ *
+ * e.g.)
+ *
+ * ((Const Output))
+ *
+ * becomes
+ *
+ * (Const) -> [Permute] -> ((Output))
+ *
+ * Note that this is a mandatory pass for Graph.
+ */
+class ConstantOutputPass : public OperandPass
+{
+public:
+ using OperandPass::OperandPass;
+
+public:
+ std::string id() final { return "ConstantOutputPass"; }
+
+public:
+ void callback(const ir::OperandIndex &i, ir::Operand &o) final;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_CONSTANT_INSERTION_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/LoweredOperandPass.h b/runtime/onert/core/src/compiler/pass/LoweredOperandPass.h
new file mode 100644
index 000000000..0c5f7d745
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/LoweredOperandPass.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_PASS_LOWERED_OPERAND_PASS_H__
+#define __ONERT_IR_PASS_LOWERED_OPERAND_PASS_H__
+
+#include "OperandPass.h"
+#include "compiler/LoweredGraph.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+class LoweredOperandPass : public OperandPass
+{
+public:
+ LoweredOperandPass(compiler::LoweredGraph &lowered_graph)
+ : OperandPass{lowered_graph.graph()}, _lowered_graph{lowered_graph}
+ {
+ // DO NOTHING
+ }
+
+ virtual ~LoweredOperandPass() = default;
+
+ std::string id() override = 0;
+ void callback(const ir::OperandIndex &i, ir::Operand &o) override = 0;
+
+protected:
+ compiler::LoweredGraph &_lowered_graph;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_IR_PASS_LOWERED_OPERAND_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/LoweredOperationPass.h b/runtime/onert/core/src/compiler/pass/LoweredOperationPass.h
new file mode 100644
index 000000000..5c8569be2
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/LoweredOperationPass.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_PASS_LOWERED_OPERATION_PASS_H__
+#define __ONERT_IR_PASS_LOWERED_OPERATION_PASS_H__
+
+#include "OperationPass.h"
+#include "compiler/LoweredGraph.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+class LoweredOperationPass : public OperationPass
+{
+public:
+ LoweredOperationPass(LoweredGraph &lowered_graph)
+ : OperationPass{lowered_graph.graph()}, _lowered_graph{lowered_graph}
+ {
+ // DO NOTHING
+ }
+
+ virtual ~LoweredOperationPass() = default;
+
+ std::string id() override = 0;
+ void callback(const ir::OperationIndex &i, ir::Operation &o) override = 0;
+
+protected:
+ LoweredGraph &_lowered_graph;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_IR_PASS_LOWERED_OPERATION_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/OddOutputPass.cc b/runtime/onert/core/src/compiler/pass/OddOutputPass.cc
new file mode 100644
index 000000000..f50fae0d3
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/OddOutputPass.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OddOutputPass.h"
+
+#include "ir/Graph.h"
+#include "ir/operation/Permute.h"
+#include "util/logging.h"
+#include "util/Utils.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+void OddOutputPass::run()
+{
+ auto &outputs = _graph.getOutputs();
+
+ VERBOSE(OddOutputPass) << "Case 1 : An operand which is a model output and a model input"
+ << std::endl;
+ for (auto &ind : outputs)
+ {
+ if (_graph.getInputs().contains(ind))
+ {
+ auto permute_output_ind = insertPermute(ind);
+ // Update the output to be newly added operand
+ _graph.getOutputs().replace(ind, permute_output_ind);
+ }
+ }
+
+ VERBOSE(OddOutputPass) << "Case 2 : Two or more duplicated outputs" << std::endl;
+ std::unordered_set<ir::OperandIndex> occurence;
+ for (auto &ind : outputs)
+ {
+ auto &obj = _graph.operands().at(ind);
+ if (occurence.count(ind) == 0)
+ {
+ occurence.insert(ind);
+ continue;
+ }
+
+ // Panic when it is const, it must have been handled earlier in another pass
+ UNUSED_RELEASE(obj);
+ assert(!obj.isConstant());
+
+ auto permute_output_ind = insertPermute(ind);
+ ind = permute_output_ind; // Replace output index to fix output duplication
+ }
+}
+
+ir::OperandIndex OddOutputPass::insertPermute(ir::OperandIndex ind)
+{
+ auto &obj = _graph.operands().at(ind);
+ auto output_ind = _graph.addOperand(obj.shape(), obj.typeInfo());
+ auto &output_obj = _graph.operands().at(output_ind);
+
+ using ir::operation::Permute;
+ auto permute_obj = std::make_unique<Permute>(ind, output_ind, Permute::Type::COPY);
+ auto permute_ind = _graph.operations().push(std::move(permute_obj));
+
+ output_obj.setDef(permute_ind);
+ obj.insertUse(permute_ind);
+
+ VERBOSE(OddOutputPass) << "Permute Op inserted for a constant output, node index : "
+ << permute_ind << std::endl;
+ VERBOSE(OddOutputPass) << " - Input (original) Operand : " << ind << std::endl;
+ VERBOSE(OddOutputPass) << " - Output(inserted) Operand : " << output_ind << std::endl;
+
+ return output_ind;
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/OddOutputPass.h b/runtime/onert/core/src/compiler/pass/OddOutputPass.h
new file mode 100644
index 000000000..2accbac60
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/OddOutputPass.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_ODD_OUTPUT_PASS_H__
+#define __ONERT_COMPILER_PASS_ODD_OUTPUT_PASS_H__
+
+#include <unordered_set>
+
+#include "Pass.h"
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+/**
+ * @brief Pass to specially handle odd outputs in a subgraph
+ *
+ * Runtime Graph IR requires every input or output must have distinct tensor index, this is onert's
+ * restriction. However we allow duplication of indices in the models(or API). So we should
+ * transform the graph after model-loading.
+ *
+ * This is necessary since our API lets users to set different buffers for each input and output so
+ * it is unavoidable that we must copy the value at runtime.
+ *
+ * Note that this is a mandatory pass for Graph.
+ *
+ * Case 1 : An operand which is a model output and a model input
+ *
+ * Create an operand and insert a Permute(copy) op between them. And change the output to be the
+ * newly generated operand.
+ *
+ * e.g.)
+ *
+ * ```
+ * ((#0 Input0 and also Output0))
+ * becomes
+ * ((#0 Input0)) -> [#0 Permute] -> ((#1 Output0))
+ * ```
+ *
+ * Case 2 : Two or more duplicated outputs
+ *
+ * Do the same with Case 1, but between two outputs of the same tensor index.
+ *
+ * e.g.)
+ *
+ * ```
+ * ((#0 Input0)) -> [#0 Some Operation] -> ((#1 Output0 and also Output1))
+ * becomes
+ * ((#0 Input0)) -> [#0 Some Operation] -> ((#1 Output0)) [#1 Permute] -> ((#2 Output1))
+ * ```
+ *
+ */
+class OddOutputPass : public Pass
+{
+public:
+ using Pass::Pass;
+
+public:
+ std::string id() final { return "OddOutputPass"; }
+
+public:
+ void run() override;
+
+private:
+ ir::OperandIndex insertPermute(ir::OperandIndex input);
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_ODD_OUTPUT_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/OperandPass.cc b/runtime/onert/core/src/compiler/pass/OperandPass.cc
new file mode 100644
index 000000000..50c001c30
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/OperandPass.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OperandPass.h"
+
+#include "ir/Graph.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+void OperandPass::run()
+{
+ _graph.operands().iterate(
+ [&](const ir::OperandIndex &index, ir::Operand &object) { callback(index, object); });
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/OperandPass.h b/runtime/onert/core/src/compiler/pass/OperandPass.h
new file mode 100644
index 000000000..b094879c5
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/OperandPass.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_OPERAND_PASS_H__
+#define __ONERT_COMPILER_PASS_OPERAND_PASS_H__
+
+#include "Pass.h"
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace ir
+{
+class Operand;
+} // namespace ir
+} // namespace onert
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+class OperandPass : public Pass
+{
+public:
+ using Pass::Pass;
+ virtual ~OperandPass() = default;
+
+public:
+ std::string id() override = 0;
+ void run() override final;
+ virtual void callback(const ir::OperandIndex &i, ir::Operand &o) = 0;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_OPERAND_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/OperationPass.cc b/runtime/onert/core/src/compiler/pass/OperationPass.cc
new file mode 100644
index 000000000..d7a55cb22
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/OperationPass.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OperationPass.h"
+
+#include "ir/Index.h"
+#include "ir/Operation.h"
+#include "ir/Graph.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+void OperationPass::run()
+{
+ _graph.operations().iterate(
+ [&](const ir::OperationIndex &index, ir::Operation &node) { callback(index, node); });
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/OperationPass.h b/runtime/onert/core/src/compiler/pass/OperationPass.h
new file mode 100644
index 000000000..ac4d818a2
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/OperationPass.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file OperationPass.h
+ * @brief This file contains OperationPass class
+ */
+
+#ifndef __ONERT_COMPILER_PASS_OPERATION_PASS_H__
+#define __ONERT_COMPILER_PASS_OPERATION_PASS_H__
+
+#include "Pass.h"
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace ir
+{
+class Operation;
+} // namespace ir
+} // namespace onert
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+/**
+ * @brief Class to iterate over operations and calls callback() method
+ */
+class OperationPass : public Pass
+{
+public:
+ using Pass::Pass;
+ virtual ~OperationPass() = default;
+
+public:
+ /**
+ * @brief Returns string id for this pass. Same with class name.
+ *
+ * @return string id
+ */
+ std::string id() override = 0;
+
+ /**
+ * @brief Be called for all nodes of graph.
+ * @param index is the index of a node in graph
+ * @param node is the node in graph
+ */
+ virtual void callback(const ir::OperationIndex &index, ir::Operation &node) = 0;
+
+ /**
+ * @brief Run the pass
+ */
+ void run() final;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_OPERATION_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/Pass.h b/runtime/onert/core/src/compiler/pass/Pass.h
new file mode 100644
index 000000000..3f356c337
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/Pass.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_PASS_H__
+#define __ONERT_COMPILER_PASS_PASS_H__
+
+#include <string>
+
+namespace onert
+{
+namespace ir
+{
+class Graph;
+} // namespace compiler
+} // namespace onert
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+class Pass
+{
+public:
+ Pass(ir::Graph &graph) : _graph{graph} {}
+ virtual ~Pass() = default;
+
+public:
+ virtual std::string id() = 0;
+ virtual void run() = 0;
+
+protected:
+ ir::Graph &_graph;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/PassRunner.cc b/runtime/onert/core/src/compiler/pass/PassRunner.cc
new file mode 100644
index 000000000..2a058c8ac
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/PassRunner.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PassRunner.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+PassRunner &PassRunner::append(std::unique_ptr<Pass> pass)
+{
+ _passes.emplace_back(std::move(pass));
+ return *this;
+}
+
+void PassRunner::run()
+{
+ for (auto &pass : _passes)
+ {
+ VERBOSE(PassRunner) << "Start running '" << pass->id() << "'" << std::endl;
+ pass->run();
+ VERBOSE(PassRunner) << "Finished running '" << pass->id() << "'" << std::endl;
+ // TODO Dump graph(LowerInfo, OpSequence, ...)?
+ }
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/PassRunner.h b/runtime/onert/core/src/compiler/pass/PassRunner.h
new file mode 100644
index 000000000..a43c83f89
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/PassRunner.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_PASS_RUNNER_H__
+#define __ONERT_COMPILER_PASS_PASS_RUNNER_H__
+
+#include <initializer_list>
+#include <memory>
+#include <vector>
+
+#include "Pass.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+/**
+ * @brief Composite passes with logging
+ */
+class PassRunner
+{
+public:
+ PassRunner() = default;
+ PassRunner &append(std::unique_ptr<Pass> pass);
+
+ void run();
+
+private:
+ std::vector<std::unique_ptr<Pass>> _passes;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_PASS_RUNNER_H__
diff --git a/runtime/onert/core/src/compiler/pass/PermutationEliminationPass.cc b/runtime/onert/core/src/compiler/pass/PermutationEliminationPass.cc
new file mode 100644
index 000000000..504f1b995
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/PermutationEliminationPass.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PermutationEliminationPass.h"
+#include "backend/controlflow/Config.h"
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+void PermutationEliminationPass::callback(const ir::OperationIndex &ind, ir::Operation &node)
+{
+ _op_ind = ind;
+ node.accept(*this);
+};
+
+void PermutationEliminationPass::visit(const ir::operation::Permute &node)
+{
+ auto in_operand = node.getInputs().at(0);
+ auto out_operand = node.getOutputs().at(0);
+
+ // Check if two tensors are both portable if not, we can't eliminate the node
+ {
+ auto in_def_factor = _lowered_graph.getLowerInfo(in_operand)->def_factors().getOnlyElement();
+ auto out_def_factor = _lowered_graph.getLowerInfo(out_operand)->def_factors().getOnlyElement();
+
+ auto in_config = in_def_factor.backend()->config();
+ auto out_config = out_def_factor.backend()->config();
+
+ // FIXME Supporting dynamic tensor does not exactly mean those are portable.
+ // It may need to have another config option for checking if each uses `IPortableTensor`.
+ if (!(in_config->supportDynamicTensor() && out_config->supportDynamicTensor()))
+ return;
+ }
+
+ if (_graph.getOutputs().contains(out_operand))
+ {
+ // If the input is a const, we cannot remove it since we cannot put the constant data in the
+ // output buffer during prepare phase.
+ auto permute_input = node.getInputs().at(0);
+ if (_graph.operands().at(permute_input).isConstant())
+ return;
+ // If the input is a model input, we cannot remove it since our API lets users to set different
+ // buffers for inputs and outputs even though one tensor is both at the same time.
+ auto permute_output = node.getOutputs().at(0);
+ if (_graph.getInputs().contains(permute_input) && _graph.getOutputs().contains(permute_output))
+ return;
+ // Likewise, if copying between outputs to outputs, keep it.
+ if (_graph.getOutputs().contains(permute_input) && _graph.getOutputs().contains(permute_output))
+ return;
+
+ // Exceptional case : When the output operand is a model output
+ // In this case we keep the output and remove the input
+
+ auto &out_operand_obj = _graph.operands().at(out_operand);
+ assert(out_operand_obj.getDef() == _op_ind);
+ out_operand_obj.unsetDef();
+ _lowered_graph.op_seqs().iterate([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ if (!op_seq.getOutputs().contains(in_operand))
+ return;
+
+ // Update OpSequence/ir::Operation edges and ir::Operand edges
+ op_seq.replaceOutputs(in_operand, out_operand);
+ for (auto op : op_seq.operations())
+ {
+ auto &operation_obj = _graph.operations().at(op);
+ if (operation_obj.getOutputs().contains(in_operand))
+ {
+ operation_obj.replaceOutputs(in_operand, out_operand);
+ out_operand_obj.setDef(op);
+ }
+ }
+ });
+
+ // Remove Permute operation, enclosing OpSequence and the operand
+ {
+ _graph.removeOperand(in_operand);
+
+ auto op_seq_ind = _lowered_graph.op_seqs().getOperation(_op_ind);
+ // Assumes enclosing OpSequence contatins just this Permute operation
+ assert(_lowered_graph.op_seqs().at(op_seq_ind).size() == 1);
+ _lowered_graph.op_seqs().remove(op_seq_ind);
+ _graph.operations().remove(_op_ind);
+ }
+
+ _lowered_graph.op_seqs().iterate([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ if (!op_seq.getInputs().contains(in_operand))
+ return;
+
+ op_seq.replaceInputs(in_operand, out_operand);
+ for (auto op : op_seq.operations())
+ {
+ auto &operation_obj = _graph.operations().at(op);
+ if (operation_obj.getInputs().contains(in_operand))
+ {
+ operation_obj.replaceInputs(in_operand, out_operand);
+ out_operand_obj.insertUse(op);
+ }
+ }
+ });
+
+ VERBOSE(removePermute) << "Permute Op removed, node index : " << _op_ind << std::endl;
+ VERBOSE(removePermute) << " - Input (removed) ir::Operand : " << in_operand << std::endl;
+ VERBOSE(removePermute) << " - Output(kept) ir::Operand : " << out_operand << std::endl;
+ }
+ else
+ {
+ // Otherwise keep the input and remove the output
+
+ auto &in_operand_obj = _graph.operands().at(in_operand);
+ in_operand_obj.removeUse(_op_ind);
+
+ // Make OpSequences(that use the output) use the input
+ _lowered_graph.op_seqs().iterate([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
+ if (!op_seq.getInputs().contains(out_operand))
+ return;
+
+ op_seq.replaceInputs(out_operand, in_operand);
+ for (auto op : op_seq.operations())
+ {
+ auto &operation_obj = _graph.operations().at(op);
+ if (operation_obj.getInputs().contains(out_operand))
+ {
+ operation_obj.replaceInputs(out_operand, in_operand);
+ in_operand_obj.insertUse(op);
+ }
+ }
+ });
+
+ // Remove Permute operation, enclosing OpSequence and the operand
+ {
+ _graph.removeOperand(out_operand);
+
+ auto op_seq_ind = _lowered_graph.op_seqs().getOperation(_op_ind);
+ // Assumes enclosing OpSequence contatins just this Permute operation
+ assert(_lowered_graph.op_seqs().at(op_seq_ind).size() == 1);
+ _lowered_graph.op_seqs().remove(op_seq_ind);
+ _graph.operations().remove(_op_ind);
+ }
+
+ VERBOSE(removePermute) << "Permute Op removed, node index : " << _op_ind << std::endl;
+ VERBOSE(removePermute) << " - Input (kept) ir::Operand : " << in_operand << std::endl;
+ VERBOSE(removePermute) << " - Output(removed) ir::Operand : " << out_operand << std::endl;
+ }
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/PermutationEliminationPass.h b/runtime/onert/core/src/compiler/pass/PermutationEliminationPass.h
new file mode 100644
index 000000000..29daf1a82
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/PermutationEliminationPass.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_PERMUTATION_ELIMINATION_PASS_H__
+#define __ONERT_COMPILER_PASS_PERMUTATION_ELIMINATION_PASS_H__
+
+#include "ir/OperationVisitor.h"
+#include "LoweredOperationPass.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+/**
+ * @brief An optimization pass that removes Permute operations if possible
+ *
+ * There may be some Permute operations that are inserted by PermutationInsertionPass or other
+ * passes. This pass checks all Permute operations and eliminates them if Permute in/out tensors
+ * are compatible and layouts match.
+ *
+ * Permute input tensor is kept and the output is removed for all the cases, except model outputs.
+ * As all output tensors have to be controlflow backend, so the output is kept.
+ *
+ * @note This is an optimization pass which means that everything should work fine even if this pass
+ * was skipped.
+ */
+class PermutationEliminationPass : public LoweredOperationPass, public ir::OperationVisitor
+{
+public:
+ using LoweredOperationPass::LoweredOperationPass;
+
+public:
+ std::string id() final { return "PermutationEliminationPass"; }
+
+public:
+ void callback(const ir::OperationIndex &i, ir::Operation &n) final;
+
+private:
+ void visit(const ir::operation::Permute &) final;
+
+private:
+ ir::OperationIndex _op_ind;
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_PERMUTATION_ELIMINATION_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc
new file mode 100644
index 000000000..c83a72ada
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PermutationInsertionPass.h"
+
+#include <cassert>
+#include <utility>
+#include <unordered_map>
+
+#include "backend/controlflow/Config.h"
+#include "ir/Operand.h"
+#include "ir/operation/LowerInfo.h"
+#include "ir/Graph.h"
+#include "backend/IConfig.h"
+#include "util/logging.h"
+#include <memory>
+#include "ir/operation/Permute.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+void PermutationInsertionPass::callback(const ir::OperandIndex &index, ir::Operand &object)
+{
+ auto &&operand_li = _lowered_graph.getLowerInfo(index);
+ assert(operand_li);
+
+ // NOTE Later, constants also will have Def
+ // Ignore constants
+ if (operand_li->def_factors().size() == 0)
+ {
+ return;
+ }
+
+ std::list<ir::OperationIndex> permute_indexes;
+
+ // Build a map for all necessary type of operands
+ std::unordered_map<ir::operand::PermuteFactor, ir::OperandIndex> factor_to_index;
+ {
+ assert(operand_li->def_factors().size() == 1);
+ for (auto factor : operand_li->def_factors())
+ {
+ factor_to_index.emplace(factor, index);
+ }
+
+ auto insert_set = operand_li->use_factors() - operand_li->def_factors();
+ for (auto factor : insert_set)
+ {
+ const auto permute_operation_index = insertPermute(index, factor);
+ permute_indexes.push_back(permute_operation_index);
+ const auto &permute_operation = _graph.operations().at(permute_operation_index);
+ const auto permuted_operand_index = permute_operation.getOutputs().at(0);
+ factor_to_index.emplace(factor, permuted_operand_index);
+ }
+ }
+
+ // Update operations' input that uses this operand
+ {
+ std::list<ir::OperationIndex> remove_list;
+
+ auto uses = object.getUses();
+ for (auto use : uses)
+ {
+ // If permute operation, ignore it
+ if (std::find(permute_indexes.begin(), permute_indexes.end(), use) != permute_indexes.end())
+ continue;
+
+ auto &operation = _graph.operations().at(use);
+ assert(_lowered_graph.op_seqs().containsOperation(use));
+ auto op_seq_index = _lowered_graph.op_seqs().getOperation(use);
+ auto op_seq_li = _lowered_graph.getLowerInfo(op_seq_index);
+ assert(op_seq_li);
+ const auto op_seq_layout = op_seq_li->layout();
+ const backend::Backend *backend = op_seq_li->backend();
+ assert(backend);
+ auto use_node_inputs = operation.getInputs();
+ assert(use_node_inputs.contains(index));
+
+ auto new_index = factor_to_index.at({backend, op_seq_layout});
+ if (index != new_index)
+ {
+ // Update from op_seq
+ // Replace the same inputs of an OpSequence at once for the following reasons:
+ // 1. An OpSequence's inputs are the same inputs of first operation
+ // 2. An OpSequence may have inputs as the same operand (2 or more).
+ // 3. The same inputs of OpSequence have the same PermuteFactor.
+ _lowered_graph.op_seqs().at(op_seq_index).replaceInputs(index, new_index);
+
+ // Update from operation
+ // Replace the same inputs of an operation at once for the following reasons:
+ // No. 2 and 3 above
+ operation.replaceInputs(index, new_index);
+
+ // Update from operand
+ remove_list.push_back(
+ use); // Removal should be done in another loop since we are in the loop
+ _graph.operands().at(new_index).insertUse(use);
+ }
+ }
+
+ for (auto &operation : remove_list)
+ {
+ object.removeUse(operation);
+ }
+ }
+}
+
+ir::OperationIndex PermutationInsertionPass::insertPermute(const ir::OperandIndex &operand_index,
+ const ir::operand::PermuteFactor &factor)
+{
+ assert(!_graph.isBuildingPhase());
+
+ auto &operand = _graph.operands().at(operand_index);
+
+ // Generate output operand and permute operation
+ auto out_operand_index = _graph.addOperand(operand.shape(), operand.typeInfo());
+ // change model output if operand_index is model output index
+ auto &model_outputs = _graph.getOutputs();
+ if (model_outputs.contains(operand_index))
+ {
+ model_outputs.replace(operand_index, out_operand_index);
+ }
+
+ // Find Permute information
+ auto input_factor = _lowered_graph.getLowerInfo(operand_index)->def_factors().getOnlyElement();
+ auto input_backend = input_factor.backend();
+ auto output_backend = factor.backend();
+ // NOTE Permute may not have specific layout because the layout of input and output may be
+ // different.
+ const auto permute_node_layout = ir::Layout::UNKNOWN;
+ // NOTE If one backend supports several layout, the backend must support Permute operation
+ const backend::Backend *permute_node_backend = compiler::BackendManager::get().getControlflow();
+ if (input_backend == output_backend)
+ {
+ permute_node_backend = input_backend;
+ }
+ const ir::operand::PermuteFactor permute_node_factor{permute_node_backend, permute_node_layout};
+
+ // Update LowerInfo of input operand
+ auto operand_lower_info = _lowered_graph.getLowerInfo(operand_index);
+ operand_lower_info->removeUsePermuteFactor(factor);
+ operand_lower_info->addUsePermuteFactor(permute_node_factor);
+
+ // Update LowerInfo of output operand
+ auto out_operand_li = std::make_unique<ir::operand::LowerInfo>();
+
+ // The input and output factors of all nodes will be the same except Permute. So Tensor's
+ // allocators allocates memory using only the information of def permutation factor now.
+ // TODO Change param to permute_node_factor
+ out_operand_li->addDefPermuteFactor(factor);
+ out_operand_li->addUsePermuteFactor(factor);
+ _lowered_graph.setLowerInfo(out_operand_index, std::move(out_operand_li));
+
+ // Insert permute operation to the graph
+ const auto input_layout = input_factor.layout();
+ const auto output_layout = factor.layout();
+ using Permute = ir::operation::Permute;
+ const auto permute_type = [&]() {
+ if (input_layout == ir::Layout::NHWC && output_layout == ir::Layout::NCHW)
+ {
+ return Permute::Type::NHWC_TO_NCHW;
+ }
+ else if (input_layout == ir::Layout::NCHW && output_layout == ir::Layout::NHWC)
+ {
+ return Permute::Type::NCHW_TO_NHWC;
+ }
+ else
+ {
+ return Permute::Type::COPY;
+ }
+ }();
+ auto insert_node = std::make_unique<Permute>(operand_index, out_operand_index, permute_type);
+
+ auto node_index = _graph.operations().push(std::move(insert_node));
+ const auto &node = _graph.operations().at(node_index);
+
+ VERBOSE_F() << "Permute Op inserted, node index : " << node_index << std::endl;
+ VERBOSE_F() << " - Input (original) Operand : " << operand_index << std::endl;
+ VERBOSE_F() << " - Output(inserted) Operand : " << out_operand_index << std::endl;
+
+ // OpSequence
+ {
+ auto op_seq_index = _lowered_graph.op_seqs().emplace(node_index, permute_node_layout);
+ auto &op_seq = _lowered_graph.op_seqs().at(op_seq_index);
+ op_seq.setInputs(node.getInputs());
+ op_seq.setOutputs(node.getOutputs());
+ _lowered_graph.setLowerInfo(op_seq_index, std::make_unique<ir::operation::LowerInfo>(
+ permute_node_backend, permute_node_layout));
+ }
+
+ // Update Use/Def info
+ {
+ _graph.operands().at(operand_index).insertUse(node_index);
+ _graph.operands().at(out_operand_index).setDef(node_index);
+ }
+ return node_index;
+}
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h
new file mode 100644
index 000000000..758515385
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_PERMUTATION_INSERTION_PASS_H__
+#define __ONERT_COMPILER_PASS_PERMUTATION_INSERTION_PASS_H__
+
+#include "LoweredOperandPass.h"
+#include "compiler/BackendManager.h"
+#include "ir/Operand.h"
+#include "ir/operand/PermuteFactor.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+class PermutationInsertionPass : public LoweredOperandPass
+{
+public:
+ using LoweredOperandPass::LoweredOperandPass;
+
+public:
+ std::string id() override { return "PermutationInsertionPass"; }
+ void callback(const ir::OperandIndex &index, ir::Operand &object) override;
+
+private:
+ /**
+ * @brief Insert Permute operation that has given operand as input
+ *
+ * @param operand_index is the target operand index for the insertion
+ * @param factor is the output operand's backend type and layout
+ *
+ * @return ir::OperationIndex
+ */
+ ir::OperationIndex insertPermute(const ir::OperandIndex &operand_index,
+ const ir::operand::PermuteFactor &factor);
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_PERMUTATION_INSERTION_PASS_H__
diff --git a/runtime/onert/core/src/compiler/pass/PermutationOperationPass.cc b/runtime/onert/core/src/compiler/pass/PermutationOperationPass.cc
new file mode 100644
index 000000000..93d125307
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/PermutationOperationPass.cc
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PermutationOperationPass.h"
+
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+#include "ir/Graph.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+using namespace ir;
+
+void PermutationOperationPass::callback(const OperationIndex &, Operation &node)
+{
+ node.accept(*this);
+};
+
+// TODO Remove this. Expanding ranks of Operand is dangerous
+void PermutationOperationPass::applyExpandRanks(const Operation &node)
+{
+ const auto &output_ind = node.getOutputs().at(0);
+ const auto &output = _graph.operands().at(output_ind);
+
+ assert(output.getDef().valid());
+ const auto node_index = output.getDef();
+ const auto &op_seq_index = _lowered_graph.op_seqs().getOperation(node_index);
+ const auto frontend_layout = _lowered_graph.op_seqs().at(op_seq_index).getLayout();
+ const auto backend_layout = _lowered_graph.getLowerInfo(op_seq_index)->layout();
+
+ if (frontend_layout == backend_layout)
+ {
+ return;
+ }
+
+ int32_t expanded_rank = 0;
+ for (const auto &index :
+ (node.getInputs() + node.getOutputs()) | Remove::DUPLICATED | Remove::UNDEFINED)
+ {
+ expanded_rank = std::max(expanded_rank, _graph.operands().at(index).shape().rank());
+ }
+ if (expanded_rank < 4)
+ return;
+
+ for (const auto &index :
+ (node.getInputs() + node.getOutputs()) | Remove::DUPLICATED | Remove::UNDEFINED)
+ {
+ const auto &operand = _graph.operands().at(index);
+ if (operand.shape().rank() < expanded_rank)
+ {
+ if (operand.getUses().size() > 1)
+ throw std::runtime_error("PermutationOperationPass: not supported expanding rank of "
+ "operand used in more than one node");
+ // TODO remove const_cast later. For example, _ctx may need to be a non const variable or
+ // a node to extend shape may be inserted in front of this operation
+ const_cast<Shape &>(operand.shape()).extendRank(expanded_rank);
+ }
+ }
+}
+
+void PermutationOperationPass::changeToKeepLayout(const Operation &node)
+{
+ const auto &output_ind = node.getOutputs().at(0);
+ const auto &output_obj = _graph.operands().at(output_ind);
+
+ assert(output_obj.getDef().valid());
+ const auto node_index = output_obj.getDef();
+ const auto &op_seq_index = _lowered_graph.op_seqs().getOperation(node_index);
+
+ const auto frontend_layout = _lowered_graph.op_seqs().at(op_seq_index).getLayout();
+ const auto backend_layout = _lowered_graph.getLowerInfo(op_seq_index)->layout();
+
+ if (frontend_layout == backend_layout)
+ {
+ return;
+ }
+
+ // Permutation changing layout beyond 4-D is not supported yet
+ assert(output_obj.shape().rank() <= 4);
+
+ // Divide op_seq based on target operation
+ {
+ auto &prev_op_seq = _lowered_graph.op_seqs().at(op_seq_index);
+ auto &operations = _lowered_graph.graph().operations();
+
+ // Create new op_seq and move information from existing op_seq to new op_seq if target
+ // node is the end of op_seq
+ auto it = prev_op_seq.begin();
+ // Find iterator of target node in op_seq
+ while (*(it++) != node_index)
+ ;
+ if (it != prev_op_seq.end())
+ {
+ const auto &target_op_idx = *it;
+ const auto &target_node = operations.at(target_op_idx);
+ const auto &next_op_seq_index =
+ _lowered_graph.op_seqs().emplace(target_op_idx, prev_op_seq.getLayout());
+ auto &next_op_seq = _lowered_graph.op_seqs().at(next_op_seq_index);
+ next_op_seq.setInputs(target_node.getInputs());
+ next_op_seq.setOutputs(target_node.getOutputs());
+
+ std::vector<OperationIndex> remove_list;
+ remove_list.emplace_back(target_op_idx);
+ while (++it != prev_op_seq.end())
+ {
+ next_op_seq.appendOperation(target_op_idx);
+ next_op_seq.setOutputs(target_node.getOutputs());
+ remove_list.emplace_back(target_op_idx);
+ }
+
+ prev_op_seq.setOutputs(node.getOutputs());
+ for (const auto &index : remove_list)
+ {
+ prev_op_seq.remove(index);
+ }
+
+ const auto op_seq_li = _lowered_graph.getLowerInfo(op_seq_index);
+ _lowered_graph.setLowerInfo(
+ next_op_seq_index,
+ std::make_unique<ir::operation::LowerInfo>(op_seq_li->backend(), op_seq_li->layout()));
+ }
+ }
+
+ // Remove target operation from op_seq and insert the target operation to new op_seq
+ {
+ const auto backend = _lowered_graph.getLowerInfo(op_seq_index)->backend();
+
+ // Remove target operation from op_sequence
+ _lowered_graph.op_seqs().removeFromOpSequence(node_index);
+
+ if (!_lowered_graph.op_seqs().exist(op_seq_index))
+ {
+ // Remove lowerinfo for op_seq of target operation if the op_seq does not exist
+ _lowered_graph.removeLowerInfo(op_seq_index);
+ }
+ else
+ {
+ // Update op_seq of target operation if the op_seq exists
+ auto &prev_op_seq = _lowered_graph.op_seqs().at(op_seq_index);
+ const auto &last_node_idx = *(--prev_op_seq.end());
+ const auto &last_node = _lowered_graph.graph().operations().at(last_node_idx);
+ prev_op_seq.setOutputs(last_node.getOutputs());
+ }
+
+ // Create new op_seq and set information to the op_seq
+ auto new_op_seq_index = _lowered_graph.op_seqs().emplace(node_index, frontend_layout);
+ auto &new_op_seq = _lowered_graph.op_seqs().at(new_op_seq_index);
+ new_op_seq.setInputs(node.getInputs());
+ new_op_seq.setOutputs(node.getOutputs());
+ _lowered_graph.setLowerInfo(
+ new_op_seq_index, std::make_unique<ir::operation::LowerInfo>(backend, frontend_layout));
+ }
+
+ // Change PermuteFactors of operands of target node
+ {
+ const auto &op_seq_index = _lowered_graph.op_seqs().getOperation(node_index);
+ const auto op_seq_li = _lowered_graph.getLowerInfo(op_seq_index);
+ const auto backend = op_seq_li->backend();
+ const operand::PermuteFactor removed_factor{backend, backend_layout};
+ const operand::PermuteFactor new_factor{backend, frontend_layout};
+ for (const auto &input : node.getInputs() | Remove::DUPLICATED | Remove::UNDEFINED)
+ {
+ bool canRemove = true;
+ for (const auto &use : _graph.operands().at(input).getUses())
+ {
+ if (use != node_index)
+ {
+ const auto &use_op_seq_index = _lowered_graph.op_seqs().getOperation(use);
+ auto use_op_seq_li = _lowered_graph.getLowerInfo(use_op_seq_index);
+ if (use_op_seq_li->backend() == backend && use_op_seq_li->layout() == backend_layout)
+ {
+ canRemove = false;
+ break;
+ }
+ }
+ }
+
+ auto lower_info = _lowered_graph.getLowerInfo(input);
+ if (canRemove)
+ {
+ lower_info->removeUsePermuteFactor(removed_factor);
+ }
+ lower_info->addUsePermuteFactor(new_factor);
+
+ // Whether if node's input is an input of model or a constant
+ if (!_graph.operands().at(input).getDef().valid() &&
+ (lower_info->def_factors().size() == 1 &&
+ lower_info->def_factors().getOnlyElement() == removed_factor))
+ {
+ assert(_graph.getInputs().contains(input) || _graph.operands().at(input).isConstant());
+ lower_info->removeDefPermuteFactor(removed_factor);
+ lower_info->addDefPermuteFactor(new_factor);
+ }
+ }
+
+ for (const auto &output : node.getOutputs() | Remove::DUPLICATED | Remove::UNDEFINED)
+ {
+ auto lower_info = _lowered_graph.getLowerInfo(output);
+ lower_info->removeDefPermuteFactor(removed_factor);
+ lower_info->addDefPermuteFactor(new_factor);
+
+ // Whether if node's output is an output of model
+ if (_graph.operands().at(output).getUses().size() == 0)
+ {
+ assert(_graph.getOutputs().contains(output));
+ lower_info->removeUsePermuteFactor(removed_factor);
+ lower_info->addUsePermuteFactor(new_factor);
+ }
+ }
+ }
+}
+
+void PermutationOperationPass::visit(const ir::operation::BinaryArithmetic &node)
+{
+ applyExpandRanks(node);
+}
+
+void PermutationOperationPass::visit(const ir::operation::Concat &node) { applyExpandRanks(node); }
+
+void PermutationOperationPass::visit(const ir::operation::Comparison &node)
+{
+ applyExpandRanks(node);
+}
+
+void PermutationOperationPass::visit(const ir::operation::ElementwiseBinary &node)
+{
+ applyExpandRanks(node);
+}
+
+void PermutationOperationPass::visit(const ir::operation::ElementwiseUnary &node)
+{
+ applyExpandRanks(node);
+}
+
+void PermutationOperationPass::visit(const ir::operation::FullyConnected &node)
+{
+ const auto &input_ind = node.getInputs().at(ir::operation::FullyConnected::Input::INPUT);
+ const auto &input_obj = _graph.operands().at(input_ind);
+ const auto &input_shape = input_obj.shape();
+
+ if (input_shape.rank() >= 4)
+ {
+ changeToKeepLayout(node);
+ }
+}
+
+void PermutationOperationPass::visit(const ir::operation::Gather &node)
+{
+ const auto &input_ind = node.getInputs().at(ir::operation::Gather::Input::INPUT);
+ const auto &input_obj = _graph.operands().at(input_ind);
+ const auto &input_shape = input_obj.shape();
+
+ const auto &output_ind = node.getOutputs().at(0);
+ const auto &output_obj = _graph.operands().at(output_ind);
+ const auto &output_shape = output_obj.shape();
+
+ if (input_shape.rank() >= 4 || output_shape.rank() >= 4)
+ {
+ changeToKeepLayout(node);
+ }
+}
+
+void PermutationOperationPass::visit(const ir::operation::OneHot &node)
+{
+ const auto &output_ind = node.getOutputs().at(0);
+ const auto &output_obj = _graph.operands().at(output_ind);
+ const auto &output_shape = output_obj.shape();
+
+ if (output_shape.rank() >= 4)
+ {
+ changeToKeepLayout(node);
+ }
+}
+
+void PermutationOperationPass::visit(const ir::operation::Pack &node)
+{
+ const auto &input_ind = node.getInputs().at(ir::operation::Reshape::Input::INPUT);
+ const auto &input_obj = _graph.operands().at(input_ind);
+ const auto &input_shape = input_obj.shape();
+
+ const auto &output_ind = node.getOutputs().at(0);
+ const auto &output_obj = _graph.operands().at(output_ind);
+ const auto &output_shape = output_obj.shape();
+
+ if (input_shape.rank() < 4 || output_shape.rank() >= 4)
+ {
+ changeToKeepLayout(node);
+ }
+}
+
+void PermutationOperationPass::visit(const ir::operation::PReLU &node) { applyExpandRanks(node); }
+
+void PermutationOperationPass::visit(const ir::operation::Reshape &node)
+{
+ const auto &input_ind = node.getInputs().at(ir::operation::Reshape::Input::INPUT);
+ const auto &input_obj = _graph.operands().at(input_ind);
+ const auto &input_shape = input_obj.shape();
+
+ const auto &output_ind = node.getOutputs().at(0);
+ const auto &output_obj = _graph.operands().at(output_ind);
+ const auto &output_shape = output_obj.shape();
+
+ if (input_shape.rank() >= 4 || output_shape.rank() >= 4)
+ {
+ changeToKeepLayout(node);
+ }
+}
+
+void PermutationOperationPass::visit(const ir::operation::SquaredDifference &node)
+{
+ applyExpandRanks(node);
+}
+
+void PermutationOperationPass::visit(const ir::operation::Unpack &node)
+{
+ const auto &input_ind = node.getInputs().at(ir::operation::Reshape::Input::INPUT);
+ const auto &input_obj = _graph.operands().at(input_ind);
+ const auto &input_shape = input_obj.shape();
+
+ const auto &output_ind = node.getOutputs().at(0);
+ const auto &output_obj = _graph.operands().at(output_ind);
+ const auto &output_shape = output_obj.shape();
+
+ if (input_shape.rank() < 4 || output_shape.rank() >= 4)
+ {
+ changeToKeepLayout(node);
+ }
+}
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/compiler/pass/PermutationOperationPass.h b/runtime/onert/core/src/compiler/pass/PermutationOperationPass.h
new file mode 100644
index 000000000..cea5de288
--- /dev/null
+++ b/runtime/onert/core/src/compiler/pass/PermutationOperationPass.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_COMPILER_PASS_PERMUTATION_OPERATION_PASS_H__
+#define __ONERT_COMPILER_PASS_PERMUTATION_OPERATION_PASS_H__
+
+#include "ir/OperationVisitor.h"
+#include "LoweredOperationPass.h"
+
+namespace onert
+{
+namespace compiler
+{
+namespace pass
+{
+
+class PermutationOperationPass : public LoweredOperationPass, public ir::OperationVisitor
+{
+public:
+ using LoweredOperationPass::LoweredOperationPass;
+
+public:
+ std::string id() final { return "PermutationOperationPass"; }
+
+public:
+ void callback(const ir::OperationIndex &i, ir::Operation &n) final;
+
+public:
+ void visit(const ir::operation::BinaryArithmetic &) final;
+ void visit(const ir::operation::Comparison &) final;
+ void visit(const ir::operation::Concat &) final;
+ void visit(const ir::operation::ElementwiseBinary &) final;
+ void visit(const ir::operation::ElementwiseUnary &) final;
+ void visit(const ir::operation::OneHot &) final;
+ void visit(const ir::operation::Pack &) final;
+ void visit(const ir::operation::PReLU &) final;
+ void visit(const ir::operation::SquaredDifference &) final;
+ void visit(const ir::operation::Unpack &) final;
+ void visit(const ir::operation::FullyConnected &) final;
+ void visit(const ir::operation::Gather &) final;
+ void visit(const ir::operation::Reshape &) final;
+
+private:
+ void applyExpandRanks(const ir::Operation &);
+ void changeToKeepLayout(const ir::Operation &);
+};
+
+} // namespace pass
+} // namespace compiler
+} // namespace onert
+
+#endif // __ONERT_COMPILER_PASS_PERMUTATION_OPERATION_PASS_H__
diff --git a/runtime/onert/core/src/dumper/dot/DotBuilder.cc b/runtime/onert/core/src/dumper/dot/DotBuilder.cc
new file mode 100644
index 000000000..38a69696e
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/DotBuilder.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DotBuilder.h"
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+// DotDumper
+DotBuilder::DotBuilder() {}
+
+void DotBuilder::update(const Node &node_info)
+{
+ add(node_info);
+ for (auto edge : node_info.out_edges())
+ {
+ addEdge(node_info, *edge);
+ }
+}
+
+void DotBuilder::addOpSequence(const DotSubgraphInfo &subgraph_info)
+{
+ _dot << "subgraph cluster_" << subgraph_info.index().value() << " {\n";
+ _dot << " label=\"" << subgraph_info.label() << "\";\n";
+ _dot << " style=filled;\n";
+ _dot << " color=lightgrey;\n";
+ _dot << " ";
+ for (auto op : subgraph_info.operations())
+ {
+ _dot << "operation" << op.value() << "; ";
+ }
+ for (auto op : subgraph_info.operands())
+ {
+ _dot << "operand" << op.value() << "; ";
+ }
+ _dot << "\n";
+ _dot << "}\n";
+}
+
+void DotBuilder::writeDot(std::ostream &os)
+{
+ os << "digraph D {\n"
+ << _dot.str() << "\n"
+ << "}\n";
+}
+
+void DotBuilder::add(const Node &node)
+{
+ _dot << node.id();
+ std::stringstream ss;
+ _dot << "[";
+ for (auto attr : node.attributes())
+ {
+ _dot << attr.first << "=\"" << attr.second << "\" ";
+ }
+ _dot << "];\n";
+}
+
+void DotBuilder::addEdge(const Node &node1, const Node &node2)
+{
+ _dot << node1.id() << " -> " << node2.id() << ";\n";
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
diff --git a/runtime/onert/core/src/dumper/dot/DotBuilder.h b/runtime/onert/core/src/dumper/dot/DotBuilder.h
new file mode 100644
index 000000000..681cbbf5d
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/DotBuilder.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_DUMPER_DOT_DOT_BUILDER_H__
+#define __ONERT_DUMPER_DOT_DOT_BUILDER_H__
+
+#include <sstream>
+
+#include "ir/Index.h"
+#include "ir/Operation.h"
+#include "ir/Operand.h"
+
+#include "OperationNode.h"
+#include "OperandNode.h"
+#include "DotSubgraphInfo.h"
+
+using Operation = onert::ir::Operation;
+using Object = onert::ir::Operand;
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+class DotBuilder
+{
+public:
+ DotBuilder();
+
+public:
+ void update(const Node &dotinfo);
+ void addOpSequence(const DotSubgraphInfo &subgraph_info);
+
+ void writeDot(std::ostream &os);
+
+private:
+ void add(const Node &dotinfo);
+ void addEdge(const Node &dotinfo1, const Node &dotinfo2);
+
+ std::stringstream _dot;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
+
+#endif // __ONERT_DUMPER_DOT_DOT_BUILDER_H__
diff --git a/runtime/onert/core/src/dumper/dot/DotDumper.cc b/runtime/onert/core/src/dumper/dot/DotDumper.cc
new file mode 100644
index 000000000..fdf5c6eaa
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/DotDumper.cc
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fstream>
+#include <unordered_map>
+
+#include "DotDumper.h"
+#include "DotBuilder.h"
+#include "DotSubgraphInfo.h"
+#include "ir/OpSequence.h"
+#include "ir/OperationIndexMap.h"
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+#include "compiler/BackendManager.h"
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+void DotDumper::dump(const std::string &tag)
+{
+ if (_level == Level::OFF)
+ {
+ return;
+ }
+
+ onert::dumper::dot::DotBuilder dot_builder;
+
+ auto &operations = _graph.operations();
+ auto &operands = _graph.operands();
+
+ ir::OperationIndexMap<std::unique_ptr<Operation>> operation_nodes;
+ std::unordered_map<ir::OperandIndex, std::unique_ptr<Operand>> operand_nodes;
+
+ auto backend_to_fillcolor = [](const backend::Backend *backend) {
+ static const auto map = []() {
+ std::unordered_map<const backend::Backend *, std::string> ret;
+ uint32_t index = 1; // Start from 1 to avoid 0(red) which is too dark :(
+ for (const auto backend : compiler::BackendManager::get().getAll())
+ {
+ ret.emplace(backend, Node::BG_COLORS[index]);
+ index = (index + 1) % (sizeof(Node::BG_COLORS) / sizeof(Node::BG_COLORS[0]));
+ }
+ return ret;
+ }();
+
+ auto itr = map.find(backend);
+ if (itr == map.end())
+ {
+ return Node::DEFAULT_FILLCOLOR;
+ }
+ else
+ {
+ return itr->second;
+ }
+ };
+
+ util::Set<ir::OperandIndex> shown_operand_set;
+
+ operands.iterate([&](const ir::OperandIndex &index, const ir::Operand &object) {
+ bool showing_cond = false;
+ if (_level == Level::ALL)
+ {
+ showing_cond = true;
+ }
+ else
+ {
+ showing_cond =
+ !object.isConstant() || (_graph.getInputs() + _graph.getOutputs()).contains(index);
+ }
+ if (showing_cond)
+ {
+ shown_operand_set.add(index);
+
+ auto type = [&]() {
+ using onert::dumper::dot::Operand;
+ if (_graph.getInputs().contains(index))
+ return Operand::Type::MODEL_INPUT;
+ if (_graph.getOutputs().contains(index))
+ return Operand::Type::MODEL_OUTPUT;
+ return Operand::Type::INTERNAL;
+ }();
+
+ auto node = std::make_unique<Operand>(index, type);
+
+ {
+ // Display LowerInfo attributes
+ std::string label = std::to_string(index.value());
+ std::string fillcolor = "";
+ if (_lowered_graph)
+ {
+ auto lower_info = _lowered_graph->getLowerInfo(index);
+ const auto &def_factors = lower_info->def_factors();
+ if (def_factors.size() > 0)
+ {
+ label += "\\n[";
+ label += def_factors.getOnlyElement().backend()->config()->id();
+ label += "]";
+
+ fillcolor = backend_to_fillcolor(lower_info->def_factors().getOnlyElement().backend());
+ }
+ }
+ node->setAttribute("label", label);
+ node->setAttribute("fillcolor", fillcolor);
+ }
+
+ operand_nodes.emplace(index, std::move(node));
+ }
+ });
+
+ operations.iterate([&](const ir::OperationIndex &index, const ir::Operation &op) {
+ auto node = std::make_unique<Operation>(index, op);
+
+ for (auto input : op.getInputs())
+ {
+ using onert::dumper::dot::Operand;
+
+ // Constant input and dump level is ALL_BUT_CONSTANTS
+ if (operand_nodes.find(input) == operand_nodes.end())
+ continue;
+
+ auto &input_node = operand_nodes.at(input);
+ input_node->addOutEdge(node.get());
+ }
+
+ for (auto output : op.getOutputs() | ir::Remove::UNDEFINED)
+ {
+ using onert::dumper::dot::Operand;
+ auto &output_node = operand_nodes.at(output);
+ node->addOutEdge(output_node.get());
+ }
+
+ operation_nodes.emplace(index, std::move(node));
+ });
+
+ if (_lowered_graph)
+ {
+ const auto &op_seqs = _lowered_graph->op_seqs();
+ op_seqs.iterate([&](const ir::OpSequenceIndex &index, const ir::OpSequence &op_seq) {
+ const auto lower_info = _lowered_graph->getLowerInfo(index);
+ auto fillcolor = backend_to_fillcolor(lower_info->backend());
+ std::string label =
+ std::to_string(index.value()) + " [" + lower_info->backend()->config()->id() + "]";
+ DotSubgraphInfo subgraph_info{index, op_seq, shown_operand_set, _graph.operations()};
+ subgraph_info.label(label);
+ subgraph_info.fillcolor(fillcolor);
+ dot_builder.addOpSequence(subgraph_info);
+
+ // Set fillcolor of all operations in the op_seq
+ for (const auto &op_idx : op_seq.operations())
+ {
+ auto found = operation_nodes.find(op_idx);
+ if (found != operation_nodes.end())
+ {
+ auto &&op = found->second;
+ op->setAttribute("fillcolor", fillcolor);
+ }
+ }
+ });
+ }
+
+ for (const auto &e : operation_nodes)
+ dot_builder.update(*e.second);
+ for (const auto &e : operand_nodes)
+ dot_builder.update(*e.second);
+
+ // Dump to file
+ {
+ std::string file_name;
+ file_name += tag;
+ file_name += ".dot";
+ std::filebuf fb;
+
+ fb.open(file_name, std::ios::out);
+ std::ostream os(&fb);
+
+ dot_builder.writeDot(os);
+
+ fb.close();
+ }
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
diff --git a/runtime/onert/core/src/dumper/dot/DotDumper.h b/runtime/onert/core/src/dumper/dot/DotDumper.h
new file mode 100644
index 000000000..fdbca1642
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/DotDumper.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Graph.h"
+#include "compiler/LoweredGraph.h"
+
+#ifndef __ONERT_DUMPER_DOT_DOT_DUMPER_H__
+#define __ONERT_DUMPER_DOT_DOT_DUMPER_H__
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+class DotDumper
+{
+public:
+ enum Level
+ {
+ OFF = 0, //< Do not dump
+ ALL_BUT_CONSTANTS = 1, //< Emit all operations and operands but constants
+ ALL = 2 //< Emit all operations and operands
+ };
+
+public:
+ DotDumper(const ir::Graph &graph, Level level)
+ : _lowered_graph{nullptr}, _graph(graph), _level{level}
+ {
+ }
+ DotDumper(const compiler::LoweredGraph *lowered_graph, Level level)
+ : _lowered_graph{lowered_graph}, _graph(_lowered_graph->graph()), _level{level}
+ {
+ }
+
+public:
+ /**
+ * @brief Dump to dot file as tag name if "GRAPH_DOT_DUMP" is set
+ *
+ * @param[in] tag The name of dot file that would be created
+ * @return N/A
+ */
+ void dump(const std::string &tag);
+
+private:
+ const compiler::LoweredGraph *_lowered_graph;
+ const ir::Graph &_graph;
+ Level _level;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
+
+#endif // __ONERT_DUMPER_DOT_DOT_DUMPER_H__
diff --git a/runtime/onert/core/src/dumper/dot/DotSubgraphInfo.cc b/runtime/onert/core/src/dumper/dot/DotSubgraphInfo.cc
new file mode 100644
index 000000000..52e9c758d
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/DotSubgraphInfo.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DotSubgraphInfo.h"
+
+#include <sstream>
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+DotSubgraphInfo::DotSubgraphInfo(const ir::OpSequenceIndex &index, const ir::OpSequence &op_seq,
+ const util::Set<ir::OperandIndex> &shown_operands,
+ const ir::Operations &operations_ctx)
+ : _index{index}
+{
+ for (const auto &op_idx : op_seq.operations())
+ {
+ _operations.insert(op_idx);
+ const auto &node = operations_ctx.at(op_idx);
+ for (auto o : node.getInputs())
+ {
+ // Must be a shown operand, not op_seq's inputs
+ if (shown_operands.contains(o) && !op_seq.getInputs().contains(o))
+ {
+ _operands.insert(o);
+ }
+ }
+ for (auto o : node.getOutputs())
+ {
+ // Must be a shown operand, not op_seq's inputs
+ if (shown_operands.contains(o) && !op_seq.getOutputs().contains(o))
+ {
+ _operands.insert(o);
+ }
+ }
+ }
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
diff --git a/runtime/onert/core/src/dumper/dot/DotSubgraphInfo.h b/runtime/onert/core/src/dumper/dot/DotSubgraphInfo.h
new file mode 100644
index 000000000..95ba8953e
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/DotSubgraphInfo.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__
+#define __ONERT_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__
+
+#include <unordered_set>
+
+#include "ir/Index.h"
+#include <ir/Operations.h>
+#include "ir/OpSequence.h"
+#include "util/Set.h"
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+class DotSubgraphInfo
+{
+public:
+ DotSubgraphInfo(const ir::OpSequenceIndex &index, const ir::OpSequence &op_seq,
+ const util::Set<ir::OperandIndex> &shown_operands,
+ const ir::Operations &operations_ctx);
+
+ ir::OpSequenceIndex index() const { return _index; }
+ std::string label() const { return _label; }
+ void label(const std::string &val) { _label = val; }
+ std::string fillcolor() const { return _fillcolor; }
+ void fillcolor(const std::string &val) { _fillcolor = val; }
+ const std::unordered_set<ir::OperationIndex> &operations() const { return _operations; }
+ const std::unordered_set<ir::OperandIndex> &operands() const { return _operands; }
+
+private:
+ ir::OpSequenceIndex _index;
+ std::string _label;
+ std::string _fillcolor;
+ std::unordered_set<ir::OperationIndex> _operations;
+ std::unordered_set<ir::OperandIndex> _operands;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
+
+#endif // __ONERT_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__
diff --git a/runtime/onert/core/src/dumper/dot/Node.cc b/runtime/onert/core/src/dumper/dot/Node.cc
new file mode 100644
index 000000000..85d6e67a4
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/Node.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Node.h"
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+const std::string Node::DEFAULT_COLORSCHEME = "x11";
+const std::string Node::DEFAULT_FILLCOLOR = "white";
+// RED, BLUE, GREEN, PURPLE, ORANGE, YELLOW, BROWN, PINK
+const std::string Node::BG_COLORS[8] = {"1", "2", "3", "4", "5", "6", "7", "8"};
+
+Node::Node(const std::string &id) : _id{id}
+{
+ // Set default values
+ _attributes["style"] = "filled";
+ _attributes["colorscheme"] = DEFAULT_COLORSCHEME;
+ _attributes["fillcolor"] = DEFAULT_FILLCOLOR;
+}
+
+void Node::setAttribute(const std::string &key, const std::string &val) { _attributes[key] = val; }
+
+std::string Node::getAttribute(const std::string &key)
+{
+ auto itr = _attributes.find(key);
+ if (itr == _attributes.end())
+ {
+ return "";
+ }
+ else
+ {
+ return itr->second;
+ }
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
diff --git a/runtime/onert/core/src/dumper/dot/Node.h b/runtime/onert/core/src/dumper/dot/Node.h
new file mode 100644
index 000000000..9b09b92e7
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/Node.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Node.h
+ * @brief This file contains Node class
+ * @ingroup COM_AI_RUNTIME
+ *
+ */
+
+#ifndef __ONERT_DUMPER_DOT_NODE_H__
+#define __ONERT_DUMPER_DOT_NODE_H__
+
+#include <string>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+enum BGCOLORS : int
+{
+ RED,
+ BLUE,
+ GREEN,
+ PUPLE,
+ ORANGE,
+ YELLOW,
+ BROWN,
+ PINK
+};
+
+/**
+ * @brief Class that represents a Node in "dot" format
+ *
+ */
+class Node
+{
+public:
+ const static std::string DEFAULT_FILLCOLOR;
+ const static std::string DEFAULT_COLORSCHEME;
+ const static std::string BG_COLORS[8];
+
+public:
+ /**
+ * @brief Destroy the Node object
+ *
+ */
+ virtual ~Node() = default;
+
+ /**
+ * @brief Construct a new Node object
+ *
+ * @param id
+ */
+ Node(const std::string &id);
+
+ /**
+ * @brief return id
+ *
+ * @return id
+ */
+ std::string id() const { return _id; }
+
+ /**
+ * @brief return attributes
+ *
+ * @return const reference of attributes object
+ */
+ const std::unordered_map<std::string, std::string> &attributes() const { return _attributes; }
+ /**
+ * @brief Store an attribute with key-value pair
+ *
+ * @param[in] key attribute's key
+ * @param[in] val attribute's value that is associated with the key
+ */
+ void setAttribute(const std::string &key, const std::string &val);
+ /**
+ * @brief Get the attributte value that is associated with key
+ *
+ * @param[in] key key of the attribute
+ * @return value that is associated with the key
+ */
+ std::string getAttribute(const std::string &key);
+
+ /**
+ * @brief Add an edge in the graph, which is an outgoing edge
+ *
+ * @param[in] dotinfo A node that the new edge will be connected to
+ */
+ void addOutEdge(Node *dotinfo) { _out_edges.emplace_back(dotinfo); }
+ /**
+ * @brief Return list of out edges
+ *
+ * @return Edges
+ */
+ const std::vector<Node *> &out_edges() const { return _out_edges; }
+
+private:
+ std::string _id;
+ std::unordered_map<std::string, std::string> _attributes;
+ std::vector<Node *> _out_edges;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
+
+#endif // __ONERT_DUMPER_DOT_NODE_H__
diff --git a/runtime/onert/core/src/dumper/dot/OperandNode.cc b/runtime/onert/core/src/dumper/dot/OperandNode.cc
new file mode 100644
index 000000000..5a6015ca9
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/OperandNode.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+
+#include "OperandNode.h"
+#include "ir/Graph.h"
+#include "ir/operand/LowerInfo.h"
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+const std::string Operand::INPUT_SHAPE = "doublecircle";
+const std::string Operand::OUTPUT_SHAPE = "doublecircle";
+const std::string Operand::OPERAND_SHAPE = "ellipse";
+const std::string Operand::BG_COLOR_SCHEME = "set18";
+
+Operand::Operand(const ir::OperandIndex &index, Type type)
+ : Node{"operand" + std::to_string(index.value())}
+{
+ {
+ auto type_to_shape = [](Type type) {
+ switch (type)
+ {
+ case Type::MODEL_INPUT:
+ return INPUT_SHAPE;
+ case Type::MODEL_OUTPUT:
+ return OUTPUT_SHAPE;
+ case Type::UNDEFINED:
+ case Type::INTERNAL:
+ default:
+ return OPERAND_SHAPE;
+ }
+ };
+ setAttribute("shape", type_to_shape(type));
+ }
+
+ setAttribute("colorscheme", BG_COLOR_SCHEME);
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
diff --git a/runtime/onert/core/src/dumper/dot/OperandNode.h b/runtime/onert/core/src/dumper/dot/OperandNode.h
new file mode 100644
index 000000000..2e7cc5861
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/OperandNode.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Operand.h
+ * @brief This file contains Operand
+ * @ingroup COM_AI_RUNTIME
+ *
+ */
+
+#ifndef __ONERT_DUMPER_DOT_DOT_OPERAND_INFO_H__
+#define __ONERT_DUMPER_DOT_DOT_OPERAND_INFO_H__
+
+#include <vector>
+
+#include "Node.h"
+#include "ir/Operand.h"
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+/**
+ * @brief Class that represents an Operand
+ *
+ */
+class Operand : public Node
+{
+public:
+ enum class Type
+ {
+ UNDEFINED,
+ MODEL_INPUT,
+ MODEL_OUTPUT,
+ INTERNAL
+ };
+
+public:
+ static const std::string INPUT_SHAPE;
+ static const std::string OUTPUT_SHAPE;
+ static const std::string OPERAND_SHAPE;
+ static const std::string BG_COLOR_SCHEME;
+
+public:
+ /**
+ * @brief Construct a new Operand Node object
+ *
+ * @param[in] index Operand index
+ * @param[in] type Operand type
+ * @param[in] lower_info Operand LowerInfo
+ */
+ Operand(const ir::OperandIndex &index, Type type);
+
+private:
+ void addBackendLabel();
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
+
+#endif // __ONERT_DUMPER_DOT_DOT_OPERAND_INFO_H__
diff --git a/runtime/onert/core/src/dumper/dot/OperationNode.cc b/runtime/onert/core/src/dumper/dot/OperationNode.cc
new file mode 100644
index 000000000..bee137e7c
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/OperationNode.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+
+#include "OperationNode.h"
+#include "ir/Graph.h"
+#include "ir/operation/LowerInfo.h"
+#include "backend/IConfig.h"
+#include "backend/Backend.h"
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+const std::string Operation::OPERATION_SHAPE = "rect";
+const std::string Operation::BG_COLOR_SCHEME = "pastel18";
+
+Operation::Operation(const ir::OperationIndex &index, const ir::Operation &node)
+ : Node{"operation" + std::to_string(index.value())}
+{
+ setAttribute("label", std::to_string(index.value()) + " : " + node.name());
+ setAttribute("shape", OPERATION_SHAPE);
+ setAttribute("colorscheme", BG_COLOR_SCHEME);
+ setAttribute("fillcolor", DEFAULT_FILLCOLOR);
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
diff --git a/runtime/onert/core/src/dumper/dot/OperationNode.h b/runtime/onert/core/src/dumper/dot/OperationNode.h
new file mode 100644
index 000000000..74a37d3fb
--- /dev/null
+++ b/runtime/onert/core/src/dumper/dot/OperationNode.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Operation.h
+ * @brief This file contains Operation
+ * @ingroup COM_AI_RUNTIME
+ *
+ */
+
+#ifndef __ONERT_DUMPER_DOT_DOT_NODE_INFO_H__
+#define __ONERT_DUMPER_DOT_DOT_NODE_INFO_H__
+
+#include "Node.h"
+#include "ir/Operation.h"
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace dumper
+{
+namespace dot
+{
+
+/**
+ * @brief Class that represents an Operation
+ *
+ */
+class Operation : public Node
+{
+public:
+ static const std::string OPERATION_SHAPE;
+ static const std::string BG_COLOR_SCHEME;
+
+public:
+ /**
+ * @brief Construct a new Operation Node object
+ *
+ * @param[in] index operation index
+ * @param[in] node operation object
+ */
+ Operation(const ir::OperationIndex &index, const ir::Operation &node);
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace onert
+
+#endif // __ONERT_DUMPER_DOT_DOT_NODE_INFO_H__
diff --git a/runtime/onert/core/src/exec/BackendSet.h b/runtime/onert/core/src/exec/BackendSet.h
new file mode 100644
index 000000000..33ec75e4b
--- /dev/null
+++ b/runtime/onert/core/src/exec/BackendSet.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_BACKEND_SET_H__
+#define __ONERT_EXEC_BACKEND_SET_H__
+
+#include "util/Set.h"
+
+namespace onert
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace onert
+
+namespace onert
+{
+namespace exec
+{
+
+using BackendSet = util::Set<const backend::Backend *>;
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_BACKEND_SET_H__
diff --git a/runtime/onert/core/src/exec/DataflowExecutor.cc b/runtime/onert/core/src/exec/DataflowExecutor.cc
new file mode 100644
index 000000000..53bc3c204
--- /dev/null
+++ b/runtime/onert/core/src/exec/DataflowExecutor.cc
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DataflowExecutor.h"
+
+#include <cassert>
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace exec
+{
+
+int64_t DataflowExecutor::calculateRank(const std::vector<ir::OperationIndex> &operations)
+{
+ int64_t rank = 0;
+ if (!_indexed_ranks)
+ {
+ return rank;
+ }
+ for (const auto &operation_idx : operations)
+ {
+ auto it = _indexed_ranks->find(operation_idx);
+ if (it == _indexed_ranks->end())
+ {
+ assert(_graph.operations().at(operation_idx).opcode() == ir::OpCode::Permute &&
+ operations.size() == 1);
+ // run Permute ASAP for next operations to be ready for other backends
+ return std::numeric_limits<int64_t>::max();
+ }
+ else
+ {
+ rank += it->second;
+ }
+ }
+ return rank;
+}
+
+void DataflowExecutor::emplaceToReadyJobs(const uint32_t &id)
+{
+ auto &job = _waiting_jobs[id];
+ assert(job != nullptr);
+ auto &op_seq = _lowered_graph->op_seqs().at(_job_to_op_seq[job->index()]);
+ auto rank = calculateRank(op_seq.operations());
+ _ready_jobs.emplace(rank, std::move(job));
+}
+
+void DataflowExecutor::notify(uint32_t finished_job_id)
+{
+ for (auto id : _output_info[finished_job_id])
+ {
+ assert(_input_info[id] > 0);
+ auto count = --_input_info[id];
+ if (count == 0) // No dependent jobs left, ready for execution
+ {
+ emplaceToReadyJobs(id);
+ }
+ }
+}
+bool DataflowExecutor::noWaitingJobs()
+{
+ return std::all_of(_waiting_jobs.begin(), _waiting_jobs.end(),
+ [](const std::unique_ptr<Job> &job) { return job == nullptr; });
+}
+
+DataflowExecutor::DataflowExecutor(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const std::vector<backend::ITensor *> &input_tensors,
+ const std::vector<backend::ITensor *> &output_tensors,
+ const compiler::TensorRegistries &tensor_regs,
+ compiler::CodeMap &&code_map)
+ : ExecutorBase{std::move(lowered_graph), input_tensors, output_tensors, tensor_regs},
+ _code_map{std::move(code_map)}
+{
+ VERBOSE(DataflowExecutor) << "Constructing Dataflow Executor" << std::endl;
+
+ const auto &op_seqs = _lowered_graph->op_seqs();
+ // Assign jobs convert OpSequenceIndex to job index(uint32_t)
+ uint32_t next_job_index = 0;
+ std::unordered_map<ir::OpSequenceIndex, uint32_t> op_seq_to_job;
+ op_seqs.iterate([&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &) {
+ VERBOSE(DataflowExecutor) << "Create a job #" << next_job_index << " with OpSequenceIndex "
+ << op_seq_index.value() << std::endl;
+ _finished_jobs.emplace_back(
+ std::make_unique<Job>(next_job_index, _code_map.at(op_seq_index).fn_seq.get()));
+ op_seq_to_job[op_seq_index] = next_job_index++;
+ });
+
+ _waiting_jobs.resize(next_job_index);
+ _output_info.resize(next_job_index);
+ _initial_input_info.resize(next_job_index, 0);
+
+ op_seqs.iterate([&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &op_seq) {
+ auto job_index = op_seq_to_job[op_seq_index];
+ for (auto output : op_seq.getOutputs())
+ {
+ // Update output and input info
+ op_seqs.iterate(
+ [&](const ir::OpSequenceIndex &op_seq_cur_index, const ir::OpSequence &op_seq_cur) {
+ if (op_seq_cur.getInputs().contains(output))
+ {
+ auto dep_index = op_seq_to_job[op_seq_cur_index];
+ ++_initial_input_info[dep_index];
+ _output_info[job_index].push_back(dep_index);
+ }
+ });
+ }
+ });
+ for (const auto &s : op_seq_to_job)
+ _job_to_op_seq.emplace(s.second, s.first);
+
+ _input_info = _initial_input_info;
+}
+
+void DataflowExecutor::executeImpl()
+{
+ assert(noWaitingJobs());
+
+ bool dynamic_input_exists = hasDynamicInput();
+
+ // Execution setup
+ _waiting_jobs.swap(_finished_jobs); // Move finished jobs to waiting jobs
+
+ for (uint32_t i = 0; i < _waiting_jobs.size(); ++i)
+ {
+ if (_input_info[i] == 0)
+ {
+ emplaceToReadyJobs(i);
+ }
+ }
+ assert(!_ready_jobs.empty()); // Cannot begin if there is no initial jobs
+
+ _subject.notifyModelBegin(this);
+
+ while (!_ready_jobs.empty())
+ {
+ auto job = std::move((_ready_jobs.begin())->second);
+ _ready_jobs.erase(_ready_jobs.begin());
+ auto job_index = job->index();
+ VERBOSE(DataflowExecutor) << "Run job #" << job_index << std::endl;
+
+ auto op_seq_index = _job_to_op_seq[job_index];
+ auto op_seq = &_lowered_graph->op_seqs().at(op_seq_index);
+ const backend::Backend *backend =
+ _lowered_graph->getLowerInfo()->op_seq.at(op_seq_index)->backend();
+
+ _subject.notifyJobBegin(this, op_seq, backend);
+
+ job->fn_seq()->initRunning();
+
+ // check if FunctionSequence needs to handle dynamic tensor
+ bool handle_dynamic_tensor = op_seq->has_dynamic_tensor() || dynamic_input_exists;
+ job->fn_seq()->enableDynamicShapeInferer(handle_dynamic_tensor);
+
+ job->run();
+
+ _subject.notifyJobEnd(this, op_seq, backend);
+ notify(job_index);
+ _finished_jobs[job_index] = std::move(job);
+ }
+ assert(noWaitingJobs());
+
+ _subject.notifyModelEnd(this);
+
+ // Reset input info for the next execution
+ _input_info = _initial_input_info;
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/DataflowExecutor.h b/runtime/onert/core/src/exec/DataflowExecutor.h
new file mode 100644
index 000000000..69dfda15c
--- /dev/null
+++ b/runtime/onert/core/src/exec/DataflowExecutor.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_DATAFLOW_EXECUTOR_H__
+#define __ONERT_EXEC_DATAFLOW_EXECUTOR_H__
+
+#include <list>
+#include <map>
+#include <unordered_map>
+
+#include "exec/FunctionSequence.h"
+#include "Job.h"
+#include "ir/OperandIndexSequence.h"
+#include "ir/Index.h"
+#include <memory>
+#include "exec/ExecutorBase.h"
+#include "compiler/CodeMap.h"
+
+namespace onert
+{
+namespace exec
+{
+
+class DataflowExecutor : public ExecutorBase
+{
+
+protected:
+ virtual void notify(uint32_t finished_job_id);
+ bool noWaitingJobs();
+
+public:
+ /**
+ * @brief Constructs a DataflowExecutor object
+ *
+ * @param lowered_graph LoweredGraph object
+ * @param tensor_builders Tensor builders that are currently used
+ * @param code_map OpSequence and its code map
+ */
+ DataflowExecutor(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const std::vector<backend::ITensor *> &input_tensors,
+ const std::vector<backend::ITensor *> &output_tensors,
+ const compiler::TensorRegistries &tensor_regs, compiler::CodeMap &&code_map);
+
+ void executeImpl() override;
+
+protected:
+ int64_t calculateRank(const std::vector<ir::OperationIndex> &operations);
+ void emplaceToReadyJobs(const uint32_t &id);
+
+protected:
+ compiler::CodeMap _code_map;
+ /**
+ * @brief A vector of finished jobs for current execution
+ * After a run it has all the jobs of this execution for the next run
+ */
+ std::vector<std::unique_ptr<Job>> _finished_jobs;
+ /**
+ * @brief A vector of waiting jobs for current execution
+ * All the jobs are moved from #_finished_jobs to it when start a run
+ */
+ std::vector<std::unique_ptr<Job>> _waiting_jobs;
+ /**
+ * @brief Jobs' output info
+ * Used for notifying after finishing a job
+ */
+ std::vector<std::list<uint32_t>> _output_info;
+ std::vector<uint32_t> _initial_input_info;
+ std::vector<uint32_t> _input_info;
+ /**
+ * @brief A collection of jobs that are ready for execution
+ * Jobs in it are ready to be scheduled.
+ * Ordered by priority from `_indexed_ranks`
+ */
+ std::multimap<int64_t, std::unique_ptr<Job>, std::greater<int64_t>> _ready_jobs;
+
+ /// @brief Which job runs which op and function.
+ std::unordered_map<uint32_t, ir::OpSequenceIndex> _job_to_op_seq;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_DATAFLOW_EXECUTOR_H__
diff --git a/runtime/onert/core/src/exec/DynamicShapeInferer.cc b/runtime/onert/core/src/exec/DynamicShapeInferer.cc
new file mode 100644
index 000000000..5a40bba78
--- /dev/null
+++ b/runtime/onert/core/src/exec/DynamicShapeInferer.cc
@@ -0,0 +1,1236 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "exec/DynamicShapeInferer.h"
+#include "util/ShapeInference.h"
+#include <assert.h>
+
+namespace onert
+{
+namespace exec
+{
+
+void DynamicShapeInferer::handleBinaryArithmeticOp(const ir::Operation &op,
+ const ir::OperandIndex lhs_idx,
+ const ir::OperandIndex rhs_idx)
+{
+ auto lhs = _tensor_registry->getITensor(lhs_idx);
+ auto lhs_shape = lhs->getShape();
+
+ auto rhs = _tensor_registry->getITensor(rhs_idx);
+ auto rhs_shape = rhs->getShape();
+
+ /*
+ Here, the state after compilation (satic shape inference) could be one of the following:
+
+ lhs rhs output execution-time shape inf required
+ ------------------------------------------ ---------------------------------
+ case 1) static static static X
+ case 2) one or both are dynamic dynamic O
+
+ Then nnfw_apply_tensorinf() could change one or both inputs dynamic.
+ So, in this method, we have one more state and we have to re-calculate shape for this shape.
+
+ case 3) one or both are dynamic static O
+
+ So, only when all inputs are static, we can skip dynamic shape inference.
+ */
+ if ((!lhs->is_dynamic()) && (!rhs->is_dynamic()))
+ return;
+
+ auto output_idx = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_idx);
+
+ ir::Shape new_shape = shape_inference::inferEltwiseShape(lhs_shape, rhs_shape);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::handleSimpleUnaryOp(const ir::Operation &op,
+ const ir::OperandIndex input_ind)
+{
+ // check if input is not dynamic
+ auto input = _tensor_registry->getITensor(input_ind);
+ auto output_shape = input->getShape();
+
+ /*
+ Here, the state after compilation (satic shape inference) could be one of the following:
+
+ input output execution-time shape inf required
+ ------------------------- ---------------------------------
+ case 1) static static X
+ case 2) dynamic dynamic O
+
+ Then nnfw_apply_tensorinf() could change input dynamic.
+ So, in this method, we have one more state and we have to re-calculate shape for this shape.
+
+ case 3) dynamic static O
+
+ So, only when input is static, we can skip dynamic shape inference.
+ */
+ if (!input->is_dynamic())
+ return;
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::ArgMax &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::ArgMax::Input::INPUT)};
+ const auto input = _tensor_registry->getITensor(input_idx);
+
+ const auto axis_idx{op.getInputs().at(ir::operation::ArgMax::Input::AXIS)};
+ const auto axis = _tensor_registry->getITensor(axis_idx);
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ if (!input->is_dynamic() && !output->is_dynamic())
+ return;
+
+ auto input_shape = input->getShape();
+ auto axis_value = *reinterpret_cast<const int32_t *>(axis->buffer());
+ const auto rank = input_shape.rank();
+ axis_value = axis_value < 0 ? axis_value + rank : axis_value;
+
+ ir::Shape new_shape = shape_inference::inferArgMaxShape(input_shape, axis_value, rank);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::BatchMatMul &op)
+{
+ const auto lhs_index = op.getInputs().at(ir::operation::BatchMatMul::Input::LHS);
+ const auto rhs_index = op.getInputs().at(ir::operation::BatchMatMul::Input::RHS);
+ auto lhs = _tensor_registry->getITensor(lhs_index);
+ auto rhs = _tensor_registry->getITensor(rhs_index);
+
+ if (!lhs->is_dynamic() && !rhs->is_dynamic())
+ return;
+
+ const auto output_index = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_index);
+
+ auto lhs_shape = lhs->getShape();
+ auto rhs_shape = rhs->getShape();
+ // TODO
+
+ auto new_shape = shape_inference::inferBatchMatMulShape(lhs_shape, rhs_shape, op.param());
+ output->applyShape(new_shape);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::BCQFullyConnected &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::BCQFullyConnected::Input::INPUT)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+
+ const auto cluster_idx{
+ op.getInputs().at(ir::operation::BCQFullyConnected::Input::WEIGHTS_CLUSTERS)};
+ const auto &cluster = _tensor_registry->getITensor(cluster_idx);
+ assert(cluster->is_constant());
+
+ if (!input->is_dynamic())
+ return;
+
+ auto input_shape = input->getShape();
+ auto cluster_shape = cluster->getShape();
+
+ auto cluster_buf = reinterpret_cast<const int32_t *>(cluster->buffer());
+ assert(cluster_buf);
+
+ ir::Shape new_shape =
+ shape_inference::inferBCQFullyConnectedShape(input_shape, cluster_shape, cluster_buf);
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::BCQGather &op)
+{
+ const auto indices_idx{op.getInputs().at(ir::operation::BCQGather::Input::INDICES)};
+ const auto &indices = _tensor_registry->getITensor(indices_idx);
+
+ const auto input_binary_idx{op.getInputs().at(ir::operation::BCQGather::Input::INDICES)};
+ const auto &input_binary = _tensor_registry->getITensor(input_binary_idx);
+
+ const auto cluster_idx{op.getInputs().at(ir::operation::BCQGather::Input::INPUT_CLUSTERS)};
+ const auto &cluster = _tensor_registry->getITensor(cluster_idx);
+ assert(cluster->is_constant());
+
+ if (!indices->is_dynamic())
+ return;
+
+ auto indices_shape = indices->getShape();
+ auto cluster_shape = cluster->getShape();
+ auto rank = input_binary->getShape().rank();
+
+ auto cluster_buf = reinterpret_cast<const int32_t *>(cluster->buffer());
+ assert(cluster_buf);
+
+ ir::Shape new_shape = shape_inference::inferBCQGatherShape(indices_shape, cluster_shape,
+ cluster_buf, rank, op.param());
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::BinaryArithmetic &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::BinaryArithmetic::Input::LHS),
+ op.getInputs().at(ir::operation::BinaryArithmetic::Input::RHS));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::BroadcastTo &op)
+{
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ auto input_idx = op.getInputs().at(ir::operation::BroadcastTo::INPUT);
+ auto input = _tensor_registry->getITensor(input_idx);
+
+ if ((!input->is_dynamic()) && (!output->is_dynamic()))
+ return;
+
+ auto shape_idx = op.getInputs().at(ir::operation::Tile::Input::MULTIPLES);
+ const auto &shape = _tensor_registry->getITensor(shape_idx);
+
+ assert(shape); // It shouldn't be 0.
+
+ auto output_shape = shape_inference::inferBroadcastToShape(
+ shape->getShape(), reinterpret_cast<const int32_t *>(shape->buffer()));
+
+ // set output shape and output buffer
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Comparison &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::Comparison::Input::INPUT0),
+ op.getInputs().at(ir::operation::Comparison::Input::INPUT1));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Concat &op)
+{
+ /*
+ The state after compilation (satic shape inference) could be one of the following:
+
+ inputs output execution-time shape inf required
+ ------------------------------------------ ---------------------------------
+ case 1) all static static X
+ case 2) at least on is dynamic dynamic O
+
+ Then nnfw_apply_tensorinf() could change one or both inputs dynamic.
+ So, in this method, we have one more state and we have to re-calculate shape for this shape.
+
+ case 3) at least on is dynamic static O
+
+ So, only when all inputs are static, we can skip dynamic shape inference.
+ */
+ bool all_static = true;
+ for (auto input_ind : op.getInputs())
+ {
+ auto input = _tensor_registry->getITensor(input_ind);
+ if (input->is_dynamic())
+ {
+ all_static = false;
+ break;
+ }
+ }
+
+ if (all_static)
+ return;
+
+ // sanity check
+ {
+ auto isConcatible = [](const backend::ITensor *input1, const backend::ITensor *input2,
+ int32_t axis) {
+ if (input1->num_dimensions() != input2->num_dimensions())
+ return false;
+
+ for (size_t i = 0; i < input1->num_dimensions(); i++)
+ {
+ auto positive_axis = (axis >= 0) ? axis : axis + input1->num_dimensions();
+
+ if (i != positive_axis)
+ if (input1->dimension(i) != input2->dimension(i))
+ return false;
+ }
+
+ return true;
+ };
+
+ auto first_input_ind = op.getInputs().at(0);
+ auto first_input = _tensor_registry->getITensor(first_input_ind);
+
+ for (auto input_ind : op.getInputs())
+ {
+ auto input = _tensor_registry->getITensor(input_ind);
+ if (input != first_input && !isConcatible(first_input, input, op.param().axis))
+ throw std::runtime_error("input shapes does not matched for concat");
+ }
+ }
+
+ // getting output shape
+ onert::shape_inference::Shapes in_shapes;
+ for (auto input_ind : op.getInputs())
+ {
+ auto input = _tensor_registry->getITensor(input_ind);
+ ir::Shape shape = input->getShape();
+
+ in_shapes.emplace_back(shape);
+ }
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+ auto output_shape = shape_inference::inferConcatShape(in_shapes, op.param());
+
+ output->applyShape(output_shape);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Conv2D &op)
+{
+ // check if input is not dynamic
+ auto input_ind = op.getInputs().at(ir::operation::Conv2D::INPUT);
+ auto input = _tensor_registry->getITensor(input_ind);
+
+ auto ker_ind = op.getInputs().at(ir::operation::Conv2D::KERNEL);
+ auto ker = _tensor_registry->getITensor(ker_ind);
+
+ if ((!input->is_dynamic()) && (!ker->is_dynamic()))
+ return;
+
+ ir::Shape input_shape = input->getShape();
+ ir::Shape ker_shape = ker->getShape();
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ ir::Shape output_shape = shape_inference::inferConv2DShape(input_shape, ker_shape, op.param());
+
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::ElementwiseActivation &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::ElementwiseActivation::INPUT));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::ElementwiseBinary &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::ElementwiseBinary::Input::LHS),
+ op.getInputs().at(ir::operation::ElementwiseBinary::Input::RHS));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::ElementwiseUnary &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::ElementwiseUnary::Input::INPUT));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::ExpandDims &op)
+{
+ // check if input is not dynamic
+ auto input_ind = op.getInputs().at(ir::operation::ExpandDims::INPUT);
+ auto input = _tensor_registry->getITensor(input_ind);
+
+ // check if output is not dynamic, meaning when 1st input is static and 2nd input is const
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ /*
+ Here, the state after compilation (satic shape inference) could be one of the following:
+
+ input1 input2 output execution-time shape inf required
+ ----------------------------- --------------------------------
+ case 1) static const static X
+ case 2) static placeholder dynamic O
+ case 3) dynamic const dynamic O
+ case 4) dynamic placeholder dynamic O
+
+ Then nnfw_apply_tensorinf() could change input dynamic.
+ So, in this method, we could have one more state and we have to re-calculate shape
+ for this shape.
+
+ case 5) dynamic const static O
+
+ So, only when input1 and ouput are static, we can skip dynamic shape inference.
+ */
+ if ((!input->is_dynamic()) && (!output->is_dynamic()))
+ return;
+
+ ir::Shape input_shape = input->getShape();
+
+ auto axis_ind = op.getInputs().at(ir::operation::ExpandDims::AXIS);
+ auto axis = _tensor_registry->getITensor(axis_ind);
+ auto axis_buf = reinterpret_cast<const int32_t *>(axis->buffer());
+ assert(axis_buf);
+
+ auto output_shape = shape_inference::inferExpandDimsShape(input_shape, axis_buf[0]);
+
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Fill &op)
+{
+ // check if output is not dynamic
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+ auto input_ind = op.getInputs().at(ir::operation::Fill::Input::INPUT);
+ auto input = _tensor_registry->getITensor(input_ind);
+ ir::Shape input_shape = input->getShape();
+
+ if ((!input->is_dynamic()) && (!output->is_dynamic()))
+ return;
+
+ assert(input->data_type() == ir::DataType::INT32);
+
+ auto input_buf = reinterpret_cast<const int32_t *>(input->buffer());
+ assert(input_buf);
+
+ auto output_shape = shape_inference::inferFillShape(input_shape, input_buf);
+
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::FullyConnected &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::FullyConnected::Input::INPUT)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+
+ const auto ker_idx{op.getInputs().at(ir::operation::FullyConnected::Input::WEIGHT)};
+ const auto &ker = _tensor_registry->getITensor(ker_idx);
+
+ if (!input->is_dynamic() && !ker->is_dynamic())
+ return;
+
+ auto input_shape = input->getShape();
+ auto ker_shape = ker->getShape();
+
+ ir::Shape new_shape = shape_inference::inferFullyConnectedShape(input_shape, ker_shape);
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::FusedBatchNorm &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::FusedBatchNorm::Input::INPUT));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Gather &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Gather::Input::INPUT)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+ auto input_shape = input->getShape();
+
+ const auto indices_idx{op.getInputs().at(ir::operation::Gather::Input::INDICES)};
+ const auto &indices = _tensor_registry->getITensor(indices_idx);
+ auto indices_shape = indices->getShape();
+
+ if (!(input->is_dynamic()) && !(indices->is_dynamic()))
+ return;
+
+ const auto rank = input_shape.rank();
+ const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
+
+ assert(0 <= axis && axis < rank);
+
+ ir::Shape new_shape = shape_inference::inferGatherShape(input_shape, indices_shape, axis, rank);
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::L2Normalization &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::L2Normalization::INPUT));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::LSTM &op)
+{
+ const auto output_index{op.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)};
+ auto output = _tensor_registry->getITensor(output_index);
+
+ const auto output_state_out_index{
+ op.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)};
+
+ const auto cell_state_out_index{op.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)};
+
+ const auto scratch_buffer_index{op.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)};
+
+ if (!output->is_dynamic() &&
+ !(_tensor_registry->getITensor(output_state_out_index) != nullptr &&
+ _tensor_registry->getITensor(output_state_out_index)->is_dynamic()) &&
+ !(_tensor_registry->getITensor(cell_state_out_index) != nullptr &&
+ _tensor_registry->getITensor(cell_state_out_index)->is_dynamic()) &&
+ !(_tensor_registry->getITensor(scratch_buffer_index) != nullptr &&
+ _tensor_registry->getITensor(cell_state_out_index)->is_dynamic()))
+ return;
+
+ const auto input_index{op.getInputs().at(ir::operation::LSTM::Input::INPUT)};
+ const auto input = _tensor_registry->getITensor(input_index);
+ const auto input_shape = input->getShape();
+
+ const auto input_to_output_weights_index{
+ op.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)};
+ const auto input_to_output_weights = _tensor_registry->getITensor(input_to_output_weights_index);
+ const auto input_to_output_weights_shape = input_to_output_weights->getShape();
+
+ const auto recurrent_to_output_weights_index{
+ op.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS)};
+ const auto recurrent_to_output_weights =
+ _tensor_registry->getITensor(recurrent_to_output_weights_index);
+ const auto recurrent_to_output_weights_shape = recurrent_to_output_weights->getShape();
+
+ // re-sizing outputs
+ const int n_batch =
+ (input_shape.rank() == 3 && op.param().time_major) ? input_shape.dim(1) : input_shape.dim(0);
+ const int n_cell = input_to_output_weights_shape.dim(0);
+ const int n_output = recurrent_to_output_weights_shape.dim(1);
+ if (input_shape.rank() == 3)
+ {
+ if (op.param().time_major)
+ output->applyShape(ir::Shape{input_shape.dim(0), n_batch, n_output});
+ else
+ output->applyShape(ir::Shape{n_batch, input_shape.dim(1), n_output});
+ }
+ else
+ {
+ assert(input_shape.rank() == 2);
+ output->applyShape(ir::Shape{n_batch, n_output});
+ }
+ assert(output->buffer() != nullptr);
+
+ auto output_state_out = _tensor_registry->getITensor(output_state_out_index);
+ if (output_state_out != nullptr)
+ {
+ output_state_out->applyShape(ir::Shape{n_batch, n_output});
+ assert(output_state_out->buffer() != nullptr);
+ }
+
+ auto cell_state_out = _tensor_registry->getITensor(cell_state_out_index);
+ if (cell_state_out != nullptr)
+ {
+ cell_state_out->applyShape(ir::Shape{n_batch, n_cell});
+ assert(cell_state_out->buffer() != nullptr);
+ }
+
+ auto scratch_buffer = _tensor_registry->getITensor(scratch_buffer_index);
+ if (scratch_buffer != nullptr)
+ {
+ const auto input_to_input_weights_index{
+ op.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)};
+ const auto recurrent_to_input_weights_index{
+ op.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)};
+
+ const auto input_to_input_weights_shape =
+ _tensor_registry->getITensor(input_to_input_weights_index)->getShape();
+ bool has_input_to_input_weights =
+ input_to_input_weights_shape.dim(0) != 0 && input_to_input_weights_shape.dim(1) != 0;
+
+ const auto recurrent_to_input_weights_shape =
+ _tensor_registry->getITensor(recurrent_to_input_weights_index)->getShape();
+ bool has_recurrent_to_input_weights = recurrent_to_input_weights_shape.dim(0) != 0 &&
+ recurrent_to_input_weights_shape.dim(1) != 0;
+
+ // NOTE The cell_to_input_weights do not exist in non-peephole although regular LSTM(non-CIFG).
+ // true: no CIFG
+ // false: CIFG
+ bool has_cifg_param = has_input_to_input_weights && has_recurrent_to_input_weights;
+ if (has_cifg_param)
+ {
+ scratch_buffer->applyShape(ir::Shape{n_batch, n_cell * 4});
+ }
+ else
+ {
+ scratch_buffer->applyShape(ir::Shape{n_batch, n_cell * 3});
+ }
+ assert(scratch_buffer->buffer() != nullptr);
+ }
+}
+
+void DynamicShapeInferer::visit(const ir::operation::MatrixBandPart &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::MatrixBandPart::INPUT));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::OneHot &op)
+{
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ auto indices_ind = op.getInputs().at(ir::operation::OneHot::INDICES);
+ const auto &indices = _tensor_registry->getITensor(indices_ind);
+ auto indices_shape = indices->getShape();
+
+ auto depth_ind = op.getInputs().at(ir::operation::OneHot::DEPTH);
+ const auto &depth = _tensor_registry->getITensor(depth_ind);
+
+ if (!indices->is_dynamic() && !depth->is_dynamic())
+ {
+ return;
+ }
+
+ int32_t *depth_buf = reinterpret_cast<int32_t *>(depth->buffer());
+ assert(depth_buf);
+ const auto axis_val = op.param().axis;
+
+ ir::Shape new_shape = shape_inference::inferOnehotShape(indices_shape, *depth_buf, axis_val);
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Pack &op)
+{
+ bool is_any_of_inputs_dynamic = [&]() -> bool {
+ for (uint32_t i = 0; i < op.getInputs().size(); ++i)
+ {
+ const auto &input = _tensor_registry->getITensor(op.getInputs().at(i));
+ if (input->is_dynamic())
+ {
+ return true;
+ }
+ }
+ return false;
+ }();
+
+ const auto input_idx{op.getInputs().at(0)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+ auto input_shape = input->getShape();
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ if (!is_any_of_inputs_dynamic && !output->is_dynamic())
+ return;
+
+ const auto rank = input_shape.rank() + 1;
+ const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
+ const auto num = op.param().num;
+
+ assert(0 <= axis && axis < rank);
+
+ ir::Shape new_shape = shape_inference::inferPackShape(input_shape, axis, rank, num);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Pad &op)
+{
+ // check if output is not dynamic
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ auto input_ind = op.getInputs().at(ir::operation::Pad::Input::INPUT);
+ auto input = _tensor_registry->getITensor(input_ind);
+
+ auto pad_ind = op.getInputs().at(ir::operation::Pad::Input::PAD);
+ auto pad = _tensor_registry->getITensor(pad_ind);
+
+ // check if input and output are not dynamic
+ if ((!input->is_dynamic()) && (!output->is_dynamic()))
+ return;
+
+ int32_t *pad_buf = reinterpret_cast<int32_t *>(pad->buffer());
+ assert(pad_buf);
+
+ auto output_shape =
+ shape_inference::inferPadShape(input->getShape(), pad_buf, pad->getShape().num_elements());
+
+ // change output shape and reallocate output tensor memory
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Permute & /* op */)
+{
+ // NOTE Permute is a special operation which does not do shape inference before the actual
+ // function(kernel) execution. Shape inference and output allocation will be done in the kernel
+ // on-the-fly, as it must support inter-backend inference/allocation.
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Pow &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::Pow::Input::LHS),
+ op.getInputs().at(ir::operation::Pow::Input::RHS));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Range &op)
+{
+ // check if output is not dynamic
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ // from op, access the buffer of second input to read new shape
+ auto start_idx = op.getInputs().at(ir::operation::Range::Input::START);
+ auto start_tensor = _tensor_registry->getITensor(start_idx);
+
+ auto limit_idx = op.getInputs().at(ir::operation::Range::Input::LIMIT);
+ auto limit_tensor = _tensor_registry->getITensor(limit_idx);
+
+ auto delta_idx = op.getInputs().at(ir::operation::Range::Input::DELTA);
+ auto delta_tensor = _tensor_registry->getITensor(delta_idx);
+
+ if (!start_tensor->is_dynamic() && !limit_tensor->is_dynamic() && !delta_tensor->is_dynamic() &&
+ !output->is_dynamic())
+ return;
+
+ ir::Shape new_shape;
+ if (output->data_type() == ir::DataType::FLOAT32)
+ {
+ new_shape =
+ shape_inference::inferRangeShape<float>(*reinterpret_cast<float *>(start_tensor->buffer()),
+ *reinterpret_cast<float *>(limit_tensor->buffer()),
+ *reinterpret_cast<float *>(delta_tensor->buffer()));
+ }
+ else if (output->data_type() == ir::DataType::INT32)
+ {
+ new_shape = shape_inference::inferRangeShape<int32_t>(
+ *reinterpret_cast<int32_t *>(start_tensor->buffer()),
+ *reinterpret_cast<int32_t *>(limit_tensor->buffer()),
+ *reinterpret_cast<int32_t *>(delta_tensor->buffer()));
+ }
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Reduce &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Reduce::Input::INPUT)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+ auto input_shape = input->getShape();
+
+ const auto axes_idx{op.getInputs().at(ir::operation::Reduce::Input::AXES)};
+ const auto &axes = _tensor_registry->getITensor(axes_idx);
+
+ if (!input->is_dynamic())
+ return;
+
+ std::vector<int32_t> axes_vec;
+ for (uint32_t i = 0; i < axes->getShape().num_elements(); ++i)
+ {
+ const auto buffer = axes->buffer() + axes->calcOffset({i});
+ switch (axes->data_type())
+ {
+ case ir::DataType::INT32:
+ {
+ axes_vec.emplace_back(*reinterpret_cast<const int32_t *>(buffer));
+ break;
+ }
+ case ir::DataType::INT64:
+ {
+ axes_vec.emplace_back(*reinterpret_cast<const int64_t *>(buffer));
+ break;
+ }
+ default:
+ throw std::runtime_error("DynamicShapeInferer " + op.name() + ": Not supported data type");
+ break;
+ }
+ }
+ const auto keep_dims = op.param().keep_dims;
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ ir::Shape new_shape = shape_inference::inferReduceShape(input_shape, axes_vec, keep_dims);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Reshape &op)
+{
+ // check if output is not dynamic
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ auto input_ind = op.getInputs().at(ir::operation::Reshape::Input::INPUT);
+ auto input = _tensor_registry->getITensor(input_ind);
+
+ /*
+ Here, the state after compilation (satic shape inference) could be one of the following:
+
+ input1 input2 (or option) output execution-time shape inf required
+ ------------------------------------ --------------------------------
+ case 1) static const static X
+ case 2) static placeholder dynamic O
+ case 3) dynamic const dynamic O
+ case 4) dynamic placeholder dynamic O
+
+ Then nnfw_apply_tensorinf() could change input dynamic.
+ So, in this method, we could have one more state and we have to re-calculate shape
+ for this shape.
+
+ case 5) dynamic const static O
+
+ So, only when both input1 and ouput are static, we can skip dynamic shape inference.
+ */
+ if ((!input->is_dynamic()) && (!output->is_dynamic()))
+ return;
+
+ // New shape is given by second input tensor
+ if (op.getInputs().size() == 2)
+ {
+ // from op, access the buffer of second input to read new shape
+ auto new_shape_ind = op.getInputs().at(ir::operation::Reshape::Input::SHAPE);
+
+ // getting output shape by reading new_shape tensor buffer
+ auto new_shape = _tensor_registry->getITensor(new_shape_ind);
+ assert(new_shape);
+
+ int32_t *new_shape_buf = reinterpret_cast<int32_t *>(new_shape->buffer());
+ assert(new_shape_buf);
+
+ auto output_shape = shape_inference::inferReshapeShape(
+ new_shape_buf, new_shape->getShape().num_elements(), input->getShape().num_elements());
+
+ // if shape is changed, change output shape and reallocate output tensor memory
+ if (output_shape != output->getShape() || output->buffer() == nullptr)
+ {
+ // change on output shape
+ output->applyShape(output_shape);
+ }
+ assert(output->buffer() != nullptr);
+ }
+ // New shape is given by option
+ else if (op.param().new_shape.size() != 0)
+ {
+ // Let's check the new_shape option
+ auto shape = op.param().new_shape;
+ auto output_shape = shape_inference::inferReshapeShape(shape.data(), shape.size(),
+ input->getShape().num_elements());
+
+ // if shape is changed, change output shape and reallocate output tensor memory
+ if (output_shape != output->getShape() || output->buffer() == nullptr)
+ {
+ // change on output shape
+ output->applyShape(output_shape);
+ }
+ assert(output->buffer() != nullptr);
+ }
+ else
+ {
+ throw std::runtime_error("Reshape: new shape is missing");
+ return;
+ }
+}
+
+void DynamicShapeInferer::visit(const ir::operation::ResizeBilinear &op)
+{
+ // check if output is not dynamic
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ auto input_ind = op.getInputs().at(ir::operation::Reshape::Input::INPUT);
+ auto input = _tensor_registry->getITensor(input_ind);
+
+ if ((!input->is_dynamic()) && (!output->is_dynamic()))
+ return;
+
+ // getting output shape from input shape and Params
+ int32_t height_out, width_out;
+ if (op.getInputs().size() == 2)
+ {
+ auto size_ind = op.getInputs().at(ir::operation::ResizeBilinear::Input::SIZE);
+ auto size = _tensor_registry->getITensor(size_ind);
+ if (size->data_type() == ir::DataType::INT32)
+ {
+ auto size_buf = reinterpret_cast<const int32_t *>(size->buffer());
+ height_out = size_buf[0];
+ width_out = size_buf[1];
+ }
+ else
+ {
+ throw std::runtime_error("DynamicShapeInferer ResizeBilinear : Unsupported data type");
+ }
+ }
+ else
+ {
+ height_out = op.param().height_out;
+ width_out = op.param().width_out;
+ }
+ auto output_shape =
+ shape_inference::inferResizeBilinearShape(input->getShape(), height_out, width_out);
+
+ // if shape is changed, change output shape and reallocate output tensor memory
+ if (output_shape != output->getShape() || output->buffer() == nullptr)
+ {
+ // change on output shape
+ output->applyShape(output_shape);
+ }
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Reverse &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::Reverse::INPUT));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Select &op)
+{
+ const auto input_cond_idx = op.getInputs().at(ir::operation::Select::Input::CONDITION);
+ const auto &input_cond = _tensor_registry->getITensor(input_cond_idx);
+
+ const auto input_true_idx = op.getInputs().at(ir::operation::Select::Input::INPUT_TRUE);
+ const auto &input_true = _tensor_registry->getITensor(input_true_idx);
+
+ const auto input_false_idx = op.getInputs().at(ir::operation::Select::Input::INPUT_FALSE);
+ const auto &input_false = _tensor_registry->getITensor(input_false_idx);
+
+ if ((!input_cond->is_dynamic()) && (!input_true->is_dynamic()) && (!input_false->is_dynamic()))
+ {
+ return;
+ }
+
+ auto input_cond_shape = input_cond->getShape();
+ auto input_true_shape = input_true->getShape();
+ auto input_false_shape = input_false->getShape();
+
+ // Select output shpae
+ ir::Shape new_shape =
+ shape_inference::inferSelectShape(input_cond_shape, input_true_shape, input_false_shape);
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Shape &op)
+{
+ const auto input_idx{op.getInputs().at(0)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+ auto input_shape = input->getShape();
+
+ if (!input->is_dynamic())
+ return;
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ ir::Shape output_shape;
+ output_shape.append(input_shape.rank());
+
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Slice &op)
+{
+ const auto input_index{op.getInputs().at(ir::operation::Slice::Input::INPUT)};
+ const auto input = _tensor_registry->getITensor(input_index);
+ const auto begins_index{op.getInputs().at(ir::operation::Slice::Input::BEGINS)};
+ const auto begins = _tensor_registry->getITensor(begins_index);
+ const auto sizes_index{op.getInputs().at(ir::operation::Slice::Input::SIZES)};
+ const auto sizes = _tensor_registry->getITensor(sizes_index);
+ auto output_index = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_index);
+
+ if (!(input->is_dynamic() || begins->is_dynamic() || sizes->is_dynamic() || output->is_dynamic()))
+ {
+ return;
+ }
+
+ ir::Shape input_shape = input->getShape();
+ auto begins_buf = reinterpret_cast<const int32_t *>(begins->buffer());
+ auto sizes_buf = reinterpret_cast<const int32_t *>(sizes->buffer());
+
+ ir::Shape new_shape = shape_inference::inferSliceShape(input_shape, begins_buf, sizes_buf);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Softmax &op)
+{
+ handleSimpleUnaryOp(op, op.getInputs().at(ir::operation::Softmax::INPUT));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::SpaceToBatchND &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)};
+ const auto block_shape_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)};
+ const auto padding_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)};
+ auto output_idx{op.getOutputs().at(0)};
+
+ const auto &input = _tensor_registry->getITensor(input_idx);
+ const auto &block_shape = _tensor_registry->getITensor(block_shape_idx);
+ const auto &padding = _tensor_registry->getITensor(padding_idx);
+ auto output = _tensor_registry->getITensor(output_idx);
+
+ if (!(input->is_dynamic() || block_shape->is_dynamic() || padding->is_dynamic() ||
+ output->is_dynamic()))
+ {
+ return;
+ }
+
+ auto input_shape = input->getShape();
+ auto block_shape_shape = block_shape->getShape();
+ auto padding_shape = padding->getShape();
+
+ auto block_shape_data = reinterpret_cast<int32_t *>(block_shape->buffer());
+ auto padding_data = reinterpret_cast<int32_t *>(padding->buffer());
+
+ ir::Shape new_shape = shape_inference::inferSpaceToBatchNDShape(
+ input_shape, block_shape_shape, padding_shape, block_shape_data, padding_data);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Split &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Split::Input::INPUT)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+
+ // Return if all tensors are not dynamic
+ bool has_dynamic = false;
+ for (const auto output_idx : op.getOutputs())
+ {
+ auto output = _tensor_registry->getITensor(output_idx);
+ has_dynamic |= output->is_dynamic();
+ }
+ if (!input->is_dynamic() && !has_dynamic)
+ {
+ return;
+ }
+
+ auto input_shape = input->getShape();
+
+ const auto axis_idx{op.getInputs().at(ir::operation::Split::Input::AXIS)};
+ const auto &axis = _tensor_registry->getITensor(axis_idx);
+
+ auto axis_value = *reinterpret_cast<const int32_t *>(axis->buffer());
+ const auto num_splits = op.param().num_splits;
+ const auto rank = input_shape.rank();
+ axis_value = axis_value < 0 ? axis_value + rank : axis_value;
+
+ assert(0 <= axis_value && axis_value < rank);
+
+ ir::Shape new_shape = shape_inference::inferSplitShape(input_shape, axis_value, num_splits);
+ for (int out_tensor_idx = 0; out_tensor_idx < num_splits; out_tensor_idx++)
+ {
+ auto output_ind = op.getOutputs().at(out_tensor_idx);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+ }
+}
+
+void DynamicShapeInferer::visit(const ir::operation::SquaredDifference &op)
+{
+ handleBinaryArithmeticOp(op, op.getInputs().at(ir::operation::SquaredDifference::Input::LHS),
+ op.getInputs().at(ir::operation::SquaredDifference::Input::RHS));
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Squeeze &op)
+{
+ const auto input_idx{op.getInputs().at(ir::operation::Squeeze::Input::INPUT)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+
+ if (!input->is_dynamic())
+ {
+ return;
+ }
+
+ auto input_shape = input->getShape();
+
+ // Squeeze output shpae
+ ir::Shape new_shape = shape_inference::inferSqueezeShape(input_shape, op.param());
+
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::StridedSlice &op)
+{
+
+ const auto input_index{op.getInputs().at(ir::operation::StridedSlice::Input::INPUT)};
+ auto input = _tensor_registry->getITensor(input_index);
+ ir::Shape input_shape = input->getShape();
+
+ const auto starts_index{op.getInputs().at(ir::operation::StridedSlice::Input::STARTS)};
+ auto starts = _tensor_registry->getITensor(starts_index);
+
+ const auto ends_index{op.getInputs().at(ir::operation::StridedSlice::Input::ENDS)};
+ auto ends = _tensor_registry->getITensor(ends_index);
+
+ const auto strides_index{op.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)};
+ auto strides = _tensor_registry->getITensor(strides_index);
+
+ if (!(input->is_dynamic() || starts->is_dynamic() || ends->is_dynamic() || strides->is_dynamic()))
+ {
+ return;
+ }
+
+ const auto begin_mask = op.param().begin_mask;
+ const auto end_mask = op.param().end_mask;
+ const auto shrink_axis_mask = op.param().shrink_axis_mask;
+ const auto rank = input_shape.rank();
+
+ auto op_params = shape_inference::buildStridedSliceParams(
+ reinterpret_cast<uint32_t *>(starts->buffer()), reinterpret_cast<uint32_t *>(ends->buffer()),
+ reinterpret_cast<uint32_t *>(strides->buffer()), begin_mask, end_mask, shrink_axis_mask,
+ rank);
+
+ auto output_index = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_index);
+
+ ir::Shape output_shape =
+ onert::shape_inference::inferStridedSliceShape(input_shape, op_params, rank);
+
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Tile &op)
+{
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ auto input_idx = op.getInputs().at(ir::operation::Tile::Input::INPUT);
+ auto input = _tensor_registry->getITensor(input_idx);
+
+ auto multiplier_idx = op.getInputs().at(ir::operation::Tile::Input::MULTIPLES);
+ auto multiplier = _tensor_registry->getITensor(multiplier_idx);
+
+ if ((!input->is_dynamic()) && (!output->is_dynamic()))
+ return;
+
+ auto input_shape = input->getShape();
+ auto multiplier_buffer = reinterpret_cast<const int32_t *>(multiplier->buffer());
+ assert(multiplier_buffer);
+
+ auto output_shape =
+ shape_inference::inferTileShape(input_shape, multiplier_buffer, multiplier->dimension(0));
+
+ // set output shape and output buffer
+ output->applyShape(output_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Transpose &op)
+{
+ // check if output is not dynamic
+ auto output_ind = op.getOutputs().at(0);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ // from op, access the buffer of second input to read new shape
+ auto input_ind = op.getInputs().at(ir::operation::Transpose::Input::INPUT);
+ auto input = _tensor_registry->getITensor(input_ind);
+ auto input_shape = input->getShape();
+
+ /*
+ Here, the state after compilation (static shape inference) could be one of the following:
+
+ input perms output execution-time shape inf required
+ ------------------------------------ --------------------------------
+ case 1) static const static X
+ case 2) static non-const dynamic O
+ case 3) dynamic const dynamic O
+ case 4) dynamic non-const dynamic O
+
+ So, only when both input1 and ouput are static, we can skip dynamic shape inference.
+ */
+ if ((!input->is_dynamic()) && (!output->is_dynamic()))
+ return;
+
+ auto perm_ind = op.getInputs().at(ir::operation::Transpose::Input::PERMUTATION);
+ auto perm = _tensor_registry->getITensor(perm_ind);
+
+ ir::Shape new_shape;
+ // TODO Change perm->dimension(0) == 0 to perm->num_elements() == 0
+ if (perm->dimension(0) == 0) // This condition means that perm is (n-1...0)
+ {
+ // Call by (n-1...0)
+ new_shape = shape_inference::inferTransposeShape(input_shape, nullptr, 0);
+ }
+ else
+ {
+ // Check rank
+ if (input->num_dimensions() != perm->getShape().num_elements())
+ {
+ throw std::runtime_error("DynamicShapeInferer failed, bad rank size: " +
+ std::to_string(perm->getShape().num_elements()));
+ }
+
+ // set output shape, based on input and params
+ const auto perm_buffer = reinterpret_cast<const int32_t *>(perm->buffer());
+ new_shape = shape_inference::inferTransposeShape(input_shape, perm_buffer, perm->dimension(0));
+ }
+ output->applyShape(new_shape);
+ assert(output->buffer() != nullptr);
+}
+
+void DynamicShapeInferer::visit(const ir::operation::Unpack &op)
+{
+ // check if output is not dynamic
+ const auto input_idx{op.getInputs().at(0)};
+ const auto &input = _tensor_registry->getITensor(input_idx);
+
+ if (!input->is_dynamic())
+ return;
+
+ auto input_shape = input->getShape();
+
+ const auto rank = input_shape.rank();
+ const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
+ const auto num = op.param().num;
+
+ assert(0 <= axis && axis < rank);
+
+ ir::Shape new_shape = shape_inference::inferUnpackShape(input_shape, axis, rank);
+
+ for (int out_tensor_idx = 0; out_tensor_idx < num; out_tensor_idx++)
+ {
+ auto output_ind = op.getOutputs().at(out_tensor_idx);
+ auto output = _tensor_registry->getITensor(output_ind);
+
+ output->applyShape(new_shape);
+
+ assert(output->buffer() != nullptr);
+ }
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ExecTime.cc b/runtime/onert/core/src/exec/ExecTime.cc
new file mode 100644
index 000000000..6bf2744a9
--- /dev/null
+++ b/runtime/onert/core/src/exec/ExecTime.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "exec/ExecTime.h"
+
+#include <fstream>
+#include <cassert>
+#include <limits>
+#include <algorithm>
+
+namespace onert
+{
+namespace exec
+{
+
+int64_t ExecTime::getOperationExecTime(const backend::Backend *backend,
+ const std::string &operation, bool quant,
+ uint32_t op_size) const
+{
+ auto found_backend = _measurements.find(backend);
+ if (found_backend == _measurements.end())
+ return NOT_FOUND; // no execution time for this backend
+
+ auto found_operation_with_type = found_backend->second.find(operation);
+ if (found_operation_with_type == found_backend->second.end())
+ // no execution time for this operation
+ return NOT_FOUND;
+
+ auto found_operation = found_operation_with_type->second.find(quant);
+ if (found_operation == found_operation_with_type->second.end())
+ // no execution time for this operation
+ return NOT_FOUND;
+
+ auto found_size = found_operation->second.find(op_size);
+ if (found_size != found_operation->second.end())
+ return found_size->second; // found execution time
+
+ // Try to interpolate
+ if (found_operation->second.size() < 2)
+ // not possible to do linear interpolation
+ return found_operation->second.begin()->second;
+
+ // if we reach here, then this means, that there is no record, that is equal to op_size
+ auto upper_bound = found_operation->second.upper_bound(op_size); // > op_size
+ auto lower_bound = upper_bound;
+
+ if (upper_bound == found_operation->second.end()) // all values <= op_size
+ {
+ upper_bound--;
+ lower_bound = upper_bound;
+ lower_bound--;
+ }
+ else if (upper_bound == found_operation->second.begin()) // all values > op_size
+ {
+ upper_bound++;
+ }
+ else // op_size between
+ {
+ lower_bound--;
+ }
+
+ // Linear interpolation
+ const auto x0 = static_cast<int64_t>(lower_bound->first); // size
+ const auto x1 = static_cast<int64_t>(upper_bound->first); // size
+ const int64_t y0 = lower_bound->second; // time
+ const int64_t y1 = upper_bound->second; // time
+ const auto x = static_cast<int64_t>(op_size);
+
+ int64_t interpolated_value = y0 + (x - x0) * (y1 - y0) / (x1 - x0);
+
+ // In some cases ops with smaller inputs is executed slower than the one
+ // with larger inputs, more likely because of a backend's load difference
+ if (interpolated_value < 0 && x > x1)
+ {
+ return y0;
+ }
+ // It must be non-positive ONLY if it's lesser than both of them
+ assert(interpolated_value > 0 || x < x0);
+
+ // execution time must be non-negative
+ return std::max<int64_t>(interpolated_value, 1);
+}
+
+void ExecTime::updateOperationExecTime(const backend::Backend *backend,
+ const std::string &operation, bool quant, uint32_t op_size,
+ int64_t time)
+{
+ // If the op is not implemented for some input, it should not be scheduled
+ const auto &recs = _measurements[backend][operation][quant];
+ if (time == getMax() ||
+ std::any_of(recs.begin(), recs.end(),
+ [](std::pair<const uint32_t, const int64_t> p) { return p.second == getMax(); }))
+ {
+ _measurements[backend][operation][quant].clear();
+ _measurements[backend][operation][quant].emplace(op_size, getMax());
+ }
+ else
+ {
+ auto it = _measurements[backend][operation][quant].emplace(op_size, time);
+ if (!it.second)
+ {
+ // affect of the last measurement is bigger than the previous ones:
+ // this prefers new metrics than older once, so will adapt backend changes
+ it.first->second = (it.first->second + time) / 2;
+ }
+ }
+}
+
+void ExecTime::updatePermuteTime(const backend::Backend *from_backend,
+ const backend::Backend *to_backend, bool quant, uint32_t op_size,
+ int64_t time)
+{
+ updateOperationExecTime(from_backend, to_backend->config()->id(), quant, op_size, time);
+}
+
+int64_t ExecTime::getPermuteTime(const backend::Backend *from_backend,
+ const backend::Backend *to_backend, bool quant,
+ uint32_t op_size) const
+{
+ return getOperationExecTime(from_backend, to_backend->config()->id(), quant, op_size);
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ExecTime.h b/runtime/onert/core/src/exec/ExecTime.h
new file mode 100644
index 000000000..846d0930b
--- /dev/null
+++ b/runtime/onert/core/src/exec/ExecTime.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_EXEC_TIME_H__
+#define __ONERT_EXEC_EXEC_TIME_H__
+
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+#include "JSONExecTime.h"
+#include <memory>
+#include <limits>
+#include <map>
+#include <unordered_map>
+#include <vector>
+
+namespace onert
+{
+namespace exec
+{
+class ExecTime
+{
+public:
+ explicit ExecTime(const std::vector<const backend::Backend *> &backends)
+ : _json(backends, _measurements)
+ {
+ }
+
+public:
+ /**
+ * @brief Get exec time of an operation with input size
+ * or linearly interpolated value based on size if there is no record for given size
+ *
+ * @param[in] backend id of a backend
+ * @param[in] operation name of an operation
+ * @param[in] quant if input type quantized
+ * @param[in] op_size sum of operation's flattened sizes of inputs and outputs
+ * @return execution time for given input sizes
+ * -1 if there are no records for given parameters (backend, op, quantization).
+ */
+ int64_t getOperationExecTime(const backend::Backend *backend, const std::string &operation,
+ bool quant, uint32_t op_size) const;
+ /**
+ * @brief Update exec time of the operation on a backend with given input size or
+ * add new entity if there is no one.
+ *
+ * @param[in] backend id of a backend
+ * @param[in] operation name of an operation
+ * @param[in] quant if input type quantized
+ * @param[in] op_size sum of operation's flattened sizes of inputs and outputs
+ * @param[in] time real measured value
+ */
+ void updateOperationExecTime(const backend::Backend *backend, const std::string &operation,
+ bool quant, uint32_t op_size, int64_t time);
+ /**
+ * @brief Get the permute time from one backend to another
+ *
+ * @param[in] from_backend
+ * @param[in] to_backend
+ * @param[in] quant if input type quantized
+ * @param[in] op_size sum of operation's flattened sizes of inputs and outputs
+ * @return permutation time for operation size
+ */
+ int64_t getPermuteTime(const backend::Backend *from_backend, const backend::Backend *to_backend,
+ bool quant, uint32_t op_size) const;
+ /**
+ * @brief Update permute time from one backend to another
+ *
+ * @param[in] from_backend
+ * @param[in] to_backend
+ * @param[in] quant if input type quantized
+ * @param[in] time measured permutation time
+ * @param[in] op_size sum of operation's flattened sizes of inputs and outputs
+ */
+ void updatePermuteTime(const backend::Backend *from_backend, const backend::Backend *to_backend,
+ bool quant, uint32_t op_size, int64_t time);
+ /**
+ * @brief Get the max value of int32_t in int64_t
+ * @return max value
+ */
+ static int64_t getMax() { return _MAX; }
+ /**
+ * @brief Update metrics file with new data.
+ */
+ void uploadOperationsExecTime() const { _json.uploadOperationsExecTime(); }
+ static const int64_t NOT_FOUND = -1;
+
+private:
+ /// @brief Measurement data, which is shared with serializer
+ MeasurementData _measurements;
+ // int64_t::max may cause integer overflow
+ static const int64_t _MAX = std::numeric_limits<int32_t>::max();
+ /// @brief Serializer
+ JSON _json;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_EXEC_TIME_H__
diff --git a/runtime/onert/core/src/exec/Execution.cc b/runtime/onert/core/src/exec/Execution.cc
new file mode 100644
index 000000000..21fdd9c05
--- /dev/null
+++ b/runtime/onert/core/src/exec/Execution.cc
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "exec/Execution.h"
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace exec
+{
+
+Execution::Execution(const std::shared_ptr<ExecutorMap> &executors) : _executors{executors}
+{
+ assert(executors != nullptr);
+ assert(executors->at(ir::SubgraphIndex{0}) != nullptr);
+ const auto &primary_subg = primary_subgraph();
+ _io_desc.inputs.resize(primary_subg.getInputs().size());
+ _io_desc.outputs.resize(primary_subg.getOutputs().size());
+}
+
+void Execution::changeInputShape(const ir::IOIndex &index, const ir::Shape &new_shape)
+{
+ // This will be used later to set input tensor dynamic
+ // Note that 'compiled' model will not be updated with new_shape
+ // but new_shape will change model input shape while 'running' the model
+ _io_desc.dynamic_input_shapes[index] = new_shape;
+
+ VERBOSE(Execution) << "Model input shape will be changed at the start of execute()"
+ << "(index: " << index.value() << ")" << std::endl;
+}
+
+// TODO Remove default parameter
+void Execution::setInput(const ir::IOIndex &index, const void *buffer, size_t length,
+ ir::Layout layout)
+{
+ const auto input_index = primary_subgraph().getInputs().at(index);
+ const auto info = primary_subgraph().operands().at(input_index).info();
+
+ // TODO handle when (!buffer && length != 0) : setting the input as an optional tensor
+
+ // check if size enough for input is passed
+ // if input_shape_sig is set, input_shape_sig overrides shape in info
+ // note: input_shape_sig contains shape passed by nnfw_set_input_tensorinfo()
+ {
+ auto input_shape_sig = _io_desc.dynamic_input_shapes.find(index);
+ auto size_required = (input_shape_sig != _io_desc.dynamic_input_shapes.end())
+ ? input_shape_sig->second.num_elements() *
+ onert::ir::sizeOfDataType(info.typeInfo().type())
+ : info.total_size();
+
+ if (length < size_required)
+ {
+ throw std::runtime_error{"Too small length"};
+ }
+ }
+
+ _io_desc.inputs.at(index.value()) = std::make_unique<InputDesc>(info, buffer, length, layout);
+}
+
+// TODO Remove default parameter
+void Execution::setInput(const ir::IOIndex &index, const ir::TypeInfo &type, const ir::Shape &shape,
+ const void *buffer, size_t length, ir::Layout layout)
+{
+ auto info = ir::OperandInfo::createStaticInfo(shape, type);
+
+ if (length < info.total_size())
+ {
+ throw std::runtime_error{"Too small length"};
+ }
+
+ _io_desc.inputs.at(index.value()) = std::make_unique<InputDesc>(info, buffer, length, layout);
+}
+
+// TODO Remove default parameter
+void Execution::setOutput(const ir::IOIndex &index, void *buffer, size_t length, ir::Layout layout)
+{
+ const auto output_index = primary_subgraph().getOutputs().at(index);
+ const auto info = primary_subgraph().operands().at(output_index).info();
+
+ if (length < info.total_size())
+ {
+ throw std::runtime_error{"Too small length"};
+ }
+
+ _io_desc.outputs.at(index.value()) = std::make_unique<OutputDesc>(info, buffer, length, layout);
+}
+
+// TODO Remove default parameter
+void Execution::setOutput(const ir::IOIndex &index, const ir::TypeInfo &type,
+ const ir::Shape &shape, void *buffer, size_t length, ir::Layout layout)
+{
+ auto info = ir::OperandInfo::createStaticInfo(shape, type);
+
+ if (length < info.total_size())
+ {
+ throw std::runtime_error{"Too small length"};
+ }
+
+ _io_desc.outputs.at(index.value()) = std::make_unique<OutputDesc>(info, buffer, length, layout);
+}
+
+void Execution::setInputLayout(const ir::IOIndex &index, ir::Layout layout)
+{
+ const auto &input_desc = _io_desc.inputs.at(index.value());
+ _io_desc.inputs.at(index.value()) =
+ std::make_unique<InputDesc>(input_desc->info, input_desc->buffer, input_desc->size, layout);
+}
+
+void Execution::setOutputLayout(const ir::IOIndex &index, ir::Layout layout)
+{
+ const auto &output_desc = _io_desc.outputs.at(index.value());
+ _io_desc.outputs.at(index.value()) = std::make_unique<OutputDesc>(
+ output_desc->info, output_desc->buffer, output_desc->size, layout);
+}
+
+void Execution::execute()
+{
+ VERBOSE(Execution) << "Start execution" << std::endl;
+
+ primary_executor()->execute(_io_desc);
+ finished = true;
+
+ VERBOSE(Execution) << "Execution finished" << std::endl;
+}
+
+void Execution::startExecute()
+{
+ VERBOSE(Execution) << "Create asynchronous execution thread" << std::endl;
+
+ _exec_thread = std::make_unique<std::thread>(&Execution::execute, this);
+}
+
+void Execution::waitFinish()
+{
+ VERBOSE(Execution) << "Wait to finish execution" << std::endl;
+
+ _exec_thread->join();
+ finished = true;
+}
+
+bool Execution::isFinished(void) const { return finished; }
+
+ir::Shape Execution::getInputShape(ir::IOIndex ind) const
+{
+ auto itr = _io_desc.dynamic_input_shapes.find(ind);
+ if (itr == _io_desc.dynamic_input_shapes.end())
+ {
+ auto operand_idx = primary_subgraph().getInputs().at(ind.value());
+ return primary_subgraph().operands().at(operand_idx).shape();
+ }
+ else
+ {
+ return itr->second;
+ }
+}
+
+ir::Shape Execution::getOutputShape(ir::IOIndex ind) const
+{
+ if (!isFinished())
+ throw std::runtime_error("Cannot get output shape before execution is finished");
+
+ const auto &output_desc = _io_desc.outputs.at(ind.value());
+
+ return output_desc->info.shape();
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ExecutionObservee.cc b/runtime/onert/core/src/exec/ExecutionObservee.cc
new file mode 100644
index 000000000..ddb1fb6a0
--- /dev/null
+++ b/runtime/onert/core/src/exec/ExecutionObservee.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExecutionObservee.h"
+
+namespace onert
+{
+namespace exec
+{
+
+void ExecutionObservee::add(std::unique_ptr<IExecutionObserver> observer)
+{
+ _observers.emplace_back(std::move(observer));
+}
+
+void ExecutionObservee::notifyModelBegin(IExecutor *executor)
+{
+ for (auto &o : _observers)
+ {
+ o->handleBegin(executor);
+ }
+}
+
+void ExecutionObservee::notifyModelEnd(IExecutor *executor)
+{
+ for (auto &o : _observers)
+ {
+ o->handleEnd(executor);
+ }
+}
+
+void ExecutionObservee::notifyJobBegin(IExecutor *executor, const ir::OpSequence *op_seq,
+ const backend::Backend *backend)
+{
+ for (auto &o : _observers)
+ {
+ o->handleBegin(executor, op_seq, backend);
+ }
+}
+
+void ExecutionObservee::notifyJobEnd(IExecutor *executor, const ir::OpSequence *op_seq,
+ const backend::Backend *backend)
+{
+ for (auto &o : _observers)
+ {
+ o->handleEnd(executor, op_seq, backend);
+ }
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ExecutionObservee.h b/runtime/onert/core/src/exec/ExecutionObservee.h
new file mode 100644
index 000000000..49d409a3a
--- /dev/null
+++ b/runtime/onert/core/src/exec/ExecutionObservee.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_EXECUTION_OBSERVEE_H__
+#define __ONERT_EXEC_EXECUTION_OBSERVEE_H__
+
+#include <list>
+
+#include "exec/ExecutionObservers.h"
+
+namespace onert
+{
+namespace exec
+{
+
+/**
+ * @brief Class that
+ *
+ */
+class ExecutionObservee
+{
+public:
+ /**
+ * @brief Register an observer
+ *
+ * @param observer Observer to be added
+ */
+ void add(std::unique_ptr<IExecutionObserver> observer);
+ void notifyModelBegin(IExecutor *executor);
+ void notifyModelEnd(IExecutor *executor);
+ void notifyJobBegin(IExecutor *executor, const ir::OpSequence *op_seq,
+ const backend::Backend *backend);
+ void notifyJobEnd(IExecutor *executor, const ir::OpSequence *op_seq,
+ const backend::Backend *backend);
+
+private:
+ std::list<std::unique_ptr<IExecutionObserver>> _observers;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_EXECUTION_OBSERVEE__
diff --git a/runtime/onert/core/src/exec/ExecutionObservers.cc b/runtime/onert/core/src/exec/ExecutionObservers.cc
new file mode 100644
index 000000000..066b52ee1
--- /dev/null
+++ b/runtime/onert/core/src/exec/ExecutionObservers.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "exec/ExecutionObservers.h"
+
+#include <string>
+
+#include "util/logging.h"
+#include "exec/IExecutor.h"
+#include "misc/polymorphic_downcast.h"
+#include "ir/OpSequence.h"
+#include "util/EventWriter.h"
+
+namespace onert
+{
+
+namespace exec
+{
+
+void ProfileObserver::handleBegin(onert::exec::IExecutor *, const ir::OpSequence *,
+ const onert::backend::Backend *backend)
+{
+ _timer = backend->config()->timer();
+ if (_timer == nullptr)
+ throw std::runtime_error("To profile backend timer() method must be implemented");
+ _timer->handleBegin();
+}
+
+void ProfileObserver::handleEnd(IExecutor *exec, const ir::OpSequence *op_seq,
+ const backend::Backend *backend)
+{
+ _timer->handleEnd();
+ const auto timer_res = _timer->getTime();
+
+ // NOTE This assumes there is just one operation in a op_seq
+ const auto &node = _graph.operations().at(op_seq->operations().at(0));
+ auto node_name = node.name();
+ VERBOSE(ProfileInfo) << "Time for " << node_name << " : " << timer_res << std::endl;
+
+ // fill ExecTime:
+ bool is_quantized = exec->graph().operands().at(node.getInputs().at(0)).typeInfo().type() ==
+ ir::DataType::QUANT_UINT8_ASYMM;
+
+ uint32_t size = 0;
+ for (const auto &ind : (node.getInputs() + node.getOutputs()) | ir::Remove::UNDEFINED)
+ {
+ size += exec->graph().operands().at(ind).info().total_size();
+ }
+ if (node_name == "Permute")
+ {
+ // TODO Change it to updateOperationExecTime()
+ _et->updatePermuteTime(backend, backend, is_quantized, size, timer_res);
+ }
+ else
+ {
+ _et->updateOperationExecTime(backend, node_name, is_quantized, size, timer_res);
+ }
+};
+
+ChromeTracingObserver::ChromeTracingObserver(const std::string &filepath, const ir::Graph &graph)
+ : _base_filepath(filepath), _recorder{}, _collector{&_recorder}, _graph{graph}
+{
+}
+
+ChromeTracingObserver::~ChromeTracingObserver()
+{
+ try
+ {
+ EventWriter{_recorder}.writeToFiles(_base_filepath);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "E: Fail to record event in ChromeTracingObserver: " << e.what() << std::endl;
+ }
+}
+
+void ChromeTracingObserver::handleBegin(IExecutor *)
+{
+ _collector.onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "runtime", "Graph"});
+}
+
+void ChromeTracingObserver::handleBegin(IExecutor *, const ir::OpSequence *op_seq,
+ const backend::Backend *backend)
+{
+ std::string backend_id = backend->config()->id();
+ _collector.onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, backend_id,
+ opSequenceTag(op_seq, _graph.operations())});
+}
+
+void ChromeTracingObserver::handleEnd(IExecutor *, const ir::OpSequence *op_seq,
+ const backend::Backend *backend)
+{
+ std::string backend_id = backend->config()->id();
+ _collector.onEvent(EventCollector::Event{EventCollector::Edge::END, backend_id,
+ opSequenceTag(op_seq, _graph.operations())});
+}
+
+void ChromeTracingObserver::handleEnd(IExecutor *)
+{
+ _collector.onEvent(EventCollector::Event{EventCollector::Edge::END, "runtime", "Graph"});
+}
+
+std::string ChromeTracingObserver::opSequenceTag(const ir::OpSequence *op_seq,
+ const ir::Operations &operations)
+{
+ if (op_seq->size() == 0)
+ return "Empty OpSequence";
+
+ const auto &first_op_idx = op_seq->operations().at(0);
+ const auto &first_op_node = operations.at(first_op_idx);
+ std::string tag = "$" + std::to_string(first_op_idx.value());
+ tag += " " + first_op_node.name();
+ if (op_seq->size() > 1)
+ {
+ tag += " (+" + std::to_string(op_seq->size() - 1) + ")";
+ }
+ return tag;
+}
+
+} // namespace exec
+
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ExecutionObservers.h b/runtime/onert/core/src/exec/ExecutionObservers.h
new file mode 100644
index 000000000..f8c2acca5
--- /dev/null
+++ b/runtime/onert/core/src/exec/ExecutionObservers.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_OBSREVERS_H__
+#define __ONERT_EXEC_OBSREVERS_H__
+
+#include "exec/IFunction.h"
+#include "ir/OpSequence.h"
+#include "ExecTime.h"
+#include "util/ITimer.h"
+#include "exec/IExecutor.h"
+#include "util/EventCollector.h"
+#include "util/EventRecorder.h"
+
+namespace onert
+{
+namespace exec
+{
+class IExecutionObserver
+{
+public:
+ /// @brief Invoked just before model (not individual operation) execution begins
+ virtual void handleBegin(IExecutor *) { return; }
+
+ virtual void handleBegin(IExecutor *, const ir::OpSequence *, const backend::Backend *) = 0;
+ virtual void handleEnd(IExecutor *, const ir::OpSequence *, const backend::Backend *) = 0;
+
+ /// @brief Invoked just after model (not individual operation) execution ends
+ virtual void handleEnd(IExecutor *) { return; }
+
+ virtual ~IExecutionObserver() = default;
+};
+
+class ProfileObserver : public IExecutionObserver
+{
+public:
+ explicit ProfileObserver(std::shared_ptr<ExecTime> et, const ir::Graph &graph)
+ : _et(std::move(et)), _graph(graph)
+ {
+ }
+ void handleBegin(IExecutor *, const ir::OpSequence *, const backend::Backend *) override;
+ void handleEnd(IExecutor *, const ir::OpSequence *, const backend::Backend *) override;
+
+ void handleEnd(IExecutor *) override { _et->uploadOperationsExecTime(); }
+
+private:
+ std::unique_ptr<util::ITimer> _timer;
+ std::shared_ptr<ExecTime> _et;
+ const ir::Graph &_graph;
+};
+
+class ChromeTracingObserver : public IExecutionObserver
+{
+public:
+ ChromeTracingObserver(const std::string &filepath, const ir::Graph &graph);
+ ~ChromeTracingObserver();
+ void handleBegin(IExecutor *) override;
+ void handleBegin(IExecutor *, const ir::OpSequence *, const backend::Backend *) override;
+ void handleEnd(IExecutor *, const ir::OpSequence *, const backend::Backend *) override;
+ void handleEnd(IExecutor *) override;
+
+private:
+ static std::string opSequenceTag(const ir::OpSequence *op_seq, const ir::Operations &operations);
+
+private:
+ const std::string &_base_filepath;
+ EventRecorder _recorder;
+ EventCollector _collector;
+ const ir::Graph &_graph;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_OBSREVERS_H__
diff --git a/runtime/onert/core/src/exec/ExecutorBase.cc b/runtime/onert/core/src/exec/ExecutorBase.cc
new file mode 100644
index 000000000..018a0bba0
--- /dev/null
+++ b/runtime/onert/core/src/exec/ExecutorBase.cc
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExecutorBase.h"
+
+#include "backend/ITensor.h"
+#include "backend/controlflow/UserTensor.h"
+#include "backend/cpu_common/Tensor.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace exec
+{
+
+ExecutorBase::ExecutorBase(std::unique_ptr<compiler::LoweredGraph> &&lowered_graph,
+ const std::vector<backend::ITensor *> &input_tensors,
+ const std::vector<backend::ITensor *> &output_tensors,
+ const compiler::TensorRegistries &tensor_regs)
+ : _lowered_graph{std::move(lowered_graph)}, _graph{_lowered_graph->graph()},
+ _input_tensors{input_tensors}, _output_tensors{output_tensors}, _mutex()
+{
+ // TODO Fix the way of knowing whether it is primary or not
+ bool primary_executor = !(_input_tensors.empty() && _output_tensors.empty());
+ if (!primary_executor)
+ {
+ auto build_input_tensor_list = [&](const onert::ir::OperandIndexSequence &ind_seq) {
+ std::vector<backend::ITensor *> list;
+ for (auto ind : ind_seq)
+ {
+ backend::ITensor *tensor = tensor_regs.getITensor(ind);
+ assert(tensor != nullptr);
+ list.push_back(tensor);
+ }
+ return list;
+ };
+ auto build_output_tensor_list = [&](const onert::ir::OperandIndexSequence &ind_seq) {
+ std::vector<backend::ITensor *> list;
+ for (auto ind : ind_seq)
+ {
+ backend::ITensor *tensor = tensor_regs.getITensor(ind);
+ assert(tensor != nullptr);
+ list.push_back(tensor);
+ }
+ return list;
+ };
+ _input_tensors = build_input_tensor_list(_graph.getInputs());
+ _output_tensors = build_output_tensor_list(_graph.getOutputs());
+ }
+}
+
+void ExecutorBase::execute(const std::vector<backend::ITensor *> &src_tensors,
+ const std::shared_ptr<IPermuteFunction> &pre_fn)
+{
+ // For thread-safe, use mutex
+ // TODO: if all used backends on this executor are thread-safe,
+ // do not need to use mutex (otherwise, use mutex)
+ // Deadlock occurs when an Executor is called recursively.
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ assert(src_tensors.size() == _graph.getInputs().size());
+ assert(src_tensors.size() == _input_tensors.size());
+ for (uint32_t n = 0; n < _graph.getInputs().size(); ++n)
+ {
+ // when user changes input shape, the input tensor is dynamic and its memory is not allocated.
+ // This code find the info to allocate dynamic tensor, and allocate memory based on the source
+ // tensor's shape set by caller.
+ const auto src_tensor = src_tensors[n];
+ auto input_tensor = _input_tensors[n];
+ // If src_tensor or input_tensor is nullptr, pre_fn does not copy the tensors
+ if (src_tensor != nullptr && input_tensor != nullptr)
+ {
+ const auto orig_input_shape = input_tensor->getShape();
+ const auto changed_input_shape =
+ convertShape(src_tensor->getShape(), src_tensor->layout(), input_tensor->layout());
+ if (orig_input_shape != changed_input_shape)
+ {
+ input_tensor->set_dynamic();
+ }
+ }
+ }
+
+ // TODO Move calling permute_fn.run() into executeImpl()
+ assert(pre_fn);
+ pre_fn->run();
+
+ executeImpl();
+}
+
+void ExecutorBase::execute(const IODescription &desc)
+{
+ // For thread-safe, use mutex
+ // TODO: if all used backends on this executor are thread-safe,
+ // do not need to use mutex (otherwise, use mutex)
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ // Set input(s)
+ assert(_input_tensors.size() == desc.inputs.size());
+ for (uint32_t i = 0; i < _input_tensors.size(); ++i)
+ {
+ // TODO Remove dynamic_cast
+ auto *tensor = dynamic_cast<backend::controlflow::UserTensor *>(_input_tensors[i]);
+ assert(tensor);
+ auto input_shape = desc.dynamic_input_shapes.find(ir::IOIndex{i});
+ if (input_shape != desc.dynamic_input_shapes.end())
+ {
+ tensor->set_dynamic();
+ tensor->setShape(input_shape->second);
+ }
+ // TODO Check if (desc.inputs[i] == nullptr)
+ // TODO Better design for ITensor? (we need const_cast as ITensor is writable)
+ tensor->setBuffer(static_cast<uint8_t *>(const_cast<void *>(desc.inputs[i]->buffer)),
+ desc.inputs[i]->size);
+
+ handleDynamicInputTensor(ir::IOIndex{i}, desc);
+ }
+
+ assert(_output_tensors.size() == desc.outputs.size());
+ for (uint32_t i = 0; i < _output_tensors.size(); ++i)
+ {
+ // TODO Remove dynamic_cast
+ auto *tensor = dynamic_cast<backend::controlflow::UserTensor *>(_output_tensors[i]);
+ assert(tensor);
+ tensor->set_dynamic(); // It can't be resized but shape could change
+ if (desc.outputs[i] == nullptr)
+ throw std::runtime_error{"Output " + std::to_string(i) + "'s buffer is not set."};
+ tensor->setBuffer(static_cast<uint8_t *>(desc.outputs[i]->buffer), desc.outputs[i]->size);
+ }
+
+ executeImpl();
+
+ // Update output(s) desc
+ for (uint32_t n = 0; n < _graph.getOutputs().size(); ++n)
+ {
+ ir::IOIndex output_index{n};
+ // Optional output
+ if (desc.outputs.at(n) == nullptr)
+ {
+ continue;
+ }
+ auto &output = *desc.outputs.at(n);
+
+ // set shape of outputDesc to tensor shape since tensor can be dynamic
+ const auto output_tensor_shape = _output_tensors[n]->getShape();
+ output.info.shape(
+ convertShape(output_tensor_shape, _output_tensors[n]->layout(), output.layout));
+ }
+}
+
+/**
+ * @brief Changes tensor shape and allocate memory
+ * if input shape was changed by nnfw_set_input_tensorinfo()
+ *
+ * @note Cases are:
+ * 1) static operand -> nnfw_set_input_tensorinfo() -> execute() -> execute()
+ * (a) (b)
+ *
+ * at (a), operand is static, tensor is static - memory dealloc is not needed
+ * (DynamicTensorManager cannot dealloc memory allocated by StaticTensorManager)
+ * at (b), operand is static, tensor is dynamic - memory dealloc is needed
+ *
+ * 2) dynamic operand -> nnfw_set_input_tensorinfo() -> execute() -> execute()
+ * (a) (b)
+ *
+ * at (a), operand is dynamic, tensor is dynamic - memory dealloc is not needed
+ * since it has not been allocated yet
+ * at (b), operand is dynamic, tensor is dynamic - memory dealloc is needed
+ */
+void ExecutorBase::handleDynamicInputTensor(ir::IOIndex io_ind, const IODescription &desc)
+{
+ auto shape_sig_found = desc.dynamic_input_shapes.find(io_ind);
+ if (shape_sig_found != desc.dynamic_input_shapes.end())
+ {
+ auto changed_input_shape = shape_sig_found->second;
+ _input_tensors[io_ind.value()]->applyShape(changed_input_shape);
+ }
+}
+
+bool ExecutorBase::hasDynamicInput()
+{
+ for (auto &tensor : _input_tensors)
+ {
+ if (tensor->is_dynamic())
+ return true;
+ }
+ return false;
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ExecutorBase.h b/runtime/onert/core/src/exec/ExecutorBase.h
new file mode 100644
index 000000000..8a6ec9174
--- /dev/null
+++ b/runtime/onert/core/src/exec/ExecutorBase.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_EXECUTOR_BASE_H__
+#define __ONERT_EXEC_EXECUTOR_BASE_H__
+
+#include <mutex>
+
+#include "IPermuteFunction.h"
+#include "exec/ExecutionObservers.h"
+#include "ShapeConverter.h"
+#include "exec/IExecutor.h"
+#include "compiler/LoweredGraph.h"
+#include "ir/LowerInfoMap.h"
+#include "backend/IConfig.h"
+#include "backend/Backend.h"
+#include "exec/ExecTime.h"
+#include "exec/IFunction.h"
+#include "backend/IDynamicTensorManager.h"
+#include "backend/ITensorManager.h"
+#include "exec/ExecutionObservee.h"
+#include "compiler/TensorRegistries.h"
+#include <list>
+
+namespace onert
+{
+namespace exec
+{
+
+class ExecutorBase : public IExecutor
+{
+public:
+ /**
+ * @brief Construct a new ExecutorBase object
+ * @param graph Graph object
+ * @param tensor_builders Tensor builders that are currently used
+ */
+ ExecutorBase(std::unique_ptr<compiler::LoweredGraph> &&lowered_graph,
+ const std::vector<backend::ITensor *> &input_tensors,
+ const std::vector<backend::ITensor *> &output_tensors,
+ const compiler::TensorRegistries &tensor_regs);
+
+ virtual ~ExecutorBase() = default;
+
+ const ir::Graph &graph() final { return _graph; }
+
+ /**
+ * @brief Execute without IODescription
+ *
+ * @param src_tensor Tensor list that will be copied to input tensors of this
+ * @param pre_fn The permutation function that copy from src_tensor to input tensors of this
+ */
+ void execute(const std::vector<backend::ITensor *> &src_tensors,
+ const std::shared_ptr<IPermuteFunction> &pre_fn);
+
+ void execute(const IODescription &desc) final;
+
+ // Used only in Dataflow and Parallel Executors
+ void setIndexedRanks(std::shared_ptr<ir::OperationIndexMap<int64_t>> ranks) final
+ {
+ _indexed_ranks = std::move(ranks);
+ };
+
+ virtual void executeImpl(void) = 0;
+
+ void addObserver(std::unique_ptr<IExecutionObserver> ref) { _subject.add(std::move(ref)); };
+
+ const std::vector<backend::ITensor *> &getInputTensors() const { return _input_tensors; }
+
+ const std::vector<backend::ITensor *> &getOutputTensors() const { return _output_tensors; }
+
+protected:
+ /**
+ * @brief Returns @c true if any input tensor is dynamic; @c false if all are static tensors
+ */
+ bool hasDynamicInput();
+
+protected:
+ ExecutionObservee _subject;
+ std::shared_ptr<ir::OperationIndexMap<int64_t>> _indexed_ranks;
+ std::unique_ptr<compiler::LoweredGraph> _lowered_graph;
+ const ir::Graph &_graph;
+ std::vector<backend::ITensor *> _input_tensors;
+ std::vector<backend::ITensor *> _output_tensors;
+ std::mutex _mutex;
+
+private:
+ void handleDynamicInputTensor(ir::IOIndex input_index, const IODescription &desc);
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_EXECUTOR_BASE_H__
diff --git a/runtime/onert/core/src/exec/FunctionSequence.cc b/runtime/onert/core/src/exec/FunctionSequence.cc
new file mode 100644
index 000000000..8aefa5eeb
--- /dev/null
+++ b/runtime/onert/core/src/exec/FunctionSequence.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "exec/FunctionSequence.h"
+
+#include "ir/Operation.h"
+#include "backend/IDynamicTensorManager.h"
+#include "backend/ITensorRegistry.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace exec
+{
+
+void FunctionSequence::run()
+{
+ if (_enable_dynamic_shape_inferer && _dynamic_tensor_ctx)
+ {
+ // acl_cl and acl_neon backend don't support dynamic shape.
+ // _dynamic_tensor_ctx is always nullptr for acl_cl and acl_neon
+ // Thus, those two bakends cannot reach here.
+ if (_dynamic_tensor_ctx->op_seq->size() != _functions.size())
+ throw std::runtime_error("operation and functions should be mapped one by one");
+
+ auto op_seq_iter = _dynamic_tensor_ctx->op_seq->begin();
+ for (const auto &function : _functions)
+ {
+ // set shape of output and allocate memory when needed
+ auto &op = _dynamic_tensor_ctx->operations->at(*op_seq_iter);
+ op.accept(*_dynamic_tensor_ctx->dynamic_shape_inferer);
+
+ auto *sub_func_seq = dynamic_cast<FunctionSequence *>(function.get());
+ if (sub_func_seq != nullptr)
+ {
+ sub_func_seq->enableDynamicShapeInferer(true);
+ sub_func_seq->dynamic_tensor_ctx(dynamic_tensor_ctx());
+ }
+
+ // run kernel
+ function->run();
+
+ // deallocate input tensors which is no longer used
+ _dynamic_tensor_ctx->dynamic_tensor_manager->deallocInput(*op_seq_iter);
+
+ op_seq_iter++;
+ }
+ }
+ else
+ {
+ for (const auto &function : _functions)
+ {
+ function->run();
+ }
+ }
+}
+
+void FunctionSequence::prepare()
+{
+ for (const auto &function : _functions)
+ {
+ function->prepare();
+ }
+}
+
+void FunctionSequence::append(std::unique_ptr<IFunction> &&function)
+{
+ _functions.push_back(std::move(function));
+}
+
+void FunctionSequence::iterate(const std::function<void(IFunction &)> &fn)
+{
+ for (const auto &func : _functions)
+ {
+ fn(*func);
+ }
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/IPermuteFunction.h b/runtime/onert/core/src/exec/IPermuteFunction.h
new file mode 100644
index 000000000..11017edc9
--- /dev/null
+++ b/runtime/onert/core/src/exec/IPermuteFunction.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_I_PERMUTE_FUNCTION_H__
+#define __ONERT_EXEC_I_PERMUTE_FUNCTION_H__
+
+#include "feature/IndexIterator.h"
+#include "feature/nchw/Reader.h"
+#include "feature/nchw/View.h"
+#include "feature/nhwc/Reader.h"
+#include "feature/nhwc/View.h"
+
+#include "backend/ITensor.h"
+#include "exec/IFunction.h"
+#include "ir/Index.h"
+#include "ir/Shape.h"
+#include <memory>
+#include <typeinfo>
+#include "util/Utils.h"
+#include <vector>
+#include <unordered_map>
+
+namespace onert
+{
+namespace exec
+{
+
+inline void UpdateOffsets(::onert::backend::ITensor *src, ::onert::backend::ITensor *dst,
+ const ::onert::ir::Shape &loop_shape, std::vector<size_t> &src_offsets,
+ std::vector<size_t> &dst_offsets)
+{
+ ShapeLoop(loop_shape, [&](const onert::ir::Coordinates &coords) {
+ src_offsets.emplace_back(src->calcOffset(coords));
+ dst_offsets.emplace_back(dst->calcOffset(coords));
+ });
+}
+
+inline void CopyStatic(const uint8_t *src_buffer, uint8_t *dst_buffer,
+ const std::vector<size_t> &src_offsets,
+ const std::vector<size_t> &dst_offsets, size_t copy_len)
+{
+ assert(src_offsets.size() == dst_offsets.size());
+ for (size_t i = 0; i < src_offsets.size(); ++i)
+ {
+ memcpy(dst_buffer + dst_offsets.at(i), src_buffer + src_offsets.at(i), copy_len);
+ }
+}
+
+inline void CopyDynamic(const ::onert::backend::ITensor *src, const ::onert::backend::ITensor *dst,
+ uint8_t *dst_buffer, const ::onert::ir::Shape &loop_shape, size_t copy_len)
+{
+ ShapeLoop(loop_shape, [&](const onert::ir::Coordinates &coords) {
+ // Copy src tensor's data to dst_buffer with calculated offset of dst tensor
+ memcpy(dst_buffer + dst->calcOffset(coords), src->buffer() + src->calcOffset(coords), copy_len);
+ });
+}
+
+class IPermuteFunction : public IFunction
+{
+protected:
+ enum class PermuteType
+ {
+ NHWC_TO_NCHW,
+ NCHW_TO_NHWC,
+ COPY
+ };
+
+public:
+ virtual void run() override
+ {
+ // TODO Optimization : Make control does not reach here? when (_src_tensors.size() == 0)
+ assert(_src_tensors.size() == _dst_tensors.size());
+ if (_src_tensors_offsets.size() == 0)
+ {
+ _src_tensors_offsets.resize(_src_tensors.size());
+ _dst_tensors_offsets.resize(_dst_tensors.size());
+ }
+ assert(_src_tensors.size() == _src_tensors_offsets.size());
+ assert(_src_tensors_offsets.size() == _dst_tensors_offsets.size());
+
+ for (size_t i = 0; i < _src_tensors.size(); ++i)
+ {
+ auto src_tensor = _src_tensors.at(i);
+ auto dst_tensor = _dst_tensors.at(i);
+ auto &src_offsets = _src_tensors_offsets.at(i);
+ auto &dst_offsets = _dst_tensors_offsets.at(i);
+ if (src_tensor != dst_tensor)
+ {
+ const auto rank = src_tensor->num_dimensions();
+ permute(src_tensor, dst_tensor, rank, src_offsets, dst_offsets);
+ }
+ }
+ }
+
+ virtual void prepare() override { optimize(); }
+
+ virtual void optimize() = 0;
+
+protected:
+ void permute(backend::ITensor *src_tensor, backend::ITensor *dst_tensor, size_t rank,
+ std::vector<size_t> &src_offsets, std::vector<size_t> &dst_offsets)
+ {
+ if (src_tensor->total_size() == 0)
+ {
+ assert(dst_tensor->total_size() == 0);
+ return;
+ }
+
+ assert(src_tensor != dst_tensor);
+ assert(underlying_type(src_tensor->data_type()) == underlying_type(dst_tensor->data_type()));
+ switch (src_tensor->data_type())
+ {
+ case ir::DataType::FLOAT32:
+ permute<float>(src_tensor, dst_tensor, rank, src_offsets, dst_offsets);
+ break;
+ case ir::DataType::INT32:
+ permute<int32_t>(src_tensor, dst_tensor, rank, src_offsets, dst_offsets);
+ break;
+ case ir::DataType::UINT32:
+ permute<uint32_t>(src_tensor, dst_tensor, rank, src_offsets, dst_offsets);
+ break;
+ case ir::DataType::BOOL8:
+ case ir::DataType::QUANT_UINT8_ASYMM:
+ case ir::DataType::UINT8:
+ permute<uint8_t>(src_tensor, dst_tensor, rank, src_offsets, dst_offsets);
+ break;
+ case ir::DataType::QUANT_INT8_ASYMM:
+ case ir::DataType::QUANT_INT8_SYMM:
+ permute<int8_t>(src_tensor, dst_tensor, rank, src_offsets, dst_offsets);
+ break;
+ case ir::DataType::INT64:
+ permute<int64_t>(src_tensor, dst_tensor, rank, src_offsets, dst_offsets);
+ break;
+ default:
+ throw std::runtime_error("IPermuteFunction: Not supported data type");
+ break;
+ }
+ }
+
+private:
+ // TODO make src const by proving const access()
+ template <class T>
+ void permute(backend::ITensor *src, backend::ITensor *dst, size_t rank,
+ std::vector<size_t> &src_offsets, std::vector<size_t> &dst_offsets)
+ {
+ assert(src->total_size() != 0 && dst->total_size() != 0);
+ // If dst is subtensor, we have to use clEnqueueMapBuffer instead of clEnqueueWirteBuffer
+ if (dst->needMemoryMap() && !dst->is_subtensor())
+ {
+ // A assertion to check mapping without calling map()
+ // Now there is no case where both src and dst have cl buffer.
+ assert(!src->needMemoryMap());
+
+ if (!src->has_padding() && !dst->has_padding() && src->layout() == dst->layout())
+ {
+ src->access([&](backend::ITensor &) { dst->enqueueWriteBuffer(src->buffer(), false); });
+ }
+ else
+ {
+ // TODO Optimize this block in case of that padding size of dst is big.
+ _buffers_map[dst].reserve(dst->total_size());
+ auto dst_buffer = _buffers_map[dst].data();
+ src->access([&](backend::ITensor &) {
+ permute<T>(src, dst, rank, dst_buffer, dst->total_size(), src_offsets, dst_offsets);
+ });
+ dst->enqueueWriteBuffer(dst_buffer, false);
+ }
+ }
+ else if (src->needMemoryMap() && !src->is_subtensor() && !src->has_padding() &&
+ !dst->has_padding() && src->layout() == dst->layout())
+ {
+ assert(!dst->needMemoryMap());
+ dst->access([&](backend::ITensor &) { src->enqueueReadBuffer(dst->buffer(), true); });
+ }
+ else
+ {
+ auto fn = [&](backend::ITensor &) {
+ dst->access([&](backend::ITensor &) {
+ permute<T>(src, dst, rank, dst->buffer(), dst->total_size(), src_offsets, dst_offsets);
+ });
+ };
+ src->access(fn);
+ }
+ }
+
+ template <class T>
+ void permute(backend::ITensor *src, backend::ITensor *dst, size_t rank, uint8_t *dst_buffer,
+ size_t dst_size, std::vector<size_t> &src_offsets, std::vector<size_t> &dst_offsets)
+ {
+ assert(dst_buffer != nullptr);
+ assert(dst_size == dst->total_size());
+
+ const auto permute_type = [&]() -> PermuteType {
+ if (src->layout() == ir::Layout::NHWC && dst->layout() == ir::Layout::NCHW)
+ {
+ return PermuteType::NHWC_TO_NCHW;
+ }
+ else if (src->layout() == ir::Layout::NCHW && dst->layout() == ir::Layout::NHWC)
+ {
+ return PermuteType::NCHW_TO_NHWC;
+ }
+ else
+ {
+ return PermuteType::COPY;
+ }
+ }();
+ if (rank == 4 && permute_type != PermuteType::COPY)
+ {
+ switch (permute_type)
+ {
+ case PermuteType::NHWC_TO_NCHW:
+ {
+ ir::FeatureShape shape;
+ shape.N = dst->dimension(0);
+ shape.C = dst->dimension(1);
+ shape.H = dst->dimension(2);
+ shape.W = dst->dimension(3);
+
+ typename feature::nchw::View<T>::Strides strides;
+ const auto start_offset = dst->calcOffset({0, 0, 0, 0});
+ strides.W = dst->dimension(3) == 1 ? 0 : dst->calcOffset({0, 0, 0, 1}) - start_offset;
+ strides.H = dst->dimension(2) == 1 ? 0 : dst->calcOffset({0, 0, 1, 0}) - start_offset;
+ strides.C = dst->dimension(1) == 1 ? 0 : dst->calcOffset({0, 1, 0, 0}) - start_offset;
+ strides.N = dst->dimension(0) == 1 ? 0 : dst->calcOffset({1, 0, 0, 0}) - start_offset;
+
+ const feature::nhwc::Reader<T> from(src);
+ feature::nchw::View<T> into(shape, strides,
+ reinterpret_cast<T *>(dst_buffer + start_offset), dst_size);
+ feature::iterate(shape) << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, row, col, ch);
+ into.at(batch, ch, row, col) = value;
+ };
+ break;
+ }
+ case PermuteType::NCHW_TO_NHWC:
+ {
+ ir::FeatureShape shape;
+ shape.N = dst->dimension(0);
+ shape.H = dst->dimension(1);
+ shape.W = dst->dimension(2);
+ shape.C = dst->dimension(3);
+
+ typename feature::nhwc::View<T>::Strides strides;
+ const auto start_offset = dst->calcOffset({0, 0, 0, 0});
+ strides.C = dst->dimension(3) == 1 ? 0 : dst->calcOffset({0, 0, 0, 1}) - start_offset;
+ strides.W = dst->dimension(2) == 1 ? 0 : dst->calcOffset({0, 0, 1, 0}) - start_offset;
+ strides.H = dst->dimension(1) == 1 ? 0 : dst->calcOffset({0, 1, 0, 0}) - start_offset;
+ strides.N = dst->dimension(0) == 1 ? 0 : dst->calcOffset({1, 0, 0, 0}) - start_offset;
+
+ const feature::nchw::Reader<T> from(src);
+ feature::nhwc::View<T> into(shape, strides,
+ reinterpret_cast<T *>(dst_buffer + start_offset), dst_size);
+ feature::iterate(shape) << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, ch, row, col);
+ into.at(batch, row, col, ch) = value;
+ };
+ break;
+ }
+ default:
+ {
+ throw std::runtime_error("Unsupported Permutation");
+ break;
+ }
+ }
+ }
+ else if (!src->has_padding() && !dst->has_padding())
+ {
+ auto src_size = src->total_size();
+ assert(src_size <= dst->total_size());
+ memcpy(dst_buffer, src->buffer(), src_size);
+ }
+ else
+ {
+ auto loop_shape = src->getShape();
+ const auto copy_axis = loop_shape.rank() - 1;
+ const auto copy_len = loop_shape.dim(copy_axis) * sizeof(T);
+ loop_shape.dim(copy_axis) = 1;
+
+ if (src->is_dynamic())
+ {
+ assert(dst->is_dynamic());
+ CopyDynamic(src, dst, dst_buffer, loop_shape, copy_len);
+ }
+ else
+ {
+ // TODO Uncomment the assertion below
+ // assert(!dst->is_dynamic() || dst is output of graph);
+ if (src_offsets.size() == 0)
+ {
+ assert(dst_offsets.size() == 0);
+
+ auto loop_shape = src->getShape();
+ const auto copy_axis = loop_shape.rank() - 1;
+ loop_shape.dim(copy_axis) = 1;
+ UpdateOffsets(src, dst, loop_shape, src_offsets, dst_offsets);
+ }
+ CopyStatic(src->buffer(), dst_buffer, src_offsets, dst_offsets, copy_len);
+ }
+ }
+ }
+
+protected:
+ // NOTE The typeid expression is lvalue expression which refers to an object with static storage
+ // duration, of the polymorphic type const std::type_info or of some type derived from it.
+ // So std::type_info is non-copyable
+ const std::type_info &underlying_type(ir::DataType type) const
+ {
+ switch (type)
+ {
+ case ir::DataType::FLOAT32:
+ return typeid(float);
+ case ir::DataType::INT32:
+ return typeid(int32_t);
+ case ir::DataType::UINT32:
+ return typeid(uint32_t);
+ case ir::DataType::INT64:
+ return typeid(int64_t);
+ case ir::DataType::BOOL8:
+ case ir::DataType::QUANT_UINT8_ASYMM:
+ case ir::DataType::UINT8:
+ return typeid(uint8_t);
+ case ir::DataType::QUANT_INT8_ASYMM:
+ case ir::DataType::QUANT_INT8_SYMM:
+ return typeid(int8_t);
+ default:
+ throw std::runtime_error("IPermuteFunction: Not supported data type");
+ }
+ }
+
+protected:
+ std::vector<backend::ITensor *> _src_tensors;
+ std::vector<backend::ITensor *> _dst_tensors;
+ std::vector<std::vector<size_t>> _src_tensors_offsets;
+ std::vector<std::vector<size_t>> _dst_tensors_offsets;
+ std::unordered_map<const backend::ITensor *, std::vector<uint8_t>> _buffers_map;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_I_PERMUTE_FUNCTION_H__
diff --git a/runtime/onert/core/src/exec/JSONExecTime.cc b/runtime/onert/core/src/exec/JSONExecTime.cc
new file mode 100644
index 000000000..72a18def1
--- /dev/null
+++ b/runtime/onert/core/src/exec/JSONExecTime.cc
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "exec/JSONExecTime.h"
+#include "backend/IConfig.h"
+#include <fstream>
+
+namespace onert
+{
+namespace exec
+{
+/**
+ * @brief Helper function for reading string from stream
+ *
+ * @param str Output string
+ * @param stream File stream
+ */
+void readString(std::string &str, std::ifstream &stream)
+{
+ str.clear();
+ char buf;
+ while (stream.good())
+ {
+ stream.get(buf);
+ if (buf == '"')
+ break;
+ str.push_back(buf);
+ }
+}
+
+/**
+ * @brief Helper function for reading bool from stream
+ *
+ * @param quant Output bool
+ * @param stream File stream
+ */
+void readBool(bool &quant, std::ifstream &stream)
+{
+ char buf;
+ stream.get(buf);
+ quant = (buf == '1');
+ stream.get(buf);
+}
+
+void printString(const std::string &str, std::ofstream &stream) { stream << "\"" << str << "\""; }
+
+void printBool(bool quant, std::ofstream &stream) { stream << "\"" << quant << "\""; }
+
+void JSON::readOperation(const std::string &backend, const std::string &operation, bool quant,
+ std::ifstream &stream)
+{
+ uint32_t size = 0;
+ int64_t time = 0;
+
+ std::string int_buf;
+ char buf;
+ int number_of_closed_braces = 0;
+ int number_of_commas = 0;
+
+ while (stream.good())
+ {
+ stream.get(buf);
+
+ switch (buf)
+ {
+ case ']':
+ {
+ number_of_closed_braces++;
+ break;
+ }
+ case '[':
+ {
+ number_of_closed_braces--;
+ break;
+ }
+ default:
+ {
+ if (std::isdigit(buf))
+ {
+ int_buf.push_back(buf);
+ }
+ break;
+ }
+ }
+
+ if (number_of_closed_braces == 1)
+ break;
+
+ if ((buf == ']' && number_of_closed_braces == 0) ||
+ (buf == ',' && number_of_closed_braces == -1))
+ {
+ switch (number_of_commas % 2)
+ {
+ case 0:
+ {
+ size = static_cast<uint32_t>(std::atoi(int_buf.c_str()));
+ break;
+ }
+ case 1:
+ {
+ time = static_cast<int64_t>(std::atol(int_buf.c_str()));
+ auto bf = _backends.find(backend);
+ if (bf != _backends.end())
+ {
+ _measurements[bf->second][operation][quant][size] = time;
+ } // we ignore the records for unsupported backends
+ break;
+ }
+ }
+ number_of_commas++;
+ int_buf.clear();
+ }
+ }
+}
+void JSON::printOperation(const std::map<uint32_t, int64_t> &operation_info,
+ std::ofstream &stream) const
+{
+ for (const auto &items : operation_info)
+ {
+ stream << "[" << items.first << ", " << items.second << "], ";
+ }
+ stream.seekp(-2, std::ofstream::end);
+}
+
+void JSON::uploadOperationsExecTime() const
+{
+ std::ofstream stream(_measurement_file);
+ if (!stream.is_open())
+ {
+ throw std::runtime_error("Failed to save backend config file");
+ }
+ else
+ {
+ stream << "{";
+ for (const auto &backend : _measurements)
+ {
+ printString(backend.first->config()->id(), stream);
+ stream << ": {";
+ for (const auto &operation : backend.second)
+ {
+ printString(operation.first, stream);
+ stream << ": {";
+ for (const auto &type : operation.second)
+ {
+ printBool(type.first, stream);
+ stream << ": [";
+ printOperation(type.second, stream);
+ stream << "], ";
+ }
+ stream.seekp(-2, std::ofstream::end);
+ stream << "}, ";
+ }
+ stream.seekp(-2, std::ofstream::end);
+ stream << "}, ";
+ }
+ stream.seekp(-2, std::ofstream::end);
+ stream << "}";
+ stream.close();
+ }
+}
+
+void JSON::loadOperationsExecTime()
+{
+ std::ifstream stream(_measurement_file);
+ if (stream.is_open())
+ {
+ std::string backend;
+ std::string operation;
+ bool quant = false;
+ char buf;
+ int number_of_open_braces = 0;
+
+ while (stream.good())
+ {
+ stream.get(buf);
+ switch (buf)
+ {
+ case '{':
+ number_of_open_braces++;
+ break;
+ case '}':
+ number_of_open_braces--;
+ break;
+ case '"':
+ {
+ if (number_of_open_braces == 1)
+ {
+ // read backend string
+ readString(backend, stream);
+ }
+ if (number_of_open_braces == 2)
+ {
+ // read operation string
+ readString(operation, stream);
+ }
+ if (number_of_open_braces == 3)
+ {
+ // read operation string
+ readBool(quant, stream);
+ }
+ break;
+ }
+ case '[':
+ {
+ // reading and creating all info for operation
+ readOperation(backend, operation, quant, stream);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ stream.close();
+ }
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/JSONExecTime.h b/runtime/onert/core/src/exec/JSONExecTime.h
new file mode 100644
index 000000000..a64cb3133
--- /dev/null
+++ b/runtime/onert/core/src/exec/JSONExecTime.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_JSON_EXEC_TIME_H__
+#define __ONERT_EXEC_JSON_EXEC_TIME_H__
+
+#include <fstream>
+#include <unordered_map>
+#include <map>
+#include <vector>
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+
+namespace onert
+{
+namespace exec
+{
+
+/**
+ * @brief table, that contains execution time of an operation on some backend for different input
+ * sizes and transfer time from one backend to another for various input sizes (permutation time)
+ *
+ * backend -> op -> quant-> size --> time
+ * _measurements[Backend*]["string"][bool][uint32_t] = int64_t
+ */
+using MeasurementData = std::unordered_map<
+ const backend::Backend *,
+ std::unordered_map<std::string, std::unordered_map<bool, std::map<uint32_t, int64_t>>>>;
+
+class JSON
+{
+public:
+ explicit JSON(const std::vector<const backend::Backend *> &backends,
+ MeasurementData &measurements)
+ : _measurement_file("exec_time.json"), _backends(), _measurements(measurements)
+ {
+ for (const auto b : backends)
+ {
+ _backends.emplace(b->config()->id(), b);
+ }
+ loadOperationsExecTime();
+ };
+ /**
+ * @brief Update _operations_exec_time_file with new data.
+ */
+ void uploadOperationsExecTime() const;
+
+private:
+ ///@brief file containing measurements
+ std::string _measurement_file;
+ std::unordered_map<std::string, const backend::Backend *> _backends;
+ std::unordered_map<
+ const backend::Backend *,
+ std::unordered_map<std::string, std::unordered_map<bool, std::map<uint32_t, int64_t>>>>
+ &_measurements;
+ /**
+ * @brief Helper function for inserting data to OperationExecTimes
+ *
+ * @param backend String name of backend
+ * @param operation String name of operation
+ * @param quant if input type quantized
+ * @param stream File stream
+ */
+ void readOperation(const std::string &backend, const std::string &operation, bool quant,
+ std::ifstream &stream);
+
+ /**
+ * @brief Helper function for writing OperationExecTimes to stream
+ *
+ * @param operation_info Map of operations execution information
+ * @param stream File stream
+ */
+ void printOperation(const std::map<uint32_t, int64_t> &operation_info,
+ std::ofstream &stream) const;
+ /**
+ * @brief Parse and load operations_exec_time from _operations_exec_time_file.
+ */
+ void loadOperationsExecTime();
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_JSON_EXEC_TIME_H__
diff --git a/runtime/onert/core/src/exec/Job.cc b/runtime/onert/core/src/exec/Job.cc
new file mode 100644
index 000000000..27925a93c
--- /dev/null
+++ b/runtime/onert/core/src/exec/Job.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Job.h"
+
+#include <cassert>
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace exec
+{
+
+Job::Job(uint32_t index, FunctionSequence *fn_seq) : _index{index}, _fn_seq{fn_seq} {}
+
+void Job::run() { _fn_seq->run(); }
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/Job.h b/runtime/onert/core/src/exec/Job.h
new file mode 100644
index 000000000..6de9c31a0
--- /dev/null
+++ b/runtime/onert/core/src/exec/Job.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_JOB_H__
+#define __ONERT_EXEC_JOB_H__
+
+#include <unordered_set>
+
+#include "exec/FunctionSequence.h"
+#include "ir/Index.h"
+#include "ir/OperandIndexSequence.h"
+#include "backend/Backend.h"
+
+namespace onert
+{
+namespace exec
+{
+
+class Job
+{
+public:
+ /**
+ * @brief Constructs a Job object
+ *
+ * @param index Operation index for this job
+ * @param fn_seq compiled code to run this job
+ * @param inputs Input operand list
+ * @param outputs Output operand list
+ */
+ Job(uint32_t index, FunctionSequence *fn_seq);
+ /**
+ * @brief Execute the compiled code
+ */
+ void run();
+ /**
+ * @brief Return job index
+ *
+ * @return Job index
+ */
+ uint32_t index() const { return _index; }
+ /**
+ * @brief Return the function to be executed
+ *
+ * @return Pointer of the function
+ */
+ FunctionSequence *fn_seq() { return _fn_seq; }
+
+private:
+ uint32_t _index;
+ FunctionSequence *_fn_seq;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_JOB_H__
diff --git a/runtime/onert/core/src/exec/LinearExecutor.cc b/runtime/onert/core/src/exec/LinearExecutor.cc
new file mode 100644
index 000000000..6e6ca110f
--- /dev/null
+++ b/runtime/onert/core/src/exec/LinearExecutor.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LinearExecutor.h"
+#ifdef RUY_PROFILER
+#include "ruy/profiler/instrumentation.h"
+#endif
+
+namespace onert
+{
+namespace exec
+{
+
+#ifdef RUY_PROFILER
+namespace
+{
+char *seq_to_label(const onert::ir::OpSequence *op_seq, const onert::ir::Operations &operations)
+{
+ auto node_name = operations.at(*op_seq->begin()).name();
+ char *cstr = new char[node_name.length() + 1];
+ std::strcpy(cstr, node_name.c_str());
+ return cstr;
+}
+} // namespace
+#endif
+
+void LinearExecutor::executeImpl()
+{
+ _subject.notifyModelBegin(this);
+ for (auto &&code : _code)
+ {
+ const auto op_seq = code.op_seq;
+ const auto backend = code.lower_info->backend();
+// TODO : Move ruy profiler into ExecutionObserver
+#ifdef RUY_PROFILER
+ ruy::profiler::ScopeLabel label(seq_to_label(op_seq, _graph.operations()));
+#endif
+ _subject.notifyJobBegin(this, op_seq, backend);
+
+ auto &fn_seq = code.fn_seq;
+
+ fn_seq->initRunning();
+
+ bool handle_dynamic_tensor = op_seq->has_dynamic_tensor() || hasDynamicInput();
+ fn_seq->enableDynamicShapeInferer(handle_dynamic_tensor);
+ fn_seq->run();
+
+ _subject.notifyJobEnd(this, op_seq, backend);
+ }
+ _subject.notifyModelEnd(this);
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/LinearExecutor.h b/runtime/onert/core/src/exec/LinearExecutor.h
new file mode 100644
index 000000000..22d00ec30
--- /dev/null
+++ b/runtime/onert/core/src/exec/LinearExecutor.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file LinearExecutor.h
+ * @brief This file contains LinearExecutor class to define and run execution phase
+ */
+
+#ifndef __ONERT_EXEC_EXECUTOR_H_
+#define __ONERT_EXEC_EXECUTOR_H_
+
+#include "ir/Index.h"
+#include "ExecutorBase.h"
+#include "compiler/Linear.h"
+#include "exec/FunctionSequence.h"
+#include "compiler/CodeMap.h"
+
+namespace onert
+{
+namespace exec
+{
+
+/**
+ * @brief Class to handle execution phase. Simple run the sequence of operations that is sorted in
+ * topological order
+ */
+class LinearExecutor final : public ExecutorBase
+{
+public:
+ /**
+ * @brief Construct a new LinearExecutor object
+ * @param lowered_graph LoweredGraph object
+ * @param tensor_builders Tensor builders that are currently used
+ * @param code_map OpSequence and its code map
+ */
+ LinearExecutor(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const std::vector<backend::ITensor *> &input_tensors,
+ const std::vector<backend::ITensor *> &output_tensors,
+ const compiler::TensorRegistries &tensor_regs, compiler::CodeMap &&code_map,
+ const std::vector<ir::OpSequenceIndex> &order)
+ : ExecutorBase{std::move(lowered_graph), input_tensors, output_tensors, tensor_regs}
+ {
+ for (auto index : order)
+ {
+ _code.emplace_back(std::move(code_map.at(index)));
+ }
+ }
+
+public:
+ void executeImpl(void) override;
+
+private:
+ std::vector<compiler::CodeAndInfo> _code;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_EXECUTOR_H_
diff --git a/runtime/onert/core/src/exec/ParallelExecutor.cc b/runtime/onert/core/src/exec/ParallelExecutor.cc
new file mode 100644
index 000000000..676bdb5fa
--- /dev/null
+++ b/runtime/onert/core/src/exec/ParallelExecutor.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ParallelExecutor.h"
+
+#include <cassert>
+
+#include "util/logging.h"
+#include "exec/IFunction.h"
+
+namespace onert
+{
+namespace exec
+{
+
+class HookFunction : public IFunction
+{
+public:
+ HookFunction(IFunction *fn, const std::function<void()> &setup,
+ const std::function<void()> &teardown)
+ : _fn{fn}, _setup{setup}, _teardown{teardown}
+ {
+ }
+
+public:
+ void run() override
+ {
+ _setup();
+ _fn->run();
+ _teardown();
+ }
+
+private:
+ IFunction *_fn;
+ std::function<void()> _setup;
+ std::function<void()> _teardown;
+};
+
+void ParallelExecutor::notify(uint32_t finished_job_id)
+{
+ std::unique_lock<std::mutex> lock{_mu_jobs};
+
+ DataflowExecutor::notify(finished_job_id);
+
+ lock.unlock();
+ _cv_jobs.notify_all();
+}
+
+ParallelExecutor::ParallelExecutor(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const std::vector<backend::ITensor *> &input_tensors,
+ const std::vector<backend::ITensor *> &output_tensors,
+ const compiler::TensorRegistries &tensor_regs,
+ compiler::CodeMap &&code_map)
+ : DataflowExecutor{std::move(lowered_graph), input_tensors, output_tensors, tensor_regs,
+ std::move(code_map)}
+{
+ VERBOSE(ParallelExecutor) << "Constructing Parallel Executor" << std::endl;
+}
+
+void ParallelExecutor::executeImpl()
+{
+ bool dynamic_input_exists = hasDynamicInput();
+
+ // Init scheduler
+ // TODO Consider to have distinct backend set in LowerInfoMap
+ BackendSet backends;
+ for (auto &itr : _lowered_graph->getLowerInfo()->op_seq)
+ {
+ backends.add(itr.second->backend());
+ }
+ _scheduler = std::make_unique<ParallelScheduler>(backends);
+
+ assert(noWaitingJobs());
+
+ // Execution setup
+ _waiting_jobs.swap(_finished_jobs); // Move finished jobs to waiting jobs
+
+ for (uint32_t i = 0; i < _waiting_jobs.size(); ++i)
+ {
+ VERBOSE(ParallelExecutor) << i << ": " << _input_info[i] << std::endl;
+ if (_input_info[i] == 0)
+ {
+ emplaceToReadyJobs(i);
+ }
+ }
+ assert(!_ready_jobs.empty()); // Cannot begin if there is no initial jobs
+
+ VERBOSE(ParallelExecutor) << "INITIAL JOBS : " << _ready_jobs.size() << std::endl;
+
+ _subject.notifyModelBegin(this);
+ while (true)
+ {
+ std::unique_lock<std::mutex> lock{_mu_jobs};
+
+ if (_ready_jobs.empty())
+ {
+ _cv_jobs.wait(lock, [this] { return !_ready_jobs.empty() || noWaitingJobs(); });
+ // Check finish condition
+ if (_ready_jobs.empty() && noWaitingJobs())
+ {
+ break;
+ }
+ }
+
+ auto job = std::move(_ready_jobs.begin()->second);
+ _ready_jobs.erase(_ready_jobs.begin());
+
+ lock.unlock();
+
+ VERBOSE(ParallelExecutor) << "Assigning fn #" << job->index() << std::endl;
+
+ auto job_index = job->index();
+ auto op_sequence_index = _job_to_op_seq[job_index];
+ auto op_seq = &_lowered_graph->op_seqs().at(op_sequence_index);
+ auto backend = _lowered_graph->getLowerInfo()->op_seq.at(op_sequence_index)->backend();
+ auto setup = [&, op_seq, backend]() { _subject.notifyJobBegin(this, op_seq, backend); };
+ auto teardown = [&, job_index, op_seq, backend]() {
+ _subject.notifyJobEnd(this, op_seq, backend);
+ notify(job_index);
+ };
+
+ job->fn_seq()->initRunning();
+
+ // dynamic tensor setting
+ bool handle_dynamic_tensor = op_seq->has_dynamic_tensor() || dynamic_input_exists;
+ job->fn_seq()->enableDynamicShapeInferer(handle_dynamic_tensor);
+
+ _scheduler->assign(std::make_unique<HookFunction>(job->fn_seq(), setup, teardown), backend);
+ _finished_jobs[job_index] = std::move(job);
+ }
+
+ assert(noWaitingJobs());
+
+ // Wait for all the jobs done
+ _scheduler->finish();
+ _subject.notifyModelEnd(this);
+
+ // Reset input info for the next execution
+ _input_info = _initial_input_info;
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ParallelExecutor.h b/runtime/onert/core/src/exec/ParallelExecutor.h
new file mode 100644
index 000000000..111c20c0c
--- /dev/null
+++ b/runtime/onert/core/src/exec/ParallelExecutor.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_PARALLEL_EXECUTOR_H__
+#define __ONERT_EXEC_PARALLEL_EXECUTOR_H__
+
+#include <list>
+#include <queue>
+#include <unordered_map>
+
+#include "exec/FunctionSequence.h"
+#include "Job.h"
+#include "ir/OperandIndexSequence.h"
+#include "ir/Index.h"
+#include <memory>
+#include "exec/DataflowExecutor.h"
+#include "ParallelScheduler.h"
+
+namespace onert
+{
+namespace exec
+{
+
+/**
+ * @brief Class to execute Graph in parallel
+ */
+class ParallelExecutor : public DataflowExecutor
+{
+protected:
+ void notify(uint32_t finished_job_id) override;
+
+public:
+ /**
+ * @brief Constructs a ParallelExecutor object
+ *
+ * @param lowered_graph LoweredGraph object
+ * @param tensor_builders Tensor builders that are currently used
+ * @param code_map OpSequence and its code map
+ */
+ ParallelExecutor(std::unique_ptr<compiler::LoweredGraph> lowered_graph,
+ const std::vector<backend::ITensor *> &input_tensors,
+ const std::vector<backend::ITensor *> &output_tensors,
+ const compiler::TensorRegistries &tensor_regs, compiler::CodeMap &&code_map);
+
+ void executeImpl() override;
+
+private:
+ std::condition_variable _cv_jobs;
+ std::mutex _mu_jobs;
+ std::unique_ptr<ParallelScheduler> _scheduler;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_PARALLEL_EXECUTOR_H__
diff --git a/runtime/onert/core/src/exec/ParallelScheduler.cc b/runtime/onert/core/src/exec/ParallelScheduler.cc
new file mode 100644
index 000000000..70c9c3dd6
--- /dev/null
+++ b/runtime/onert/core/src/exec/ParallelScheduler.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ParallelScheduler.h"
+
+#include <cassert>
+
+#include <memory>
+#include "util/logging.h"
+
+namespace onert
+{
+namespace exec
+{
+
+ParallelScheduler::ParallelScheduler(const BackendSet &backends)
+{
+ assert(!backends.empty());
+
+ for (auto backend : backends)
+ {
+ _thread_pools[backend] = std::make_unique<ThreadPool>();
+ }
+}
+
+void ParallelScheduler::assign(std::unique_ptr<IFunction> &&fn, const backend::Backend *backend)
+{
+ assert(!_thread_pools.empty());
+
+ _thread_pools.at(backend)->enqueue(std::move(fn));
+}
+
+void ParallelScheduler::finish()
+{
+ for (auto &itr : _thread_pools)
+ {
+ itr.second->finish();
+ }
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ParallelScheduler.h b/runtime/onert/core/src/exec/ParallelScheduler.h
new file mode 100644
index 000000000..6802c9e43
--- /dev/null
+++ b/runtime/onert/core/src/exec/ParallelScheduler.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_PARALLEL_SCHEDULER_H__
+#define __ONERT_EXEC_PARALLEL_SCHEDULER_H__
+
+#include <unordered_map>
+#include <memory>
+
+#include "exec/IFunction.h"
+#include "BackendSet.h"
+#include "ThreadPool.h"
+
+namespace onert
+{
+namespace exec
+{
+
+class ParallelScheduler
+{
+public:
+ /**
+ * @brief Constructs ParallelScheduler object
+ *
+ * @param backends Backend set
+ */
+ ParallelScheduler(const BackendSet &backends);
+ /**
+ * @brief Assign a task to the given backend
+ *
+ * @param[in] fn Function to be assigned
+ * @param[in] fn Target backend
+ */
+ void assign(std::unique_ptr<IFunction> &&fn, const backend::Backend *backend);
+ /**
+ * @brief Block until all jobs are finished
+ */
+ void finish();
+
+private:
+ std::unordered_map<const backend::Backend *, std::unique_ptr<ThreadPool>> _thread_pools;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_PARALLEL_SCHEDULER_H__
diff --git a/runtime/onert/core/src/exec/ShapeConverter.cc b/runtime/onert/core/src/exec/ShapeConverter.cc
new file mode 100644
index 000000000..707aef29b
--- /dev/null
+++ b/runtime/onert/core/src/exec/ShapeConverter.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ShapeConverter.h"
+
+namespace onert
+{
+namespace exec
+{
+
+ir::Shape convertShape(const ir::Shape &shape, ir::Layout src_layout, ir::Layout dst_layout)
+{
+ if (shape.rank() != 4)
+ return shape;
+
+ if (src_layout == dst_layout)
+ return shape;
+
+ if (src_layout == ir::Layout::NCHW && dst_layout == ir::Layout::NHWC)
+ {
+ const ir::Shape &src_NCHW = shape;
+ ir::Shape dst_NHWC(4);
+ dst_NHWC.dim(0) = src_NCHW.dim(0); // N
+ dst_NHWC.dim(1) = src_NCHW.dim(2); // H
+ dst_NHWC.dim(2) = src_NCHW.dim(3); // W
+ dst_NHWC.dim(3) = src_NCHW.dim(1); // C
+
+ return dst_NHWC;
+ }
+
+ if (src_layout == ir::Layout::NHWC && dst_layout == ir::Layout::NCHW)
+ {
+ const ir::Shape &src_NHWC = shape;
+ ir::Shape dst_NCHW(4);
+ dst_NCHW.dim(0) = src_NHWC.dim(0); // N
+ dst_NCHW.dim(1) = src_NHWC.dim(3); // C
+ dst_NCHW.dim(2) = src_NHWC.dim(1); // H
+ dst_NCHW.dim(3) = src_NHWC.dim(2); // W
+
+ return dst_NCHW;
+ }
+
+ throw std::runtime_error("Should not reach here");
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ShapeConverter.h b/runtime/onert/core/src/exec/ShapeConverter.h
new file mode 100644
index 000000000..7dc7e7536
--- /dev/null
+++ b/runtime/onert/core/src/exec/ShapeConverter.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_SHAPE_CONVERTER_H__
+#define __ONERT_EXEC_SHAPE_CONVERTER_H__
+
+#include <ir/Layout.h>
+#include <ir/Shape.h>
+
+namespace onert
+{
+namespace exec
+{
+
+/**
+ * @brief Converts shape when its rank is 4
+ *
+ * @return ir::Shape Return a shape based on dst_layout. If rank is not 4, input shape is
+ * returned without conversion.
+ */
+ir::Shape convertShape(const ir::Shape &shape, ir::Layout src_layout, ir::Layout dst_layout);
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_SHAPE_CONVERTER_H__
diff --git a/runtime/onert/core/src/exec/ThreadPool.cc b/runtime/onert/core/src/exec/ThreadPool.cc
new file mode 100644
index 000000000..c8e0e3265
--- /dev/null
+++ b/runtime/onert/core/src/exec/ThreadPool.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ThreadPool.h"
+
+#include <cassert>
+
+namespace onert
+{
+namespace exec
+{
+
+ThreadPool::ThreadPool(uint32_t num_threads)
+{
+ assert(num_threads >= 1);
+
+ for (uint32_t i = 0; i < num_threads; i++)
+ {
+ _threads.emplace_back(std::ref(_worker));
+ }
+}
+
+ThreadPool::~ThreadPool()
+{
+ if (!_threads.empty())
+ {
+ _worker.terminate();
+ join();
+ }
+}
+
+void ThreadPool::enqueue(std::unique_ptr<IFunction> &&fn) { _worker.enqueue(std::move(fn)); }
+
+uint32_t ThreadPool::numJobsInQueue() { return _worker.numJobsInQueue(); }
+
+void ThreadPool::join()
+{
+ for (auto &thread : _threads)
+ {
+ thread.join();
+ }
+ _threads.clear();
+}
+
+void ThreadPool::finish()
+{
+ _worker.finish();
+ join();
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/ThreadPool.h b/runtime/onert/core/src/exec/ThreadPool.h
new file mode 100644
index 000000000..b638bd94c
--- /dev/null
+++ b/runtime/onert/core/src/exec/ThreadPool.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_THREAD_POOL_H__
+#define __ONERT_EXEC_THREAD_POOL_H__
+
+#include <thread>
+#include <memory>
+#include <vector>
+
+#include "WorkQueue.h"
+
+namespace onert
+{
+namespace exec
+{
+
+class ThreadPool
+{
+public:
+ /**
+ * @brief Coustruct ThreadPool object
+ *
+ * @param num_threads Number of threads
+ */
+ ThreadPool(uint32_t num_threads = 1);
+ /**
+ * @brief Destroy ThreadPool object
+ */
+ ~ThreadPool();
+ /**
+ * @brief Enqueue a function
+ *
+ * @param fn A function to be queued
+ */
+ void enqueue(std::unique_ptr<IFunction> &&fn);
+ /**
+ * @brief Get number of jobs in worker's queue
+ *
+ * @return Number of jobs
+ */
+ uint32_t numJobsInQueue();
+
+ /**
+ * @brief Block until all jobs are finished
+ */
+ void finish();
+
+private:
+ void join();
+
+private:
+ WorkQueue _worker;
+ std::vector<std::thread> _threads;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_THREAD_POOL_H__
diff --git a/runtime/onert/core/src/exec/WorkQueue.cc b/runtime/onert/core/src/exec/WorkQueue.cc
new file mode 100644
index 000000000..b37f6a387
--- /dev/null
+++ b/runtime/onert/core/src/exec/WorkQueue.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "WorkQueue.h"
+
+#include <cassert>
+
+namespace onert
+{
+namespace exec
+{
+
+WorkQueue::~WorkQueue()
+{
+ {
+ std::unique_lock<std::mutex> lock(_mu);
+ _state = State::FORCE_FINISHING;
+ }
+ _cv.notify_all();
+}
+
+void WorkQueue::operator()()
+{
+ while (true)
+ {
+ std::unique_ptr<IFunction> fn = nullptr;
+
+ {
+ std::unique_lock<std::mutex> lock{_mu};
+ _cv.wait(lock, [this] {
+ return (_state == State::FORCE_FINISHING) || (_state == State::FINISHING) ||
+ (_state == State::ONLINE && !_functions.empty());
+ });
+
+ if (_state == State::FORCE_FINISHING)
+ {
+ assert(_functions.empty() && "Terminating with unfinished jobs");
+ return;
+ }
+ else if (_state == State::FINISHING && _functions.empty())
+ {
+ return;
+ }
+ else
+ {
+ assert(((_state == State::FINISHING) || (_state == State::ONLINE)) && !_functions.empty());
+ fn = std::move(_functions.front());
+ _functions.pop();
+ }
+ }
+
+ assert(fn);
+ fn->run();
+ }
+}
+
+void WorkQueue::enqueue(std::unique_ptr<IFunction> &&fn)
+{
+ {
+ std::unique_lock<std::mutex> lock{_mu};
+ _functions.emplace(std::move(fn));
+ }
+ _cv.notify_one();
+}
+
+void WorkQueue::terminate()
+{
+ {
+ std::unique_lock<std::mutex> lock{_mu};
+ _state = State::FORCE_FINISHING;
+ }
+ _cv.notify_all();
+}
+
+void WorkQueue::finish()
+{
+ {
+ std::unique_lock<std::mutex> lock{_mu};
+ _state = State::FINISHING;
+ }
+ _cv.notify_all();
+}
+
+uint32_t WorkQueue::numJobsInQueue()
+{
+ std::unique_lock<std::mutex> lock{_mu};
+ return _functions.size();
+}
+
+} // namespace exec
+} // namespace onert
diff --git a/runtime/onert/core/src/exec/WorkQueue.h b/runtime/onert/core/src/exec/WorkQueue.h
new file mode 100644
index 000000000..2e56d85e8
--- /dev/null
+++ b/runtime/onert/core/src/exec/WorkQueue.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_WORK_QUEUE_H__
+#define __ONERT_EXEC_WORK_QUEUE_H__
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+
+#include "exec/IFunction.h"
+
+namespace onert
+{
+namespace exec
+{
+
+class WorkQueue
+{
+public:
+ enum class State
+ {
+ ONLINE,
+ FINISHING,
+ FORCE_FINISHING
+ };
+
+public:
+ /**
+ * @brief Create WorkQueue object
+ */
+ WorkQueue() = default;
+ /**
+ * @brief Destroy WorkQueue object
+ */
+ ~WorkQueue();
+ /**
+ * @brief Thread entry function
+ */
+ void operator()();
+ /**
+ * @brief Push the given Task to the job queue
+ *
+ * @param fn Function to be executed(a job)
+ */
+ void enqueue(std::unique_ptr<IFunction> &&fn);
+ /**
+ * @brief Flag as terminating so all the worker threads can terminate
+ */
+ void terminate();
+ /**
+ * @brief Flag as terminating so all the worker threads can terminate
+ */
+ void finish();
+ /**
+ * @brief Check if it has pending jobs. Even if this returns fals, WorkQueue threads may be still
+ * running
+ *
+ * @return true if the job queue not empty otherwise false
+ */
+ uint32_t numJobsInQueue();
+
+private:
+ State _state{State::ONLINE};
+ std::queue<std::unique_ptr<IFunction>> _functions;
+ std::mutex _mu;
+ std::condition_variable _cv;
+};
+
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_WORK_QUEUE_H__
diff --git a/runtime/onert/core/src/exec/feature/IndexIterator.h b/runtime/onert/core/src/exec/feature/IndexIterator.h
new file mode 100644
index 000000000..9613f5a30
--- /dev/null
+++ b/runtime/onert/core/src/exec/feature/IndexIterator.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IndexIterator.h
+ * @brief This file contains IndexIterator class
+ */
+
+#ifndef __ONERT_EXEC_FEATURE_INDEX_ITERATOR_H__
+#define __ONERT_EXEC_FEATURE_INDEX_ITERATOR_H__
+
+#include "ir/Shape.h"
+
+namespace onert
+{
+namespace exec
+{
+namespace feature
+{
+
+/**
+ * @brief Class to iterate Callable with Index of feature
+ */
+class IndexIterator
+{
+public:
+ /**
+ * @brief Construct IndexIterator object with Shape of feature
+ * @param[in] shape Shape reference of feature
+ */
+ IndexIterator(const ir::FeatureShape &shape) : _shape{shape}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Call a function iterated
+ * @param[in] cb A callback function
+ * @return Current IndexIterator object
+ */
+ template <typename Callable> IndexIterator &iter(Callable cb)
+ {
+ for (int32_t batch = 0; batch < _shape.N; ++batch)
+ {
+ for (int32_t ch = 0; ch < _shape.C; ++ch)
+ {
+ for (int32_t row = 0; row < _shape.H; ++row)
+ {
+ for (int32_t col = 0; col < _shape.W; ++col)
+ {
+ cb(batch, ch, row, col);
+ }
+ }
+ }
+ }
+
+ return (*this);
+ }
+
+private:
+ /**
+ * @brief Shape for feature
+ */
+ const ir::FeatureShape _shape;
+};
+
+/**
+ * @brief Create an object of IndexIterator for feature
+ * @param[in] Shape reference of feature
+ * @return Created IndexIterator object
+ */
+static inline IndexIterator iterate(const ir::FeatureShape &shape) { return IndexIterator{shape}; }
+
+/**
+ * @brief Call a function iterated using IndexIterator of feature
+ * Overloaded operator<<
+ * @param[in] it An IndexIterator reference
+ * @param[in] cb A callback function
+ * @return created IndexIterator object
+ */
+template <typename Callable> IndexIterator &operator<<(IndexIterator &&it, Callable cb)
+{
+ return it.iter(cb);
+}
+
+} // namespace feature
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_FEATURE_INDEX_ITERATOR_H__
diff --git a/runtime/onert/core/src/exec/feature/Reader.h b/runtime/onert/core/src/exec/feature/Reader.h
new file mode 100644
index 000000000..ed87bb990
--- /dev/null
+++ b/runtime/onert/core/src/exec/feature/Reader.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @brief This file contains Reader class
+ */
+
+#ifndef __ONERT_EXEC_FEATURE_READER_H__
+#define __ONERT_EXEC_FEATURE_READER_H__
+
+#include <cstdint>
+
+namespace onert
+{
+namespace exec
+{
+namespace feature
+{
+
+/**
+ * @brief Class reads values of feature
+ * The interface class
+ */
+template <typename T> struct Reader
+{
+ /**
+ * @brief Destruct Reader object using default destructor
+ */
+ virtual ~Reader() = default;
+
+ /**
+ * @brief Get the value used by three indexes
+ * @param[in] ch The depth index
+ * @param[in] row The height index
+ * @param[in] col The width index
+ * @return The value at the offset
+ */
+ virtual T at(uint32_t ch, uint32_t row, uint32_t col) const = 0;
+ /**
+ * @brief Get the value used by four indexes
+ * @param[in] batch The batch index
+ * @param[in] ch The depth index
+ * @param[in] row The height index
+ * @param[in] col The width index
+ * @return The value at the offset
+ */
+ virtual T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const = 0;
+};
+
+} // namespace feature
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_FEATURE_READER_H__
diff --git a/runtime/onert/core/src/exec/feature/nchw/Reader.h b/runtime/onert/core/src/exec/feature/nchw/Reader.h
new file mode 100644
index 000000000..aebedd853
--- /dev/null
+++ b/runtime/onert/core/src/exec/feature/nchw/Reader.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_FEATURE_NCHW_READER_H__
+#define __ONERT_EXEC_FEATURE_NCHW_READER_H__
+
+#include "../Reader.h"
+
+#include <cassert>
+
+#include "backend/ITensor.h"
+#include "ir/Shape.h"
+
+namespace onert
+{
+namespace exec
+{
+namespace feature
+{
+namespace nchw
+{
+
+template <typename T> class Reader : public feature::Reader<T>
+{
+public:
+ using Strides = ir::FeatureShape;
+ // Construct for buffer and strides
+ Reader(const ir::FeatureShape &shape, const Strides &strides, const T *ptr, size_t len)
+ : _shape{shape}, _strides{strides}, _ptr{reinterpret_cast<const uint8_t *>(ptr)}, _len{len}
+ {
+ UNUSED_RELEASE(len); // Workaround for unused variable in release mode
+ assert(len == static_cast<size_t>(strides.N != 0
+ ? shape.N * strides.N
+ : strides.C != 0 ? shape.C * strides.C
+ : strides.H != 0 ? shape.H * strides.H
+ : shape.W * strides.W));
+ }
+
+ // Construct for backend tensor
+ Reader(backend::ITensor *tensor)
+ : _ptr{tensor->buffer() + tensor->calcOffset({0, 0, 0, 0})}, _len{tensor->total_size()}
+ {
+ assert(tensor->layout() == ir::Layout::NCHW);
+
+ const auto start_offset = tensor->calcOffset({0, 0, 0, 0});
+ _strides.W = tensor->dimension(3) == 1 ? 0 : tensor->calcOffset({0, 0, 0, 1}) - start_offset;
+ _strides.H = tensor->dimension(2) == 1 ? 0 : tensor->calcOffset({0, 0, 1, 0}) - start_offset;
+ _strides.C = tensor->dimension(1) == 1 ? 0 : tensor->calcOffset({0, 1, 0, 0}) - start_offset;
+ _strides.N = tensor->dimension(0) == 1 ? 0 : tensor->calcOffset({1, 0, 0, 0}) - start_offset;
+
+ _shape.W = tensor->dimension(3);
+ _shape.H = tensor->dimension(2);
+ _shape.C = tensor->dimension(1);
+ _shape.N = tensor->dimension(0);
+ }
+
+public:
+ T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const final
+ {
+ return getRef(batch, ch, row, col);
+ }
+ T at(uint32_t ch, uint32_t row, uint32_t col) const final { return getRef(0, ch, row, col); }
+
+protected:
+ const T &getRef(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const
+ {
+ const auto offset = feature_index_to_byte_offset(batch, ch, row, col);
+
+ const T *ptr = reinterpret_cast<const T *>(_ptr + offset);
+
+ return *ptr;
+ }
+
+private:
+ size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const
+ {
+ assert(1u * _shape.N > batch); // shape.N > batch
+ assert(1u * _shape.C > ch); // shape.C > ch
+ assert(1u * _shape.H > row); // shape.H > row
+ assert(1u * _shape.W > col); // shape.W > col
+
+ uint32_t res = 0;
+ res += batch * _strides.N;
+ res += ch * _strides.C;
+ res += row * _strides.H;
+ res += col * _strides.W;
+
+ return res;
+ }
+
+private:
+ // TODO Remove _shape
+ ir::FeatureShape _shape;
+ Strides _strides;
+ const uint8_t *_ptr;
+ size_t _len;
+};
+
+} // namespace nchw
+} // namespace feature
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_FEATURE_NCHW_READER_H__
diff --git a/runtime/onert/core/src/exec/feature/nchw/View.h b/runtime/onert/core/src/exec/feature/nchw/View.h
new file mode 100644
index 000000000..df3576264
--- /dev/null
+++ b/runtime/onert/core/src/exec/feature/nchw/View.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_FEATURE_NCHW_VIEW_H__
+#define __ONERT_EXEC_FEATURE_NCHW_VIEW_H__
+
+#include "Reader.h"
+
+#include "backend/ITensor.h"
+#include "ir/Shape.h"
+#include "util/logging.h"
+
+#include <cassert>
+
+namespace onert
+{
+namespace exec
+{
+namespace feature
+{
+namespace nchw
+{
+
+template <typename T> class View final : public Reader<T>
+{
+public:
+ using Strides = typename Reader<T>::Strides;
+ // Construct for buffer of model inputs
+ View(const ir::FeatureShape &shape, const Strides &strides, T *ptr, size_t len)
+ : Reader<T>{shape, strides, ptr, len}
+ {
+ // DO NOTHING
+ }
+
+ // Construct for backend tensor
+ View(::onert::backend::ITensor *tensor) : Reader<T>{tensor}
+ {
+ // DO NOTHING
+ }
+
+public:
+ using Reader<T>::at;
+ T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col)
+ {
+ return const_cast<T &>(Reader<T>::getRef(batch, ch, row, col));
+ }
+ T &at(uint32_t ch, uint32_t row, uint32_t col)
+ {
+ return const_cast<T &>(Reader<T>::getRef(0, ch, row, col));
+ }
+};
+
+} // namespace nchw
+} // namespace feature
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_FEATURE_NCHW_VIEW_H__
diff --git a/runtime/onert/core/src/exec/feature/nhwc/Reader.h b/runtime/onert/core/src/exec/feature/nhwc/Reader.h
new file mode 100644
index 000000000..da6a5f6a9
--- /dev/null
+++ b/runtime/onert/core/src/exec/feature/nhwc/Reader.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_FEATURE_NHWC_READER_H__
+#define __ONERT_EXEC_FEATURE_NHWC_READER_H__
+
+#include "../Reader.h"
+
+#include <cassert>
+
+#include "backend/ITensor.h"
+#include "ir/Shape.h"
+#include "util/Utils.h"
+
+namespace onert
+{
+namespace exec
+{
+namespace feature
+{
+namespace nhwc
+{
+
+template <typename T> class Reader : public feature::Reader<T>
+{
+public:
+ using Strides = ir::FeatureShape;
+ // Construct for buffer and strides
+ Reader(const ir::FeatureShape &shape, const Strides &strides, const T *ptr, size_t len)
+ : _shape{shape}, _strides{strides}, _ptr{reinterpret_cast<const uint8_t *>(ptr)}, _len{len}
+ {
+ UNUSED_RELEASE(len); // Workaround for unused variable in release mode
+ assert(len == static_cast<size_t>(strides.N != 0
+ ? shape.N * strides.N
+ : strides.H != 0 ? shape.H * strides.H
+ : strides.W != 0 ? shape.W * strides.W
+ : shape.C * strides.C));
+ }
+
+ // Construct for backend tensor
+ Reader(const backend::ITensor *tensor)
+ : _ptr{tensor->buffer() + tensor->calcOffset({0, 0, 0, 0})}, _len{tensor->total_size()}
+ {
+ assert(tensor->layout() == ir::Layout::NHWC);
+
+ const auto start_offset = tensor->calcOffset({0, 0, 0, 0});
+ _strides.C = tensor->dimension(3) == 1 ? 0 : tensor->calcOffset({0, 0, 0, 1}) - start_offset;
+ _strides.W = tensor->dimension(2) == 1 ? 0 : tensor->calcOffset({0, 0, 1, 0}) - start_offset;
+ _strides.H = tensor->dimension(1) == 1 ? 0 : tensor->calcOffset({0, 1, 0, 0}) - start_offset;
+ _strides.N = tensor->dimension(0) == 1 ? 0 : tensor->calcOffset({1, 0, 0, 0}) - start_offset;
+
+ _shape.C = tensor->dimension(3);
+ _shape.W = tensor->dimension(2);
+ _shape.H = tensor->dimension(1);
+ _shape.N = tensor->dimension(0);
+ }
+
+public:
+ T at(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const final
+ {
+ return getRef(batch, row, col, ch);
+ }
+ T at(uint32_t row, uint32_t col, uint32_t ch) const final { return getRef(0, row, col, ch); }
+
+protected:
+ const T &getRef(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const
+ {
+ const auto offset = feature_index_to_byte_offset(batch, row, col, ch);
+
+ const T *ptr = reinterpret_cast<const T *>(_ptr + offset);
+
+ return *ptr;
+ }
+
+private:
+ size_t feature_index_to_byte_offset(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const
+ {
+ assert(1u * _shape.N > batch); // shape.N > batch
+ assert(1u * _shape.H > row); // shape.H > row
+ assert(1u * _shape.W > col); // shape.W > col
+ assert(1u * _shape.C > ch); // shape.C > ch
+
+ uint32_t res = 0;
+ res += batch * _strides.N;
+ res += row * _strides.H;
+ res += col * _strides.W;
+ res += ch * _strides.C;
+
+ return res;
+ }
+
+private:
+ // TODO Remove _shape
+ ir::FeatureShape _shape;
+ Strides _strides;
+ const uint8_t *_ptr;
+ size_t _len;
+};
+
+} // namespace nhwc
+} // namespace feature
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_FEATURE_NHWC_READER_H__
diff --git a/runtime/onert/core/src/exec/feature/nhwc/View.h b/runtime/onert/core/src/exec/feature/nhwc/View.h
new file mode 100644
index 000000000..a77f68024
--- /dev/null
+++ b/runtime/onert/core/src/exec/feature/nhwc/View.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_EXEC_FEATURE_NHWC_VIEW_H__
+#define __ONERT_EXEC_FEATURE_NHWC_VIEW_H__
+
+#include "../Reader.h"
+
+#include <cassert>
+#include <cstddef>
+
+#include "backend/ITensor.h"
+#include "ir/Shape.h"
+#include "util/Utils.h"
+
+namespace onert
+{
+namespace exec
+{
+namespace feature
+{
+namespace nhwc
+{
+
+template <typename T> class View final : public Reader<T>
+{
+public:
+ using Strides = typename Reader<T>::Strides;
+ // Construct for buffer and strides
+ View(const ir::FeatureShape &shape, const Strides &strides, T *ptr, size_t len)
+ : Reader<T>{shape, strides, ptr, len}
+ {
+ // DO NOTHING
+ }
+
+ // Construct for backend tensor
+ View(backend::ITensor *tensor) : Reader<T>{tensor}
+ {
+ // DO NOTHING
+ }
+
+public:
+ using Reader<T>::at;
+ T &at(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch)
+ {
+ return const_cast<T &>(Reader<T>::getRef(batch, row, col, ch));
+ }
+ T &at(uint32_t row, uint32_t col, uint32_t ch)
+ {
+ return const_cast<T &>(Reader<T>::getRef(0, row, col, ch));
+ }
+};
+
+} // namespace nhwc
+} // namespace feature
+} // namespace exec
+} // namespace onert
+
+#endif // __ONERT_EXEC_FEATURE_NHWC_VIEW_H__
diff --git a/runtime/onert/core/src/interp/Buffer.h b/runtime/onert/core/src/interp/Buffer.h
new file mode 100644
index 000000000..24938f74f
--- /dev/null
+++ b/runtime/onert/core/src/interp/Buffer.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Buffer.h
+ * @brief This file contains Buffer interface and InternalBuffer, ExternalBuffer class
+ */
+#ifndef __ONERT_INTERP_BUFFER_H__
+#define __ONERT_INTERP_BUFFER_H__
+
+#include <memory>
+
+#include "ir/Data.h"
+
+namespace onert
+{
+namespace interp
+{
+
+/**
+ * @brief Interface for writable data area
+ */
+class Buffer : public ir::Data
+{
+public:
+ /**
+ * @brief Return writable pointer for data area
+ * @return Writable pointer
+ */
+ virtual uint8_t *baseWritable(void) const = 0;
+};
+
+/**
+ * @brief Class for internally allocated data area
+ */
+class InternalBuffer final : public Buffer
+{
+public:
+ InternalBuffer(size_t size) : _base{std::make_unique<uint8_t[]>(size)}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ size_t size(void) const override { return _size; }
+ const uint8_t *base(void) const override { return _base.get(); }
+ uint8_t *baseWritable(void) const override { return _base.get(); }
+
+private:
+ std::unique_ptr<uint8_t[]> _base;
+ size_t _size;
+};
+
+/**
+ * @brief Class for data area from outside
+ */
+class ExternalBuffer final : public Buffer
+{
+public:
+ ExternalBuffer(uint8_t *base, size_t size) : _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ size_t size(void) const override { return _size; }
+ const uint8_t *base(void) const override { return _base; }
+ uint8_t *baseWritable(void) const override { return _base; }
+
+private:
+ uint8_t *_base;
+ size_t _size;
+};
+
+} // namespace interp
+} // namespace onert
+
+#endif // __ONERT_INTERP_BUFFER_H__
diff --git a/runtime/onert/core/src/interp/ExecEnv.h b/runtime/onert/core/src/interp/ExecEnv.h
new file mode 100644
index 000000000..7f577ea6e
--- /dev/null
+++ b/runtime/onert/core/src/interp/ExecEnv.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ExecEnv.h
+ * @brief This file contains ExecEnv to access interpreter tensor and execution status
+ */
+#ifndef __ONERT_INTERP_EXEC_ENV_H_
+#define __ONERT_INTERP_EXEC_ENV_H_
+
+#include <unordered_set>
+
+#include "ir/Graph.h"
+#include "Tensor.h"
+
+namespace onert
+{
+namespace interp
+{
+
+/**
+ * @brief Class to gather interpreter execution environment
+ * Each interpreter instance own execution environment
+ */
+class ExecEnv
+{
+public:
+ /**
+ * @brief Construct a new Exec Env object (deleted)
+ */
+ ExecEnv(void) = delete;
+ /**
+ * @brief Construct a new ExecEnv object
+ * @param[in] graph Graph to execute by interpreter
+ */
+ explicit ExecEnv(const ir::Graph &graph) : _graph(graph)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return graph to execute
+ * @return Graph
+ */
+ const ir::Graph &graph(void) const { return _graph; }
+ /**
+ * @brief Assign tensor to environment which have allocated or assigned buffer
+ * @param[in] index Tensor index
+ * @param[in] tensor Tensor
+ */
+ void assignTensor(const ir::OperandIndex index, std::shared_ptr<ITensor> tensor)
+ {
+ assert(tensor->bufferRO() != nullptr);
+ _tensors.emplace(index, tensor);
+ }
+
+ /**
+ * @brief Return tensor pointer in environment
+ * @param[in] index Tensor index
+ * can_optional @c True if tensor can be optional input, otherwise @c false
+ * @return Tensor pointer
+ */
+ const ITensor *tensorAt(const ir::OperandIndex index, bool can_optional = false) const
+ {
+ if (_tensors.find(index) == _tensors.end())
+ {
+ // It may optional input,
+ // otherwise input is not set by runtime user
+ if (can_optional)
+ {
+ return nullptr;
+ }
+
+ throw std::runtime_error{"ExecEnv: Input is not set"};
+ }
+
+ return _tensors.at(index).get();
+ }
+
+ /**
+ * @brief Check environment contains tensor
+ * @param[in] index Tensor index
+ * @return @c true if environment contain tensor, otherwise @c false
+ */
+ bool contains(const ir::OperandIndex index) const
+ {
+ return (_tensors.find(index) != _tensors.end());
+ }
+
+ /**
+ * @brief Allocate tensor using operand info
+ * @param[in] index Tensor index
+ * @param[in] info Operand info
+ * @note If already allocated, just return
+ * @TODO More smart allocation policy
+ */
+ void allocateIfNeeded(const ir::OperandIndex index, const ir::OperandInfo &info)
+ {
+ // already allocated, or constant
+ if (contains(index))
+ {
+ return;
+ }
+
+ // Buffer from external (ex. model output)
+ auto tensor = std::make_shared<Tensor>(info);
+ if (isExtBuffer(index))
+ {
+ tensor->setBuffer(_external_buffers.at(index));
+ assignTensor(index, tensor);
+
+ return;
+ }
+
+ tensor->setBuffer(std::make_shared<InternalBuffer>(tensor->total_size()));
+ assignTensor(index, tensor);
+ _buffers.insert(index);
+ }
+
+ /**
+ * @brief Allocate read-only tensor and share data with other tensor
+ * @param[in] index Tensor index
+ * @param[in] info Operand info
+ * @param[in] index_to_share Tensor index that have data to share
+ */
+ void allocateAndShareIfNeeded(const ir::OperandIndex index, const ir::OperandInfo &info,
+ const ir::OperandIndex index_to_share)
+ {
+ if (!contains(index_to_share))
+ {
+ throw std::runtime_error{"Cannot find tensor to share data"};
+ }
+
+ // already allocated
+ if (contains(index))
+ {
+ return;
+ }
+
+ if (isExtBuffer(index))
+ {
+ auto tensor = std::make_shared<Tensor>(info);
+ tensor->setBuffer(_external_buffers.at(index));
+ assignTensor(index, tensor);
+ }
+ else
+ {
+ auto tensor = std::make_shared<ROTensor>(info);
+ tensor->setData(tensorAt(index_to_share)->shareData());
+ assignTensor(index, tensor);
+ _buffers.insert(index);
+ }
+ }
+
+ /**
+ * @brief Free buffer if allocated by allocateIfNeed
+ * @param[in] index Tensor index
+ * @note If allocated by outside, just return
+ */
+ void freeIfAllocated(const ir::OperandIndex index)
+ {
+ if (_buffers.find(index) != _buffers.end())
+ {
+ _tensors.at(index)->releaseData();
+ }
+ }
+
+ /**
+ * @brief Assign ExternalBuffer into external buffer map
+ * @param[in] index Tensor index
+ * @param[in] buffer External buffer
+ */
+ void assignExternalBuffer(const ir::OperandIndex index, std::shared_ptr<ExternalBuffer> buffer)
+ {
+ _external_buffers.emplace(index, buffer);
+ }
+
+private:
+ bool isExtBuffer(const ir::OperandIndex index)
+ {
+ return (_external_buffers.find(index) != _external_buffers.end());
+ }
+
+private:
+ const ir::Graph &_graph;
+ // Tensor map to use in interpreter
+ // It should map tensors that have allocated or assigned buffer pointer
+ std::unordered_map<ir::OperandIndex, std::shared_ptr<ITensor>> _tensors;
+ // Tensors allocated by allocateIfNeed (buffer)
+ std::unordered_set<ir::OperandIndex> _buffers;
+ // Tensor buffer from external
+ std::unordered_map<ir::OperandIndex, std::shared_ptr<ExternalBuffer>> _external_buffers;
+};
+
+} // namespace interp
+} // namespace onert
+
+#endif // __ONERT_INTERP_EXEC_ENV_H_
diff --git a/runtime/onert/core/src/interp/InterpExecutor.cc b/runtime/onert/core/src/interp/InterpExecutor.cc
new file mode 100644
index 000000000..cd31a4dca
--- /dev/null
+++ b/runtime/onert/core/src/interp/InterpExecutor.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "interp/InterpExecutor.h"
+#include "interp/ExecEnv.h"
+#include "interp/Interpreter.h"
+
+#include "util/logging.h"
+
+#include <memory>
+
+namespace onert
+{
+namespace interp
+{
+
+void InterpExecutor::execute(const exec::IODescription &desc)
+{
+ /************************************************************************
+ * Prepare execution model (submodel)
+ It may execute divided model
+ but now consider model inference is done at interpreter
+ ***********************************************************************/
+ ir::OperandIndexMap<std::shared_ptr<ITensor>> tensor_map;
+
+ for (uint32_t n = 0; n < _graph.getInputs().size(); n++)
+ {
+ ir::IOIndex index{n};
+ const auto input_index = _graph.getInputs().at(index);
+
+ const auto input = desc.inputs.at(n).get();
+ if (input == nullptr)
+ {
+ // Optional input
+ continue;
+ }
+
+ auto input_tensor = std::make_shared<ROTensor>(input->info);
+ input_tensor->setData(std::make_shared<const ir::ExternalData>(
+ reinterpret_cast<const uint8_t *>(input->buffer), input->size));
+ tensor_map[input_index] = input_tensor;
+ }
+
+ /************************************************************************
+ * Prepare execution environment
+ Execution environment will be assigned to invoked interpreter instance
+ ***********************************************************************/
+
+ std::unique_ptr<ExecEnv> interp_env = std::make_unique<ExecEnv>(_graph);
+
+ // Assign input/output tensor into interpreter execution environment
+ for (auto index : _graph.getInputs())
+ {
+ if (tensor_map.find(index) != tensor_map.end())
+ {
+ VERBOSE(INTERPRETER) << "Assign input tensor. operand index:" << index.value() << std::endl;
+ interp_env->assignTensor(index, tensor_map.at(index));
+ }
+ }
+
+ for (uint32_t n = 0; n < _graph.getOutputs().size(); n++)
+ {
+ ir::IOIndex index{n};
+ const auto output_index = _graph.getOutputs().at(index);
+ const auto output = desc.outputs.at(n).get();
+ if (output == nullptr)
+ {
+ // Optional output
+ continue;
+ }
+
+ VERBOSE(INTERPRETER) << "Set out buffer to ExecEnv. operand index:" << output_index.value()
+ << std::endl;
+
+ interp_env->assignExternalBuffer(
+ output_index, std::make_shared<ExternalBuffer>(reinterpret_cast<uint8_t *>(output->buffer),
+ output->size));
+ }
+
+ // Allocate constant tensor
+ _graph.operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) {
+ if (obj.isConstant())
+ {
+ VERBOSE(INTERPRETER) << "Allocate and assign constant tensor. operand index:" << ind.value()
+ << std::endl;
+
+ assert(obj.data());
+ auto const_tensor = std::make_shared<ROTensor>(obj.info());
+ // Assume that interpreter's tensor layout is same with model (NHWC)
+ const_tensor->setData(
+ std::make_shared<ir::ExternalData>(obj.data()->base(), obj.info().total_size()));
+ interp_env->assignTensor(ind, const_tensor);
+ }
+ });
+
+ /*****************************************************************************
+ * Invoke interpreter
+ ****************************************************************************/
+
+ interp::Interpreter interp(std::move(interp_env));
+ interp.run();
+
+ /*****************************************************************************
+ * Invoked interpreter run is finished
+ ****************************************************************************/
+
+ // If interpreter execute submodel
+ // 1. Get tensor output of submodel into tensor_map to save result
+ // 2. Generate new ExecEnv for next interpretation
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/InterpExecutor.h b/runtime/onert/core/src/interp/InterpExecutor.h
new file mode 100644
index 000000000..2e3f3ca54
--- /dev/null
+++ b/runtime/onert/core/src/interp/InterpExecutor.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file InterpExecutor.h
+ * @brief This file contains InterpExecutor class\n
+ * to manage interpreter execution and environment
+ */
+#ifndef __ONERT_INTERP_INTERP_EXECUTOR_H__
+#define __ONERT_INTERP_INTERP_EXECUTOR_H__
+
+#include "ir/OperandIndexMap.h"
+#include "ir/Graph.h"
+#include "exec/IExecutor.h"
+
+namespace onert
+{
+namespace interp
+{
+
+class ITensor;
+
+/**
+ * @brief Class to execute model using interpreter
+ */
+class InterpExecutor final : public exec::IExecutor
+{
+public:
+ explicit InterpExecutor(const ir::Graph &graph) : _graph(graph)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return graph object
+ * @return Graph object
+ */
+ const ir::Graph &graph() final { return _graph; }
+ void setIndexedRanks(std::shared_ptr<ir::OperationIndexMap<int64_t>>) override{
+ // Not implemented
+ };
+ /**
+ * @brief Start execution
+ * @note It should be called after setting input and output buffer
+ */
+ void execute(const exec::IODescription &desc) final;
+
+private:
+ const ir::Graph &_graph;
+ ir::OperandIndexMap<std::shared_ptr<ITensor>> _tensor_map;
+};
+
+} // namespace interp
+} // namespace onert
+
+#endif // __ONERT_INTERP_INTERP_EXECUTOR_H__
diff --git a/runtime/onert/core/src/interp/InterpOps.lst b/runtime/onert/core/src/interp/InterpOps.lst
new file mode 100644
index 000000000..0714df38a
--- /dev/null
+++ b/runtime/onert/core/src/interp/InterpOps.lst
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INTERP_OP
+#error Define INTERP_OP before including this file
+#endif
+
+// Supported operation name in interpreter
+//
+// Same list with Operations.lst
+// Make comment out if operation is not supported in interpreter
+INTERP_OP(BinaryArithmetic)
+//INTERP_OP(BatchToSpaceND)
+//INTERP_OP(Cast)
+INTERP_OP(Conv2D)
+INTERP_OP(DepthwiseConv2D)
+INTERP_OP(Pool2D)
+INTERP_OP(Concat)
+INTERP_OP(FullyConnected)
+//INTERP_OP(Reduce)
+INTERP_OP(Reshape)
+INTERP_OP(Softmax)
+//INTERP_OP(Squeeze)
+//INTERP_OP(Slice)
+//INTERP_OP(StridedSlice)
+INTERP_OP(ElementwiseActivation)
+//INTERP_OP(Transpose)
+//INTERP_OP(Exp)
+//INTERP_OP(Comparison)
+//INTERP_OP(LogicalNot)
+//INTERP_OP(LSTM)
+//INTERP_OP(RSQRT)
+//INTERP_OP(ResizeBilinear)
+//INTERP_OP(RNN)
+//INTERP_OP(Floor)
+//INTERP_OP(SpaceToBatchND)
+//INTERP_OP(SpaceToDepth)
+//INTERP_OP(EmbeddingLookup)
+//INTERP_OP(L2Normalization)
+//INTERP_OP(HashtableLookup)
+INTERP_OP(InstanceNorm)
+//INTERP_OP(PReLU)
+INTERP_OP(TransposeConv)
+//INTERP_OP(SQRT)
+//INTERP_OP(SquaredDifference)
+//INTERP_OP(TopKV2)
+INTERP_OP(Gather)
+//INTERP_OP(Neg)
+//INTERP_OP(Abs)
+//INTERP_OP(ArgMax)
+//INTERP_OP(Dequantize)
+//INTERP_OP(LocalResponseNormalization)
+//INTERP_OP(DepthToSpace)
+//INTERP_OP(Pack)
+//INTERP_OP(Split)
+//INTERP_OP(Unpack)
+INTERP_OP(Pad)
+//INTERP_OP(Custom)
+//INTERP_OP(Permute)
+//INTERP_OP(OneHot)
diff --git a/runtime/onert/core/src/interp/Interpreter.cc b/runtime/onert/core/src/interp/Interpreter.cc
new file mode 100644
index 000000000..b92afbe73
--- /dev/null
+++ b/runtime/onert/core/src/interp/Interpreter.cc
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Interpreter.h"
+
+#include <stack>
+#include <unordered_set>
+
+#include "Registration.h"
+
+#include "ir/OperandIndexMap.h"
+#include "util/logging.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace interp
+{
+
+// TODO more structured execution kernel implementation
+// TODO use cker for execution
+// TODO divide tensor prepare and execution
+// TODO introduce memory manager (buffer allocate and free)
+class OperationExecutor
+{
+public:
+ OperationExecutor(ExecEnv *env) : _env{env}
+ {
+#define INTERP_OP(InternalName) _kernels[ir::OpCode::InternalName] = get##InternalName();
+#include "InterpOps.lst"
+#undef INTERP_OP
+ }
+
+ void execute(const ir::OperationIndex &idx)
+ {
+ const ir::Operation &node = _env->graph().operations().at(idx);
+ const auto nodeName = node.name();
+ VERBOSE(INTERPRETER) << "Prepare output operands and execute " << nodeName
+ << " operation (id: " << idx.value() << ")" << std::endl;
+
+ const auto nodeOpCode = node.opcode();
+ if (_kernels.find(nodeOpCode) == _kernels.end())
+ {
+ throw std::runtime_error{"Interpreter: Operation " + nodeName + " is not yet implemented"};
+ }
+
+ if (_kernels[nodeOpCode]->prepare != nullptr)
+ {
+ _kernels[nodeOpCode]->prepare(_env, node);
+ }
+ _kernels[nodeOpCode]->invoke(_env, node);
+ }
+
+private:
+ ExecEnv *_env;
+ std::unordered_map<ir::OpCode, OpKernel *> _kernels;
+};
+
+void Interpreter::run()
+{
+ VERBOSE(INTERPRETER) << "Interpreter is invoked " << std::endl;
+
+ // operand_stack: save operands prepared to use
+ std::stack<ir::OperandIndex> operand_stack;
+
+ // Note: We should push input first, then constant.
+ // We use use-def for find operators ready to execution,
+ // but Use-Def cannot handle parameters (maybe constant, but not always)
+ // Note: If all model inputs are constant, it may not work (depend on tensors' order).
+ // But that scenario may not exist
+ for (auto ind : _env->graph().getInputs())
+ {
+ VERBOSE(INTERPRETER) << "Input: Push to operand stack " << ind.value() << std::endl;
+
+ operand_stack.push(ind);
+ }
+
+ _env->graph().operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) {
+ if (obj.isConstant())
+ {
+ VERBOSE(INTERPRETER) << "Constant: Push to operand stack " << ind.value() << std::endl;
+
+ operand_stack.push(ind);
+ }
+ });
+
+ // Execution
+ std::unordered_set<ir::OperandIndex> ready_check;
+ std::unordered_set<ir::OperationIndex> executed;
+ OperationExecutor executor{_env.get()};
+ while (!operand_stack.empty())
+ {
+ const auto current_operand_index = operand_stack.top();
+ operand_stack.pop();
+ VERBOSE(INTERPRETER) << "Poped operand " << current_operand_index.value()
+ << " is checked ready to use" << std::endl;
+
+ assert(ready_check.find(current_operand_index) == ready_check.end());
+ ready_check.insert(current_operand_index);
+
+ // Find prepared operations by scan use of current operand
+ std::stack<ir::OperationIndex> operation_stack;
+ const auto use_operators = _env->graph().operands().at(current_operand_index).getUses();
+ for (const auto &use_operator : use_operators)
+ {
+ // Assumption: all parameters are ready to use
+ bool operator_ready = true;
+ for (auto input_index : _env->graph().operations().at(use_operator).getInputs())
+ {
+ if (ready_check.find(input_index) == ready_check.end())
+ {
+ operator_ready = false;
+ break;
+ }
+ }
+
+ if (operator_ready)
+ {
+ VERBOSE(INTERPRETER) << "Ready to execute operation " << use_operator.value() << std::endl;
+ operation_stack.push(use_operator);
+ }
+ }
+
+ while (!operation_stack.empty())
+ {
+ const auto current_operation_index = operation_stack.top();
+ operation_stack.pop();
+ VERBOSE(INTERPRETER) << "Poped operation: " << current_operation_index.value() << "("
+ << _env->graph().operations().at(current_operation_index).name() << ")"
+ << std::endl;
+
+ // execution
+ // 1. Prepare output tensor
+ // 2. Call operation kernel
+ executor.execute(current_operation_index);
+ executed.insert(current_operation_index);
+
+ // 3. Push each output into operand stack
+ const auto def_operands = _env->graph().operations().at(current_operation_index).getOutputs();
+ for (auto def_operand : def_operands)
+ {
+ VERBOSE(INTERPRETER) << "Buffer: Push to operand stack " << def_operand.value()
+ << std::endl;
+ operand_stack.push(def_operand);
+ }
+
+ // 4. Free if lifetime of buffer operands used by input is finished
+ for (auto input_index : _env->graph().operations().at(current_operation_index).getInputs())
+ {
+ const auto use_operators = _env->graph().operands().at(input_index).getUses();
+ bool dead_buffer = true;
+ for (const auto &use_operator : use_operators)
+ {
+ if (executed.find(use_operator) == executed.end())
+ {
+ dead_buffer = false;
+ break;
+ }
+ }
+
+ if (dead_buffer)
+ {
+ _env->freeIfAllocated(input_index);
+ }
+ }
+ }
+ }
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/Interpreter.h b/runtime/onert/core/src/interp/Interpreter.h
new file mode 100644
index 000000000..d2165f538
--- /dev/null
+++ b/runtime/onert/core/src/interp/Interpreter.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Interpreter.h
+ * @brief This file contains Interpreter class for interpretation
+ */
+#ifndef __ONERT_INTERP_INTERPRETER_H__
+#define __ONERT_INTERP_INTERPRETER_H__
+
+#include "ExecEnv.h"
+
+namespace onert
+{
+namespace interp
+{
+
+/**
+ * @brief Class for interpretation
+ */
+class Interpreter
+{
+
+public:
+ /**
+ * @brief Construct a new Interpreter object (deleted)
+ */
+ Interpreter() = delete;
+ /**
+ * @brief Construct a new Interpreter object
+ * @param[in] env Execution environment variable for interpreter object
+ */
+ Interpreter(std::unique_ptr<ExecEnv> env) : _env{std::move(env)}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Run interpreter until there is no operation to execute
+ */
+ void run();
+
+private:
+ std::unique_ptr<ExecEnv> _env;
+};
+
+} // namespace interp
+} // namespace onert
+
+#endif // __ONERT_INTERP_INTERPRETER_H__
diff --git a/runtime/onert/core/src/interp/Registration.h b/runtime/onert/core/src/interp/Registration.h
new file mode 100644
index 000000000..956b92a53
--- /dev/null
+++ b/runtime/onert/core/src/interp/Registration.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_INTERP_REGISTRATION_H__
+#define __ONERT_INTERP_REGISTRATION_H__
+
+#include "ExecEnv.h"
+
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace interp
+{
+
+struct OpKernel
+{
+ std::function<void(ExecEnv *, const ir::Operation &)> prepare;
+ std::function<void(const ExecEnv *, const ir::Operation &)> invoke;
+};
+
+// Defined in operations/ directory
+#define INTERP_OP(InternalName) OpKernel *get##InternalName();
+#include "InterpOps.lst"
+#undef INTERP_OP
+
+} // namespace interp
+} // namespace onert
+
+#endif // __ONERT_INTERP_REGISTRATION_H__
diff --git a/runtime/onert/core/src/interp/Tensor.cc b/runtime/onert/core/src/interp/Tensor.cc
new file mode 100644
index 000000000..07f8b75dc
--- /dev/null
+++ b/runtime/onert/core/src/interp/Tensor.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Tensor.h"
+
+#define NO_USE(a) (void)(a)
+
+namespace onert
+{
+namespace interp
+{
+
+void ITensor::access(const std::function<void(backend::ITensor &tensor)> &fn) { fn(*this); }
+
+size_t ROTensor::calcOffset(const ir::Coordinates &coords) const
+{
+ NO_USE(coords);
+ throw std::runtime_error("offset_element_in_bytes is not supported for cpu::Tensor now.");
+}
+
+size_t Tensor::calcOffset(const ir::Coordinates &coords) const
+{
+ NO_USE(coords);
+ throw std::runtime_error("offset_element_in_bytes is not supported for cpu::Tensor now.");
+}
+
+ir::Layout ROTensor::layout() const
+{
+ // TODO Changes to return frontend layout
+ return ir::Layout::NHWC;
+}
+
+ir::Layout Tensor::layout() const
+{
+ // TODO Changes to return frontend layout
+ return ir::Layout::NHWC;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/Tensor.h b/runtime/onert/core/src/interp/Tensor.h
new file mode 100644
index 000000000..8b72d537d
--- /dev/null
+++ b/runtime/onert/core/src/interp/Tensor.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Tensor.h
+ * @brief This file contains ITensor interface, ROTensor class, and Tensor class
+ */
+#ifndef __ONERT_INTERP_TENSOR_H__
+#define __ONERT_INTERP_TENSOR_H__
+
+#include "Buffer.h"
+
+#include "ir/OperandInfo.h"
+#include "backend/ITensor.h"
+#include "ir/Layout.h"
+
+namespace onert
+{
+namespace interp
+{
+
+/**
+ * @brief Interface to handle Tensor in interpreter
+ */
+class ITensor : public backend::ITensor
+{
+public:
+ virtual ~ITensor() = default;
+
+public:
+ virtual uint8_t *buffer() const = 0;
+ /**
+ * @brief Return shared pointer for buffer
+ * @return Buffer shared pointer
+ */
+ virtual std::shared_ptr<const Buffer> shareBuffer() const = 0;
+ /**
+ * @brief Return read-only buffer pointer
+ * @return Read-only buffer pointer
+ */
+ virtual const uint8_t *bufferRO() const = 0;
+ /**
+ * @brief Return shared pointer for data
+ * @return Data shared pointer
+ */
+ virtual std::shared_ptr<const ir::Data> shareData() const = 0;
+ /**
+ * @brief Set internal/external buffer
+ * @param[in] buffer Buffer pointer
+ */
+ virtual void setBuffer(std::shared_ptr<const Buffer> buffer) = 0;
+ /**
+ * @brief Set data reference (including constant, input)
+ * @param[in] data Data pointer
+ */
+ virtual void setData(std::shared_ptr<const ir::Data> data) = 0;
+ virtual void releaseData() = 0;
+
+ virtual size_t total_size() const = 0;
+ virtual size_t dimension(size_t index) const = 0;
+ virtual size_t num_dimensions() const = 0;
+ virtual size_t calcOffset(const ir::Coordinates &coords) const = 0;
+
+ virtual bool has_padding() const = 0;
+ /**
+ * @brief Return data type of tensor
+ * @return Data type of tensor
+ */
+ virtual ir::DataType data_type() const = 0;
+ /**
+ * @brief Return TensorInfo
+ * @return TensorInfo
+ */
+ virtual const ir::OperandInfo &tensorInfo() const = 0;
+ /**
+ * @brief Return number of elements
+ * @return Number of elements
+ */
+ virtual uint64_t num_elements() const = 0;
+ void access(const std::function<void(backend::ITensor &tensor)> &fn) final;
+};
+
+/**
+ * @brief Class to handle tensor in interpreter as read-only
+ */
+class ROTensor final : public ITensor
+{
+public:
+ ROTensor() = delete;
+ ROTensor(const ir::OperandInfo &info) : _info(info)
+ {
+ // DO NOTHING
+ }
+
+public:
+ uint8_t *buffer() const override { throw std::runtime_error{"Read only tensor"}; }
+ std::shared_ptr<const Buffer> shareBuffer() const override
+ {
+ throw std::runtime_error{"Read only tensor"};
+ }
+ const uint8_t *bufferRO() const override { return _data->base(); }
+ std::shared_ptr<const ir::Data> shareData() const override { return _data; }
+ void setBuffer(std::shared_ptr<const Buffer> buffer) override { _data = buffer; }
+ void setData(std::shared_ptr<const ir::Data> data) override { _data = data; }
+ void releaseData() override { _data = nullptr; }
+
+ size_t total_size() const override { return _info.total_size(); }
+ size_t dimension(size_t index) const override { return _info.shape().dim(index); }
+ size_t num_dimensions() const override { return _info.shape().rank(); }
+ size_t calcOffset(const ir::Coordinates &coords) const override;
+ ir::Layout layout() const override;
+ bool is_dynamic() const override { return false; }
+ bool has_padding() const override { return false; }
+ ir::DataType data_type() const override { return _info.typeInfo().type(); }
+ float data_scale() const override { return _info.typeInfo().scale(); }
+ int32_t data_offset() const override { return _info.typeInfo().offset(); }
+ const ir::OperandInfo &tensorInfo() const override { return _info; }
+ uint64_t num_elements() const override { return _info.shape().num_elements(); };
+
+private:
+ const ir::OperandInfo _info;
+ std::shared_ptr<const ir::Data> _data{nullptr};
+};
+
+/**
+ * @brief Class to handle tensor in interpreter as writable
+ */
+class Tensor final : public ITensor
+{
+public:
+ Tensor() = delete;
+ Tensor(const ir::OperandInfo &info) : _info(info)
+ {
+ // DO NOTHING
+ }
+
+public:
+ uint8_t *buffer() const override { return _buffer->baseWritable(); }
+ std::shared_ptr<const Buffer> shareBuffer() const override { return _buffer; };
+ const uint8_t *bufferRO() const override { return _buffer->base(); }
+ std::shared_ptr<const ir::Data> shareData() const override { return _buffer; }
+ void setBuffer(std::shared_ptr<const Buffer> buffer) override { _buffer = buffer; }
+ void setData(std::shared_ptr<const ir::Data>) override
+ {
+ throw std::runtime_error{"Passed data may read-only"};
+ }
+ void releaseData() override { _buffer = nullptr; }
+
+ size_t total_size() const override { return _info.total_size(); }
+ size_t dimension(size_t index) const override { return _info.shape().dim(index); }
+ size_t num_dimensions() const override { return _info.shape().rank(); }
+ size_t calcOffset(const ir::Coordinates &coords) const override;
+ ir::Layout layout() const override;
+ bool is_dynamic() const override { return false; }
+ bool has_padding() const override { return false; }
+ ir::DataType data_type() const override { return _info.typeInfo().type(); }
+ float data_scale() const override { return _info.typeInfo().scale(); }
+ int32_t data_offset() const override { return _info.typeInfo().offset(); }
+ const ir::OperandInfo &tensorInfo() const override { return _info; }
+ uint64_t num_elements() const override { return _info.shape().num_elements(); };
+
+private:
+ const ir::OperandInfo _info;
+ std::shared_ptr<const Buffer> _buffer{nullptr};
+};
+
+} // namespace interp
+} // namespace onert
+
+#endif // __ONERT_INTERP_TENSOR_H__
diff --git a/runtime/onert/core/src/interp/operations/BinaryArithmeticOps.cc b/runtime/onert/core/src/interp/operations/BinaryArithmeticOps.cc
new file mode 100644
index 000000000..86e883524
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/BinaryArithmeticOps.cc
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/BinaryArithmeticOps.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/BinaryArithmetic.h"
+#include "misc/polymorphic_downcast.h"
+#include "cker/Types.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace
+{
+
+enum class OpType
+{
+ ADD,
+ SUB,
+ MUL
+};
+
+void prepare(ExecEnv *env, const ir::Operation &node)
+{
+ const auto &arithmetic_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::BinaryArithmetic &>(node);
+
+ const auto lhs_index = node.getInputs().at(arithmetic_node.LHS);
+ const auto rhs_index = node.getInputs().at(arithmetic_node.RHS);
+ const auto out_index = node.getOutputs().at(0);
+
+ const auto lhs_tensor = env->tensorAt(lhs_index);
+ const auto rhs_tensor = env->tensorAt(rhs_index);
+
+ // Check shape and type lhs is same with rhs
+ // TODO Util function to compare TensorInfo
+ if (lhs_tensor->data_type() != rhs_tensor->data_type())
+ {
+ throw std::runtime_error{"Interp(" + arithmetic_node.name() + "): Different input types"};
+ }
+
+ bool try_broadcast = (lhs_tensor->tensorInfo().shape() != rhs_tensor->tensorInfo().shape());
+ if (try_broadcast)
+ {
+ bool success = true;
+ auto out_shape = calcBroadcastShape(lhs_tensor->tensorInfo().shape(),
+ rhs_tensor->tensorInfo().shape(), success);
+ if (!success)
+ {
+ throw std::runtime_error{"Interp(" + arithmetic_node.name() + "): Fail to brodcasting"};
+ }
+
+ auto output_info =
+ ir::OperandInfo::createStaticInfo(out_shape, lhs_tensor->tensorInfo().typeInfo());
+ // We can handle already allocated (ex. model output)
+ env->allocateIfNeeded(out_index, output_info);
+ }
+ else
+ {
+ // Output's shape and type is same with input
+ auto output_info = lhs_tensor->tensorInfo();
+ // We can handle already allocated (ex. model output)
+ env->allocateIfNeeded(out_index, output_info);
+ }
+
+ auto out_tensor = env->tensorAt(out_index);
+ // Check shape and type lhs is same with output
+ // TODO Util function to compare TensorInfo
+ if (lhs_tensor->data_type() != out_tensor->data_type())
+ {
+ throw std::runtime_error{"Interp(" + arithmetic_node.name() + "): Invalid output type"};
+ }
+}
+
+inline void setActivationParams(float min, float max, nnfw::cker::BinaryArithmeticOpParam *params)
+{
+ params->float_activation_min = min;
+ params->float_activation_max = max;
+}
+
+inline void setActivationParams(int32_t min, int32_t max,
+ nnfw::cker::BinaryArithmeticOpParam *params)
+{
+ params->quantized_activation_min = min;
+ params->quantized_activation_max = max;
+}
+
+template <typename raw_type, OpType op_type>
+void invoke(const ITensor *lhs_tensor, const ITensor *rhs_tensor, const ITensor *out_tensor,
+ const ir::operation::BinaryArithmetic::Param &param)
+{
+ const auto lhs_buffer = lhs_tensor->bufferRO();
+ const auto rhs_buffer = rhs_tensor->bufferRO();
+ auto out_buffer = out_tensor->buffer();
+
+ nnfw::cker::BinaryArithmeticOpParam cker_param;
+ raw_type activation_min, activation_max;
+ calculateActivationRange(param.activation, &activation_min, &activation_max);
+ setActivationParams(activation_min, activation_max, &cker_param);
+ const raw_type *lhs_ptr = reinterpret_cast<const raw_type *>(lhs_buffer);
+ const raw_type *rhs_ptr = reinterpret_cast<const raw_type *>(rhs_buffer);
+ raw_type *out_ptr = reinterpret_cast<raw_type *>(out_buffer);
+
+ const auto cker_op_type =
+ (op_type == OpType::ADD)
+ ? nnfw::cker::BinaryArithmeticOpType::ADD
+ : ((op_type == OpType::SUB) ? nnfw::cker::BinaryArithmeticOpType::SUB
+ : nnfw::cker::BinaryArithmeticOpType::MUL);
+
+ const bool need_broadcast = nnfw::cker::ProcessBroadcastShapes(
+ convertShape(lhs_tensor->tensorInfo().shape()),
+ convertShape(rhs_tensor->tensorInfo().shape()), &cker_param);
+
+ if (need_broadcast)
+ {
+ const auto lhs_shape = convertShape(lhs_tensor->tensorInfo().shape());
+ const auto rhs_shape = convertShape(rhs_tensor->tensorInfo().shape());
+ const auto out_shape = convertShape(out_tensor->tensorInfo().shape());
+ nnfw::cker::BroadcastBinaryArithmeticOp<cker_op_type>(cker_param, lhs_shape, lhs_ptr, rhs_shape,
+ rhs_ptr, out_shape, out_ptr);
+ return;
+ }
+
+ const auto lhs_shape = convertShape(lhs_tensor->tensorInfo().shape());
+ const auto rhs_shape = convertShape(rhs_tensor->tensorInfo().shape());
+ const auto out_shape = convertShape(out_tensor->tensorInfo().shape());
+ nnfw::cker::BinaryArithmeticOp<cker_op_type>(cker_param, lhs_shape, lhs_ptr, rhs_shape, rhs_ptr,
+ out_shape, out_ptr);
+}
+
+template <OpType op_type>
+void invokeBinaryArithmetic(const ExecEnv *env, const ir::operation::BinaryArithmetic &node)
+{
+ const auto lhs_index = node.getInputs().at(node.LHS);
+ const auto rhs_index = node.getInputs().at(node.RHS);
+ const auto out_index = node.getOutputs().at(0);
+ const auto lhs_tensor = env->tensorAt(lhs_index);
+ const auto rhs_tensor = env->tensorAt(rhs_index);
+ const auto out_tensor = env->tensorAt(out_index);
+ const auto data_type = lhs_tensor->data_type();
+
+ if (data_type == ir::DataType::INT32)
+ {
+ invoke<int32_t, op_type>(lhs_tensor, rhs_tensor, out_tensor, node.param());
+ }
+ else if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke<float, op_type>(lhs_tensor, rhs_tensor, out_tensor, node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Unsupported data type"};
+ }
+}
+
+void invokeBinaryArithmeticOps(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &arithmetic_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::BinaryArithmetic &>(node);
+
+ switch (arithmetic_node.param().arithmetic_type)
+ {
+ case ir::operation::BinaryArithmetic::ArithmeticType::ADD:
+ invokeBinaryArithmetic<OpType::ADD>(env, arithmetic_node);
+ break;
+ case ir::operation::BinaryArithmetic::ArithmeticType::SUB:
+ invokeBinaryArithmetic<OpType::SUB>(env, arithmetic_node);
+ break;
+ case ir::operation::BinaryArithmetic::ArithmeticType::MUL:
+ invokeBinaryArithmetic<OpType::MUL>(env, arithmetic_node);
+ break;
+ default:
+ throw std::runtime_error{"Interp(BinaryArithmetic): NYI unsupported operation " +
+ arithmetic_node.name()};
+ break;
+ }
+}
+
+} // namespace
+
+OpKernel *getBinaryArithmetic()
+{
+ static OpKernel kernel = {prepare, invokeBinaryArithmeticOps};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/Concat.cc b/runtime/onert/core/src/interp/operations/Concat.cc
new file mode 100644
index 000000000..efc46c66b
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/Concat.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/Concatenation.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/Concat.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace concat
+{
+
+void prepareConcat(ExecEnv *env, const ir::Operation &node)
+{
+ const auto &concat_node = nnfw::misc::polymorphic_downcast<const ir::operation::Concat &>(node);
+
+ const auto first_index = node.getInputs().at(0);
+ const auto out_index = node.getOutputs().at(0);
+
+ const auto first_tensor = env->tensorAt(first_index);
+ uint32_t out_axis_dimension = 0;
+ const int32_t axis_raw = concat_node.param().axis;
+ const uint32_t axis = (axis_raw < 0) ? (axis_raw + first_tensor->num_dimensions()) : axis_raw;
+
+ // All inputs shape should be same except axis dimension
+ // All inputs type should be same
+ for (auto input : node.getInputs())
+ {
+ assert(first_tensor->num_dimensions() == env->tensorAt(input)->num_dimensions());
+ assert(first_tensor->data_type() == env->tensorAt(input)->data_type());
+ for (uint32_t i = 0; i < first_tensor->num_dimensions(); i++)
+ {
+ if (i == axis)
+ {
+ out_axis_dimension += env->tensorAt(input)->dimension(i);
+ continue;
+ }
+ assert(first_tensor->dimension(i) == env->tensorAt(input)->dimension(i));
+ }
+ }
+
+ // Make output tensor info using first input tensor info, and accumulated axis dimension value
+ auto out_shape = first_tensor->tensorInfo().shape();
+ out_shape.dim(axis) = out_axis_dimension;
+ env->allocateIfNeeded(out_index, ir::OperandInfo::createStaticInfo(
+ out_shape, first_tensor->tensorInfo().typeInfo()));
+
+ auto out_tensor = env->tensorAt(out_index);
+ UNUSED_RELEASE(out_tensor);
+
+ // Output shape should be same with input except axis dimension
+ // Output type should be same with input
+ assert(first_tensor->data_type() == out_tensor->data_type());
+ for (uint32_t i = 0; i < first_tensor->num_dimensions(); i++)
+ {
+ if (i == axis)
+ {
+ continue;
+ }
+ assert(first_tensor->dimension(i) == out_tensor->dimension(i));
+ }
+}
+
+void invoke(const std::vector<const ITensor *> in_tensors, const ITensor *out_tensor, uint32_t axis)
+{
+ const uint32_t count = in_tensors.size();
+
+ // Calculate
+ nnfw::cker::ConcatenationParams cker_param;
+ cker_param.axis = (int8_t)axis;
+ cker_param.inputs_count = count;
+
+ const auto out_shape = convertShape(out_tensor->tensorInfo().shape());
+
+ std::vector<nnfw::cker::Shape> in_shapes;
+ std::vector<const nnfw::cker::Shape *> in_shape_ptrs;
+ in_shapes.reserve(count);
+ in_shape_ptrs.reserve(count);
+ std::vector<const float *> in_ptrs;
+ for (uint32_t i = 0; i < count; i++)
+ {
+ in_shapes.push_back(convertShape(in_tensors[i]->tensorInfo().shape()));
+ in_shape_ptrs.push_back(&in_shapes[i]);
+ in_ptrs.push_back(reinterpret_cast<const float *>(in_tensors[i]->bufferRO()));
+ }
+
+ auto out_buffer = out_tensor->buffer();
+ float *out_ptr = reinterpret_cast<float *>(out_buffer);
+
+ nnfw::cker::Concatenation<float>(cker_param, in_shape_ptrs.data(), in_ptrs.data(), out_shape,
+ out_ptr);
+}
+
+void invokeConcat(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &concat_node = nnfw::misc::polymorphic_downcast<const ir::operation::Concat &>(node);
+ const int32_t axis_raw = concat_node.param().axis;
+
+ std::vector<const ITensor *> in_tensors;
+ for (const auto &e : concat_node.getInputs())
+ {
+ in_tensors.emplace_back(env->tensorAt(e));
+ }
+
+ const auto out_index = node.getOutputs().at(0);
+ const auto out_tensor = env->tensorAt(out_index);
+ const uint32_t axis = (axis_raw < 0) ? (axis_raw + out_tensor->num_dimensions()) : axis_raw;
+
+ const auto data_type = in_tensors[0]->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(in_tensors, out_tensor, axis);
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Support float32 only"};
+ }
+}
+} // namespace concat
+
+OpKernel *getConcat()
+{
+ static OpKernel kernel = {concat::prepareConcat, concat::invokeConcat};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/Conv2D.cc b/runtime/onert/core/src/interp/operations/Conv2D.cc
new file mode 100644
index 000000000..bb00b828c
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/Conv2D.cc
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/Conv.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/Conv2D.h"
+#include "util/Utils.h"
+#include "util/ShapeInference.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace conv2d
+{
+
+void prepareConv2D(ExecEnv *env, const ir::Operation &node)
+{
+ const auto in_index = node.getInputs().at(ir::operation::Conv2D::INPUT);
+ const auto kernel_index = node.getInputs().at(ir::operation::Conv2D::KERNEL);
+ const auto bias_index = node.getInputs().at(ir::operation::Conv2D::BIAS);
+ const auto out_index = node.getOutputs().at(0);
+
+ const auto in_tensor = env->tensorAt(in_index);
+ const auto kernel_tensor = env->tensorAt(kernel_index);
+ const auto bias_tensor = env->tensorAt(bias_index);
+
+ assert(in_tensor->num_dimensions() == 4);
+ assert(kernel_tensor->num_dimensions() == 4);
+ assert(bias_tensor->num_dimensions() == 1);
+
+ UNUSED_RELEASE(in_tensor);
+ UNUSED_RELEASE(kernel_tensor);
+ UNUSED_RELEASE(bias_tensor);
+
+ const auto output_info = env->graph().operands().at(out_index).info();
+ if (output_info.total_size() == 0)
+ {
+ // Handle unspecified output shape
+ const auto &conv_node = nnfw::misc::polymorphic_downcast<const ir::operation::Conv2D &>(node);
+ const auto infered_output_shape = shape_inference::inferConv2DShape(
+ in_tensor->tensorInfo().shape(), kernel_tensor->tensorInfo().shape(), conv_node.param());
+ env->allocateIfNeeded(
+ out_index, ir::OperandInfo::createStaticInfo(infered_output_shape, output_info.typeInfo()));
+ }
+ else
+ {
+ env->allocateIfNeeded(out_index, output_info);
+ }
+
+ auto out_tensor = env->tensorAt(out_index);
+ UNUSED_RELEASE(out_tensor);
+
+ // Handle same ifm & ofm data type only
+ assert(in_tensor->data_type() == out_tensor->data_type());
+ assert(out_tensor->num_dimensions() == 4);
+}
+
+void invoke(const ITensor *ifm_tensor, const ITensor *ker_tensor, const ITensor *bias_tensor,
+ const ITensor *ofm_tensor, const ir::operation::Conv2D::Param &param)
+{
+ // TODO Support NCHW frontned
+ const auto ifm_shape = ifm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC);
+ const auto ofm_shape = ofm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC);
+ // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
+ const auto &ker_shape = ker_tensor->tensorInfo().shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+ const auto padding = ir::calculatePadding(param.padding, ifm_shape, ofm_shape, param.stride,
+ ker_width, ker_height);
+
+ // Calculate
+ float activation_min, activation_max;
+ calculateActivationRange(param.activation, &activation_min, &activation_max);
+
+ nnfw::cker::ConvParams cker_param;
+ cker_param.padding_type = convertPaddingType(param.padding.type);
+ cker_param.padding_values.width = padding.left;
+ cker_param.padding_values.height = padding.top;
+ cker_param.stride_width = param.stride.horizontal;
+ cker_param.stride_height = param.stride.vertical;
+ cker_param.dilation_width_factor = 1;
+ cker_param.dilation_height_factor = 1;
+ cker_param.float_activation_min = activation_min;
+ cker_param.float_activation_max = activation_max;
+
+ const auto cker_ifm_shape = convertShape(ifm_tensor->tensorInfo().shape());
+ const auto cker_ker_shape = convertShape(ker_tensor->tensorInfo().shape());
+ const auto cker_bias_shape = convertShape(bias_tensor->tensorInfo().shape());
+ const auto cker_ofm_shape = convertShape(ofm_tensor->tensorInfo().shape());
+ const float *ifm_ptr = reinterpret_cast<const float *>(ifm_tensor->bufferRO());
+ const float *ker_ptr = reinterpret_cast<const float *>(ker_tensor->bufferRO());
+ const float *bias_ptr = reinterpret_cast<const float *>(bias_tensor->bufferRO());
+ float *ofm_ptr = reinterpret_cast<float *>(ofm_tensor->buffer());
+
+ nnfw::cker::Conv conv_kernel;
+ conv_kernel(cker_param, cker_ifm_shape, ifm_ptr, cker_ker_shape, ker_ptr, cker_bias_shape,
+ bias_ptr, cker_ofm_shape, ofm_ptr);
+}
+
+void invokeConv2D(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &conv_node = nnfw::misc::polymorphic_downcast<const ir::operation::Conv2D &>(node);
+
+ const auto ifm_index = node.getInputs().at(ir::operation::Conv2D::INPUT);
+ const auto ker_index = node.getInputs().at(ir::operation::Conv2D::KERNEL);
+ const auto bias_index = node.getInputs().at(ir::operation::Conv2D::BIAS);
+ const auto ofm_index = node.getOutputs().at(0);
+
+ const auto ifm_tensor = env->tensorAt(ifm_index);
+ const auto ker_tensor = env->tensorAt(ker_index);
+ const auto bias_tensor = env->tensorAt(bias_index);
+ const auto ofm_tensor = env->tensorAt(ofm_index);
+
+ const auto data_type = ifm_tensor->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(ifm_tensor, ker_tensor, bias_tensor, ofm_tensor, conv_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Support float32 only"};
+ }
+}
+} // namespace conv2d
+
+OpKernel *getConv2D()
+{
+ static OpKernel kernel = {conv2d::prepareConv2D, conv2d::invokeConv2D};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/DepthwiseConv2D.cc b/runtime/onert/core/src/interp/operations/DepthwiseConv2D.cc
new file mode 100644
index 000000000..0473855d9
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/DepthwiseConv2D.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/DepthwiseConv.h>
+#include <misc/polymorphic_downcast.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/DepthwiseConv2D.h"
+#include "util/Utils.h"
+#include "util/ShapeInference.h"
+
+namespace onert
+{
+namespace interp
+{
+
+namespace
+{
+
+void prepareDepthwiseConv(ExecEnv *env, const ir::Operation &node)
+{
+ const auto in_index = node.getInputs().at(ir::operation::DepthwiseConv2D::INPUT);
+ const auto kernel_index = node.getInputs().at(ir::operation::DepthwiseConv2D::KERNEL);
+ const auto bias_index = node.getInputs().at(ir::operation::DepthwiseConv2D::BIAS);
+ const auto out_index = node.getOutputs().at(0);
+
+ const auto in_tensor = env->tensorAt(in_index);
+ const auto kernel_tensor = env->tensorAt(kernel_index);
+ const auto bias_tensor = env->tensorAt(bias_index);
+
+ assert(in_tensor->num_dimensions() == 4);
+ assert(kernel_tensor->num_dimensions() == 4);
+ assert(bias_tensor->num_dimensions() == 1);
+
+ UNUSED_RELEASE(in_tensor);
+ UNUSED_RELEASE(kernel_tensor);
+ UNUSED_RELEASE(bias_tensor);
+
+ // TODO handle unspecified output shape:
+ // calculate output shape using ifm shape, kernel shape, padding, stride
+ const auto output_info = env->graph().operands().at(out_index).info();
+ if (output_info.total_size() == 0)
+ {
+ // Handle unspecified output shape
+ const auto &depth_conv_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::DepthwiseConv2D &>(node);
+ const auto infered_output_shape = shape_inference::inferDepthwiseConv2DShape(
+ in_tensor->tensorInfo().shape(), kernel_tensor->tensorInfo().shape(),
+ depth_conv_node.param());
+ env->allocateIfNeeded(
+ out_index, ir::OperandInfo::createStaticInfo(infered_output_shape, output_info.typeInfo()));
+ }
+ else
+ {
+ env->allocateIfNeeded(out_index, output_info);
+ }
+
+ auto out_tensor = env->tensorAt(out_index);
+ UNUSED_RELEASE(out_tensor);
+
+ // Handle same ifm & ofm data type only
+ assert(in_tensor->data_type() == out_tensor->data_type());
+ assert(out_tensor->num_dimensions() == 4);
+}
+
+void invoke(const ITensor *ifm_tensor, const ITensor *ker_tensor, const ITensor *bias_tensor,
+ const ITensor *ofm_tensor, const ir::operation::DepthwiseConv2D::Param &param)
+{
+ // TODO Support NCHW frontend
+ const auto ifm_shape = ifm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC);
+ const auto ofm_shape = ofm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC);
+ // Kernel format is [1, kernel_height, kernel_width, depth_out].
+ const auto &ker_shape = ker_tensor->tensorInfo().shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+ const auto padding = ir::calculatePadding(param.padding, ifm_shape, ofm_shape, param.stride,
+ ker_width, ker_height);
+
+ // Calculate
+ float activation_min, activation_max;
+ calculateActivationRange(param.activation, &activation_min, &activation_max);
+
+ nnfw::cker::DepthwiseConvParams cker_param;
+ cker_param.padding_values.width = padding.left;
+ cker_param.padding_values.height = padding.top;
+ cker_param.depth_multiplier = param.multiplier;
+ cker_param.stride_width = param.stride.horizontal;
+ cker_param.stride_height = param.stride.vertical;
+ cker_param.dilation_width_factor = 1;
+ cker_param.dilation_height_factor = 1;
+ cker_param.float_activation_min = activation_min;
+ cker_param.float_activation_max = activation_max;
+
+ const auto cker_ifm_shape = convertShape(ifm_tensor->tensorInfo().shape());
+ const auto cker_ker_shape = convertShape(ker_tensor->tensorInfo().shape());
+ const auto cker_bias_shape = convertShape(bias_tensor->tensorInfo().shape());
+ const auto cker_ofm_shape = convertShape(ofm_tensor->tensorInfo().shape());
+ const float *ifm_ptr = reinterpret_cast<const float *>(ifm_tensor->bufferRO());
+ const float *ker_ptr = reinterpret_cast<const float *>(ker_tensor->bufferRO());
+ const float *bias_ptr = reinterpret_cast<const float *>(bias_tensor->bufferRO());
+ float *ofm_ptr = reinterpret_cast<float *>(ofm_tensor->buffer());
+
+ nnfw::cker::DepthwiseConv(cker_param, cker_ifm_shape, ifm_ptr, cker_ker_shape, ker_ptr,
+ cker_bias_shape, bias_ptr, cker_ofm_shape, ofm_ptr);
+}
+
+void invokeDepthwiseConv(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &conv_node = static_cast<const ir::operation::DepthwiseConv2D &>(node);
+
+ const auto ifm_index = node.getInputs().at(ir::operation::DepthwiseConv2D::INPUT);
+ const auto ker_index = node.getInputs().at(ir::operation::DepthwiseConv2D::KERNEL);
+ const auto bias_index = node.getInputs().at(ir::operation::DepthwiseConv2D::BIAS);
+ const auto ofm_index = node.getOutputs().at(0);
+
+ const auto ifm_tensor = env->tensorAt(ifm_index);
+ const auto ker_tensor = env->tensorAt(ker_index);
+ const auto bias_tensor = env->tensorAt(bias_index);
+ const auto ofm_tensor = env->tensorAt(ofm_index);
+
+ const auto data_type = ifm_tensor->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(ifm_tensor, ker_tensor, bias_tensor, ofm_tensor, conv_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Support float32 only"};
+ }
+}
+
+} // namespace
+
+OpKernel *getDepthwiseConv2D()
+{
+ static OpKernel kernel = {prepareDepthwiseConv, invokeDepthwiseConv};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/ElementwiseActivations.cc b/runtime/onert/core/src/interp/operations/ElementwiseActivations.cc
new file mode 100644
index 000000000..c8773bef4
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/ElementwiseActivations.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cmath>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+
+#include "ir/operation/ElementwiseActivation.h"
+
+#include <misc/polymorphic_downcast.h>
+#include <cker/operation/Logistic.h>
+#include <cker/operation/Tanh.h>
+
+namespace onert
+{
+namespace interp
+{
+namespace
+{
+
+enum class ActivationType
+{
+ Logistic,
+ ReLU,
+ Tanh
+};
+
+void prepare(ExecEnv *env, const ir::Operation &node)
+{
+ const auto input_index = node.getInputs().at(0);
+ const auto output_index = node.getOutputs().at(0);
+
+ const auto input_tensor = env->tensorAt(input_index);
+
+ const auto output_info = env->graph().operands().at(output_index).info();
+ if (output_info.total_size() == 0)
+ {
+ // Output's shape and type is same with input
+ auto input_info = input_tensor->tensorInfo();
+ // We can handle already allocated (ex. model output)
+ env->allocateIfNeeded(output_index, input_info);
+ }
+ else
+ {
+ env->allocateIfNeeded(output_index, output_info);
+ }
+
+ const auto output_tensor = env->tensorAt(output_index);
+ // Check shape and type lhs is same with output
+ // TODO Util function to compare TensorInfo
+ if (input_tensor->data_type() != output_tensor->data_type())
+ {
+ throw std::runtime_error{"Interp(ElementwiseActivation): Invalid output type"};
+ }
+}
+
+template <ActivationType act_type>
+void evalFloat(const float *input_ptr, float *output_ptr, uint64_t num_elements, float alpha,
+ float beta)
+{
+ std::function<float(const float &)> fn = [](const float &) { return std::nanf(""); };
+ switch (act_type)
+ {
+ case ActivationType::ReLU:
+ fn = [alpha, beta](const float &in) { return std::min(std::max(beta, in), alpha); };
+ break;
+ case ActivationType::Tanh:
+ fn = [](const float &in) { return std::tanh(in); };
+ break;
+ default:
+ throw std::runtime_error{"Interp(ElementwiseActivation): NYI - Unsupported activation"};
+ break;
+ }
+
+ const float *input_end = input_ptr + num_elements;
+ for (; input_ptr < input_end; input_ptr++, output_ptr++)
+ {
+ *output_ptr = fn(*input_ptr);
+ }
+}
+
+template <ActivationType act_type> void invoke(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto input_index = node.getInputs().at(0);
+ const auto output_index = node.getOutputs().at(0);
+
+ // Check lhs shape is same with rhs (with broadcast)
+ const auto input_tensor = env->tensorAt(input_index);
+ const auto output_tensor = env->tensorAt(output_index);
+
+ const auto data_type = input_tensor->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ uint64_t elements = input_tensor->num_elements();
+ const float *input_start = reinterpret_cast<const float *>(input_tensor->bufferRO());
+ float *out = reinterpret_cast<float *>(output_tensor->buffer());
+ if (act_type == ActivationType::Logistic)
+ {
+ const auto cker_input_shape = convertShape(input_tensor->tensorInfo().shape());
+ const auto cker_output_shape = convertShape(output_tensor->tensorInfo().shape());
+ nnfw::cker::Logistic(cker_input_shape, input_start, cker_output_shape, out);
+ }
+ else
+ {
+ const auto &act_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::ElementwiseActivation &>(node);
+ evalFloat<act_type>(input_start, out, elements, act_node.param().alpha,
+ act_node.param().beta);
+ }
+ }
+ else
+ {
+ throw std::runtime_error{"Interp(" + node.name() + "): NYI - Support float only"};
+ }
+}
+
+void invokeElementwiseActivation(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &act_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::ElementwiseActivation &>(node);
+ switch (act_node.param().op_type)
+ {
+ case ir::operation::ElementwiseActivation::Type::LOGISTIC:
+ invoke<ActivationType::Logistic>(env, node);
+ break;
+ case ir::operation::ElementwiseActivation::Type::RELU:
+ invoke<ActivationType::ReLU>(env, node);
+ break;
+ case ir::operation::ElementwiseActivation::Type::TANH:
+ invoke<ActivationType::Tanh>(env, node);
+ break;
+ default:
+ throw std::runtime_error("Interp(" + node.name() + "): NYI - Unsupported activation");
+ }
+}
+
+} // namespace
+
+OpKernel *getElementwiseActivation()
+{
+ static OpKernel kernel = {prepare, invokeElementwiseActivation};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/FullyConnected.cc b/runtime/onert/core/src/interp/operations/FullyConnected.cc
new file mode 100644
index 000000000..4f97632b2
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/FullyConnected.cc
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/FullyConnected.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/FullyConnected.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace fc
+{
+
+void prepareFC(ExecEnv *env, const ir::Operation &node)
+{
+ const auto in_index = node.getInputs().at(ir::operation::FullyConnected::INPUT);
+ const auto kernel_index = node.getInputs().at(ir::operation::FullyConnected::WEIGHT);
+ const auto bias_index = node.getInputs().at(ir::operation::FullyConnected::BIAS);
+ const auto out_index = node.getOutputs().at(0);
+
+ const auto in_tensor = env->tensorAt(in_index);
+ const auto kernel_tensor = env->tensorAt(kernel_index);
+ const auto bias_tensor = env->tensorAt(bias_index);
+
+ UNUSED_RELEASE(in_tensor);
+ UNUSED_RELEASE(kernel_tensor);
+ UNUSED_RELEASE(bias_tensor);
+
+ assert(in_tensor->num_dimensions() >= 2);
+ assert(kernel_tensor->num_dimensions() == 2);
+ assert(bias_tensor->num_dimensions() == 1);
+
+ const auto input_size_with_batch = in_tensor->num_elements();
+ const auto num_units = kernel_tensor->dimension(0);
+ const auto input_size = kernel_tensor->dimension(1);
+ const auto batch_size = input_size_with_batch / input_size;
+ assert(input_size_with_batch % input_size == 0);
+ assert(num_units == bias_tensor->dimension(0));
+
+ // Make output tensor info
+ ir::Shape output_shape(2);
+ output_shape.dim(0) = batch_size;
+ output_shape.dim(1) = num_units;
+ const auto out_info =
+ ir::OperandInfo::createStaticInfo(output_shape, in_tensor->tensorInfo().typeInfo());
+ env->allocateIfNeeded(out_index, out_info);
+
+ auto out_tensor = env->tensorAt(out_index);
+ UNUSED_RELEASE(out_tensor);
+
+ // Handle same ifm & ofm data type only
+ assert(in_tensor->data_type() == out_tensor->data_type());
+ assert(out_tensor->num_dimensions() == 2);
+ assert(out_tensor->dimension(0) == batch_size);
+ assert(out_tensor->dimension(1) == num_units);
+}
+
+void invoke(const ITensor *ifm_tensor, const ITensor *ker_tensor, const ITensor *bias_tensor,
+ const ITensor *ofm_tensor, const ir::operation::FullyConnected::Param &param)
+{
+ const auto ifm_buffer = ifm_tensor->bufferRO();
+ const auto ker_buffer = ker_tensor->bufferRO();
+ const auto bias_buffer = bias_tensor->bufferRO();
+ auto ofm_buffer = ofm_tensor->buffer();
+
+ // Calculate
+ nnfw::cker::FullyConnectedParams cker_param;
+ cker_param.activation = convertActivationType(param.activation);
+ const auto cker_ifm_shape = convertShape(ifm_tensor->tensorInfo().shape());
+ const auto cker_ker_shape = convertShape(ker_tensor->tensorInfo().shape());
+ const auto cker_bias_shape = convertShape(bias_tensor->tensorInfo().shape());
+ const auto cker_ofm_shape = convertShape(ofm_tensor->tensorInfo().shape());
+ const float *ifm_ptr = reinterpret_cast<const float *>(ifm_buffer);
+ const float *ker_ptr = reinterpret_cast<const float *>(ker_buffer);
+ const float *bias_ptr = reinterpret_cast<const float *>(bias_buffer);
+ float *ofm_ptr = reinterpret_cast<float *>(ofm_buffer);
+
+ nnfw::cker::FullyConnected(cker_param, cker_ifm_shape, ifm_ptr, cker_ker_shape, ker_ptr,
+ cker_bias_shape, bias_ptr, cker_ofm_shape, ofm_ptr);
+}
+
+void invokeFC(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &conv_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::FullyConnected &>(node);
+
+ const auto ifm_index = node.getInputs().at(ir::operation::FullyConnected::INPUT);
+ const auto ker_index = node.getInputs().at(ir::operation::FullyConnected::WEIGHT);
+ const auto bias_index = node.getInputs().at(ir::operation::FullyConnected::BIAS);
+ const auto ofm_index = node.getOutputs().at(0);
+
+ const auto ifm_tensor = env->tensorAt(ifm_index);
+ const auto ker_tensor = env->tensorAt(ker_index);
+ const auto bias_tensor = env->tensorAt(bias_index);
+ const auto ofm_tensor = env->tensorAt(ofm_index);
+
+ const auto data_type = ifm_tensor->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(ifm_tensor, ker_tensor, bias_tensor, ofm_tensor, conv_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Support float only"};
+ }
+}
+} // namespace fc
+
+OpKernel *getFullyConnected()
+{
+ static OpKernel kernel = {fc::prepareFC, fc::invokeFC};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/Gather.cc b/runtime/onert/core/src/interp/operations/Gather.cc
new file mode 100644
index 000000000..9e82def5f
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/Gather.cc
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/Gather.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/Gather.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace
+{
+
+void prepareGather(ExecEnv *env, const ir::Operation &node)
+{
+ const auto input_index = node.getInputs().at(ir::operation::Gather::INPUT);
+ const auto indices_index = node.getInputs().at(ir::operation::Gather::INDICES);
+ const auto output_index = node.getOutputs().at(0);
+
+ const auto input_tensor = env->tensorAt(input_index);
+ const auto indices_tensor = env->tensorAt(indices_index);
+
+ // TODO handle unspecified output shape:
+ // calculate output shape using ifm shape, kernel shape, padding, stride
+ const auto output_info = env->graph().operands().at(output_index).info();
+ if (output_info.total_size() == 0)
+ {
+ throw std::runtime_error{"Interp(Gather): NYI for unspecified output shape"};
+ }
+ else
+ {
+ env->allocateIfNeeded(output_index, output_info);
+ }
+
+ if (indices_tensor->data_type() != ir::DataType::INT32)
+ {
+ throw std::runtime_error{"Interp(Gather): Invalid indices data type"};
+ }
+
+ auto output_tensor = env->tensorAt(output_index);
+ auto output_rank = input_tensor->num_dimensions() + indices_tensor->num_dimensions() - 1;
+
+ if (output_rank != output_tensor->num_dimensions())
+ {
+ throw std::runtime_error{"Interp(Gather): Invalid output rank"};
+ }
+ if (output_tensor->data_type() != input_tensor->data_type())
+ {
+ throw std::runtime_error{"Interp(Gather): Invalid output data type"};
+ }
+
+ if (input_tensor->data_type() == ir::DataType::QUANT_UINT8_ASYMM &&
+ input_tensor->tensorInfo().typeInfo() != output_tensor->tensorInfo().typeInfo())
+ {
+ throw std::runtime_error{
+ "Interp(Gather): Cannot handle different I/O QUANT_UINT8_ASYMM scale/offset"};
+ }
+}
+
+template <typename raw_type>
+void invoke(const ITensor *input_tensors, const ITensor *indices_tensors,
+ const ITensor *output_tensor, uint32_t axis)
+{
+ // Calculate
+ nnfw::cker::GatherParams cker_param;
+ cker_param.axis = (int8_t)axis;
+
+ const auto cker_input_shapes = convertShape(input_tensors->tensorInfo().shape());
+ const auto cker_indices_shape = convertShape(indices_tensors->tensorInfo().shape());
+ const auto cker_output_shape = convertShape(output_tensor->tensorInfo().shape());
+ const raw_type *input_ptr = reinterpret_cast<const raw_type *>(input_tensors->bufferRO());
+ const int32_t *indices_ptr = reinterpret_cast<const int32_t *>(indices_tensors->bufferRO());
+ raw_type *output_ptr = reinterpret_cast<raw_type *>(output_tensor->buffer());
+
+ nnfw::cker::Gather<raw_type>(cker_param, cker_input_shapes, input_ptr, cker_indices_shape,
+ indices_ptr, cker_output_shape, output_ptr);
+}
+
+void invokeGather(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &gather_node = nnfw::misc::polymorphic_downcast<const ir::operation::Gather &>(node);
+ const int32_t axis_raw = gather_node.param().axis;
+
+ const auto input_index = node.getInputs().at(ir::operation::Gather::INPUT);
+ const auto indices_index = node.getInputs().at(ir::operation::Gather::INDICES);
+ const auto output_index = node.getOutputs().at(0);
+
+ const auto input_tensor = env->tensorAt(input_index);
+ const auto indices_tensor = env->tensorAt(indices_index);
+ const auto output_tensor = env->tensorAt(output_index);
+ const uint32_t axis = (axis_raw < 0) ? (axis_raw + input_tensor->num_dimensions()) : axis_raw;
+
+ const auto data_type = input_tensor->data_type();
+
+ switch (data_type)
+ {
+ case ir::DataType::FLOAT32:
+ invoke<float>(input_tensor, indices_tensor, output_tensor, axis);
+ break;
+ case ir::DataType::INT32:
+ invoke<int32_t>(input_tensor, indices_tensor, output_tensor, axis);
+ break;
+ case ir::DataType::QUANT_UINT8_ASYMM:
+ invoke<uint8_t>(input_tensor, indices_tensor, output_tensor, axis);
+ break;
+ default:
+ throw std::runtime_error{"Interp(Gather): NYI - Not supported type"};
+ }
+}
+
+} // namespace
+
+OpKernel *getGather()
+{
+ static OpKernel kernel = {prepareGather, invokeGather};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/InstanceNorm.cc b/runtime/onert/core/src/interp/operations/InstanceNorm.cc
new file mode 100644
index 000000000..2538bcc39
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/InstanceNorm.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/InstanceNorm.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/InstanceNorm.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace instancenorm
+{
+
+void prepareInstanceNorm(ExecEnv *env, const ir::Operation &node)
+{
+ const auto &instancenorm_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::InstanceNorm &>(node);
+
+ const auto input_index = node.getInputs().at(instancenorm_node.INPUT);
+ const auto output_index = node.getOutputs().at(0);
+ const auto input_tensor = env->tensorAt(input_index);
+
+ if (input_tensor->num_dimensions() != 4)
+ {
+ throw std::runtime_error{"Interp(InstanceNorm): Input should be 4D-tensor"};
+ }
+
+ // Output shape should be same with input
+ env->allocateIfNeeded(output_index, input_tensor->tensorInfo());
+
+ auto output_tensor = env->tensorAt(output_index);
+ UNUSED_RELEASE(output_tensor);
+
+ // Handle same ifm & ofm data type only
+ assert(input_tensor->data_type() == output_tensor->data_type());
+ assert(input_tensor->tensorInfo().shape() == output_tensor->tensorInfo().shape());
+}
+
+inline void setActivationParams(float min, float max, nnfw::cker::InstanceNormParams *params)
+{
+ params->float_activation_min = min;
+ params->float_activation_max = max;
+}
+
+void invoke(const ITensor *input_tensor, const ITensor *gamma_tensor, const ITensor *beta_tensor,
+ const ITensor *output_tensor, const ir::operation::InstanceNorm::Param &param)
+{
+ // Calculate
+ float activation_min, activation_max;
+ calculateActivationRange(param.activation, &activation_min, &activation_max);
+
+ nnfw::cker::InstanceNormParams cker_param;
+ cker_param.epsilon = param.epsilon;
+ cker_param.float_activation_min = activation_min;
+ cker_param.float_activation_max = activation_max;
+
+ const auto cker_input_shape = convertShape(input_tensor->tensorInfo().shape());
+ const auto cker_gamma_shape = convertShape(gamma_tensor->tensorInfo().shape());
+ const auto cker_beta_shape = convertShape(beta_tensor->tensorInfo().shape());
+ const auto cker_output_shape = convertShape(output_tensor->tensorInfo().shape());
+ const float *input_ptr = reinterpret_cast<const float *>(input_tensor->bufferRO());
+ const float *gamma_ptr = reinterpret_cast<const float *>(gamma_tensor->bufferRO());
+ const float *beta_ptr = reinterpret_cast<const float *>(beta_tensor->bufferRO());
+ float *output_ptr = reinterpret_cast<float *>(output_tensor->buffer());
+
+ nnfw::cker::InstanceNorm(cker_param, cker_input_shape, input_ptr, cker_gamma_shape, gamma_ptr,
+ cker_beta_shape, beta_ptr, cker_output_shape, output_ptr);
+}
+
+void invokeInstanceNorm(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &instancenorm_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::InstanceNorm &>(node);
+
+ const auto input_index = node.getInputs().at(instancenorm_node.INPUT);
+ const auto gamma_index = node.getInputs().at(instancenorm_node.GAMMA);
+ const auto beta_index = node.getInputs().at(instancenorm_node.BETA);
+ const auto out_index = node.getOutputs().at(0);
+ const auto input_tensor = env->tensorAt(input_index);
+ const auto gamma_tensor = env->tensorAt(gamma_index);
+ const auto beta_tensor = env->tensorAt(beta_index);
+ const auto out_tensor = env->tensorAt(out_index);
+ const auto data_type = input_tensor->data_type();
+
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(input_tensor, gamma_tensor, beta_tensor, out_tensor, instancenorm_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Unsupported data type"};
+ }
+}
+} // namespace instancenorm
+
+OpKernel *getInstanceNorm()
+{
+ static OpKernel kernel = {instancenorm::prepareInstanceNorm, instancenorm::invokeInstanceNorm};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/OperationUtil.h b/runtime/onert/core/src/interp/operations/OperationUtil.h
new file mode 100644
index 000000000..2fdf098f0
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/OperationUtil.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_INTERP_OPERATIONS_OPERATION_UTILS_H_
+#define __ONERT_INTERP_OPERATIONS_OPERATION_UTILS_H_
+
+#include "ir/Shape.h"
+#include "ir/InternalType.h"
+#include "ir/Padding.h"
+
+#include <cker/Shape.h>
+#include <cker/Types.h>
+
+namespace onert
+{
+namespace interp
+{
+
+inline nnfw::cker::Shape convertShape(const ir::Shape &shape)
+{
+ auto dimensions = std::vector<uint32_t>(shape.dims().begin(), shape.dims().end());
+
+ std::vector<int32_t> raw_shape;
+ raw_shape.resize(dimensions.size());
+
+ for (uint32_t i = 0; i < dimensions.size(); ++i)
+ {
+ raw_shape[i] = dimensions[i];
+ }
+
+ return nnfw::cker::GetShape(raw_shape);
+}
+
+inline nnfw::cker::Shape convertExtendShape(const ir::Shape &shape)
+{
+ auto dimensions = std::vector<uint32_t>(shape.dims().begin(), shape.dims().end());
+
+ const int32_t extended_rank = 4;
+ int32_t raw_shape[extended_rank];
+ uint32_t start = extended_rank - dimensions.size();
+
+ for (uint32_t i = 0; i < extended_rank; ++i)
+ {
+ if (i < start)
+ {
+ raw_shape[i] = 1;
+ }
+ else
+ {
+ raw_shape[i] = dimensions[i - start];
+ }
+ }
+
+ return nnfw::cker::Shape(extended_rank, raw_shape);
+}
+
+inline nnfw::cker::FusedActivationFunctionType
+convertActivationType(const ir::Activation activation)
+{
+ switch (activation)
+ {
+ case ir::Activation::NONE:
+ return nnfw::cker::FusedActivationFunctionType::kNone;
+ case ir::Activation::RELU:
+ return nnfw::cker::FusedActivationFunctionType::kRelu;
+ case ir::Activation::RELU1:
+ return nnfw::cker::FusedActivationFunctionType::kRelu1;
+ case ir::Activation::RELU6:
+ return nnfw::cker::FusedActivationFunctionType::kRelu6;
+ default:
+ throw std::runtime_error{"CPU backend: Cannot convert activation type"};
+ }
+}
+
+template <typename T>
+void calculateActivationRange(ir::Activation activation, T *activation_min, T *activation_max)
+{
+ if (activation == ir::Activation::RELU)
+ {
+ *activation_min = 0;
+ *activation_max = std::numeric_limits<T>::max();
+ }
+ else if (activation == ir::Activation::RELU6)
+ {
+ *activation_min = 0;
+ *activation_max = 6;
+ }
+ else if (activation == ir::Activation::RELU1)
+ {
+ *activation_min = -1;
+ *activation_max = 1;
+ }
+ else if (activation == ir::Activation::NONE)
+ {
+ *activation_min = std::numeric_limits<T>::lowest();
+ *activation_max = std::numeric_limits<T>::max();
+ }
+ else
+ {
+ throw std::runtime_error{"Unsupported activation type"};
+ }
+}
+
+inline ir::Shape calcBroadcastShape(const ir::Shape &lhs, const ir::Shape &rhs, bool &success)
+{
+ int lhs_rank = lhs.rank();
+ int rhs_rank = rhs.rank();
+
+ int out_rank = (lhs_rank > rhs_rank ? lhs_rank : rhs_rank);
+ ir::Shape out_shape(out_rank);
+
+ int lhs_idim = lhs_rank - 1;
+ int rhs_idim = rhs_rank - 1;
+ success = true;
+ for (int out_idim = out_rank - 1; out_idim >= 0; out_idim--)
+ {
+ if (lhs_idim == -1 && rhs_idim == -1)
+ {
+ // invalid result
+ success = false;
+ break;
+ }
+
+ if (lhs_idim == -1)
+ {
+ out_shape.dim(out_idim) = rhs.dim(rhs_idim);
+ rhs_idim--;
+ }
+ else if (rhs_idim == -1)
+ {
+ out_shape.dim(out_idim) = lhs.dim(lhs_idim);
+ lhs_idim--;
+ }
+ else
+ {
+ if (lhs.dim(lhs_idim) == rhs.dim(rhs_idim))
+ {
+ out_shape.dim(out_idim) = lhs.dim(lhs_idim);
+ lhs_idim--;
+ rhs_idim--;
+ }
+ else if (lhs.dim(lhs_idim) == 1)
+ {
+ out_shape.dim(out_idim) = rhs.dim(rhs_idim);
+ lhs_idim--;
+ rhs_idim--;
+ }
+ else if (rhs.dim(rhs_idim) == 1)
+ {
+ out_shape.dim(out_idim) = lhs.dim(lhs_idim);
+ lhs_idim--;
+ rhs_idim--;
+ }
+ else
+ {
+ // invalid result
+ success = false;
+ break;
+ }
+ }
+ }
+
+ if (lhs_idim != -1 || rhs_idim != -1)
+ {
+ // invalid result
+ success = false;
+ }
+ return out_shape;
+}
+
+inline nnfw::cker::PaddingType convertPaddingType(ir::PaddingType ir_padding_type)
+{
+ switch (ir_padding_type)
+ {
+ case ir::PaddingType::EXPLICIT:
+ return nnfw::cker::PaddingType::kNone;
+ case ir::PaddingType::SAME:
+ return nnfw::cker::PaddingType::kSame;
+ case ir::PaddingType::VALID:
+ return nnfw::cker::PaddingType::kValid;
+ default:
+ throw std::runtime_error("Wrong padding type.");
+ break;
+ }
+}
+
+} // namespace interp
+} // namespace onert
+
+#endif // __ONERT_INTERP_OPERATIONS_OPERATION_UTILS_H_
diff --git a/runtime/onert/core/src/interp/operations/Pad.cc b/runtime/onert/core/src/interp/operations/Pad.cc
new file mode 100644
index 000000000..c8dce698d
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/Pad.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/Pad.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/Pad.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace
+{
+
+void preparePad(ExecEnv *env, const ir::Operation &node)
+{
+ const auto input_index = node.getInputs().at(ir::operation::Pad::INPUT);
+ const auto output_index = node.getOutputs().at(0);
+
+ const auto input_tensor = env->tensorAt(input_index);
+
+ const auto output_info = env->graph().operands().at(output_index).info();
+
+ // Check shape and type lhs is same with rhs
+ // TODO Util function to compare TensorInfo
+ if (output_info.total_size() == 0)
+ {
+ throw std::runtime_error{"Interp(Pad): NYI unspecified output shape"};
+ }
+ else
+ {
+ env->allocateIfNeeded(output_index, output_info);
+ }
+
+ const auto output_tensor = env->tensorAt(output_index);
+ if (input_tensor->data_type() != output_tensor->data_type())
+ {
+ throw std::runtime_error{"Interp(Pad): Invalid output type"};
+ }
+}
+
+void invoke(const ITensor *input_tensor, const ITensor *pad_tensor, const ITensor *output_tensor)
+{
+ const auto input_buffer = input_tensor->bufferRO();
+ const auto pad_buffer = pad_tensor->bufferRO();
+ auto output_buffer = output_tensor->buffer();
+
+ int32_t pad_rank = pad_tensor->dimension(0);
+
+ const auto cker_input_shape = convertShape(input_tensor->tensorInfo().shape());
+ const auto cker_output_shape = convertShape(output_tensor->tensorInfo().shape());
+ const float *input_ptr = reinterpret_cast<const float *>(input_buffer);
+ const int32_t *pad_ptr = reinterpret_cast<const int32_t *>(pad_buffer);
+ float *output_ptr = reinterpret_cast<float *>(output_buffer);
+
+ nnfw::cker::Pad<float>(pad_ptr, pad_rank, cker_input_shape, input_ptr, cker_output_shape,
+ output_ptr, nullptr);
+}
+
+void invokePad(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto input_index = node.getInputs().at(ir::operation::Pad::INPUT);
+ const auto pad_index = node.getInputs().at(ir::operation::Pad::PAD);
+ const auto output_index = node.getOutputs().at(0);
+
+ const auto input_tensor = env->tensorAt(input_index);
+ const auto pad_tensor = env->tensorAt(pad_index);
+ const auto output_tensor = env->tensorAt(output_index);
+
+ const auto data_type = input_tensor->data_type();
+
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(input_tensor, pad_tensor, output_tensor);
+ }
+ else
+ {
+ throw std::runtime_error{"Interp(Pad): NYI - Unsupported data type"};
+ }
+}
+} // namespace
+
+OpKernel *getPad()
+{
+ static OpKernel kernel = {preparePad, invokePad};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/Pool2D.cc b/runtime/onert/core/src/interp/operations/Pool2D.cc
new file mode 100644
index 000000000..92f9d70b2
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/Pool2D.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/AveragePool.h>
+#include <cker/operation/MaxPool.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/Pool2D.h"
+#include "util/Utils.h"
+#include "util/ShapeInference.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace pool2d
+{
+
+void preparePool2D(ExecEnv *env, const ir::Operation &node)
+{
+ const auto &pool_node = nnfw::misc::polymorphic_downcast<const ir::operation::Pool2D &>(node);
+ const auto in_index = node.getInputs().at(pool_node.INPUT);
+ const auto out_index = node.getOutputs().at(0);
+
+ const auto in_tensor = env->tensorAt(in_index);
+ UNUSED_RELEASE(in_tensor);
+
+ assert(in_tensor->num_dimensions() == 4);
+
+ const auto output_info = env->graph().operands().at(out_index).info();
+ if (output_info.total_size() == 0)
+ {
+ // Handle unspecified output shape
+ const auto infered_output_shape =
+ shape_inference::inferPoolShape(in_tensor->tensorInfo().shape(), pool_node.param());
+ env->allocateIfNeeded(
+ out_index, ir::OperandInfo::createStaticInfo(infered_output_shape, output_info.typeInfo()));
+ }
+ else
+ {
+ env->allocateIfNeeded(out_index, output_info);
+ }
+
+ auto out_tensor = env->tensorAt(out_index);
+ UNUSED_RELEASE(out_tensor);
+
+ // Handle same ifm & ofm data type only
+ assert(in_tensor->data_type() == out_tensor->data_type());
+ assert(out_tensor->num_dimensions() == 4);
+}
+
+template <typename T>
+void invoke(const nnfw::cker::PoolParams &params, const nnfw::cker::Shape &in_shape,
+ const T *in_ptr, const nnfw::cker::Shape &out_shape, T *out_ptr,
+ ir::operation::Pool2D::PoolType op_type)
+{
+ switch (op_type)
+ {
+ case ir::operation::Pool2D::PoolType::AVG:
+ nnfw::cker::AveragePool<T>(params, in_shape, in_ptr, out_shape, out_ptr);
+ break;
+ case ir::operation::Pool2D::PoolType::MAX:
+ nnfw::cker::MaxPool<T>(params, in_shape, in_ptr, out_shape, out_ptr);
+ break;
+ default:
+ throw std::runtime_error{"Interp(Pool2D): NYI unsupported operation"};
+ break;
+ }
+}
+
+void invokePool2DOps(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &pool_node = nnfw::misc::polymorphic_downcast<const ir::operation::Pool2D &>(node);
+
+ const auto in_index = node.getInputs().at(0);
+ const auto out_index = node.getOutputs().at(0);
+
+ // Check lhs shape is same with rhs (with broadcast)
+ const auto in_tensor = env->tensorAt(in_index);
+ const auto out_tensor = env->tensorAt(out_index);
+
+ // TODO support NCHW frontend
+ const auto ifm_shape = in_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC);
+ const auto ofm_shape = out_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC);
+ const auto param = pool_node.param();
+ const auto padding =
+ ir::calculatePadding(param.padding, ifm_shape, ofm_shape, param.stride, param.kw, param.kh);
+ // Calculate
+ nnfw::cker::PoolParams cker_param;
+ cker_param.filter_width = param.kw;
+ cker_param.filter_height = param.kh;
+ cker_param.padding_values.width = padding.left;
+ cker_param.padding_values.height = padding.top;
+ cker_param.stride_width = param.stride.horizontal;
+ cker_param.stride_height = param.stride.vertical;
+
+ const auto data_type = in_tensor->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ calculateActivationRange(param.activation, &cker_param.float_activation_min,
+ &cker_param.float_activation_max);
+
+ const auto in_shape = convertShape(in_tensor->tensorInfo().shape());
+ const auto out_shape = convertShape(out_tensor->tensorInfo().shape());
+ const float *in_ptr = reinterpret_cast<const float *>(in_tensor->bufferRO());
+ float *out_ptr = reinterpret_cast<float *>(out_tensor->buffer());
+ // Now, invoke() supports only Pool2D in float
+ invoke<float>(cker_param, in_shape, in_ptr, out_shape, out_ptr, param.op_type);
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Support float only"};
+ }
+}
+} // namespace pool2d
+
+OpKernel *getPool2D()
+{
+ static OpKernel kernel = {pool2d::preparePool2D, pool2d::invokePool2DOps};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/Reshape.cc b/runtime/onert/core/src/interp/operations/Reshape.cc
new file mode 100644
index 000000000..3a118456b
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/Reshape.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "interp/Registration.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace
+{
+
+void prepare(ExecEnv *env, const ir::Operation &node)
+{
+ const auto in_index = node.getInputs().at(0);
+ const auto out_index = node.getOutputs().at(0);
+
+ // Unspecified shape is not supported in operation node spec now
+ const auto output_info = env->graph().operands().at(out_index).info();
+ env->allocateAndShareIfNeeded(out_index, output_info, in_index);
+
+ assert(output_info.total_size() == env->graph().operands().at(in_index).info().total_size());
+}
+
+void invoke(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto in_index = node.getInputs().at(0);
+ const auto out_index = node.getOutputs().at(0);
+
+ if (env->tensorAt(in_index)->bufferRO() == env->tensorAt(out_index)->bufferRO())
+ {
+ // Same data
+ return;
+ }
+
+ const auto output_info = env->graph().operands().at(out_index).info();
+ memcpy(env->tensorAt(out_index)->buffer(), env->tensorAt(in_index)->bufferRO(),
+ output_info.total_size());
+}
+
+} // namespace
+
+OpKernel *getReshape()
+{
+ static OpKernel kernel = {prepare, invoke};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/Softmax.cc b/runtime/onert/core/src/interp/operations/Softmax.cc
new file mode 100644
index 000000000..d30f78deb
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/Softmax.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/SoftMax.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/Softmax.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace
+{
+
+void prepareSoftMax(ExecEnv *env, const ir::Operation &node)
+{
+ const auto in_index = node.getInputs().at(0);
+ const auto out_index = node.getOutputs().at(0);
+
+ const auto in_tensor = env->tensorAt(in_index);
+ UNUSED_RELEASE(in_tensor);
+
+ assert((in_tensor->num_dimensions() == 4) || (in_tensor->num_dimensions() == 2));
+
+ // Output shape should be same with input
+ // Output type is pre-defined in model
+ const auto output_shape = env->graph().operands().at(in_index).info().shape();
+ const auto output_type = env->graph().operands().at(out_index).info().typeInfo();
+
+ const auto output_info = ir::OperandInfo::createStaticInfo(output_shape, output_type);
+ env->allocateIfNeeded(out_index, output_info);
+
+ auto out_tensor = env->tensorAt(out_index);
+ UNUSED_RELEASE(out_tensor);
+
+ // Check output shape is same with input
+ assert(out_tensor->num_dimensions() == out_tensor->num_dimensions());
+ for (uint32_t i = 0; i < in_tensor->num_dimensions(); i++)
+ {
+ assert(in_tensor->dimension(i) == out_tensor->dimension(i));
+ }
+}
+
+void invoke(const ITensor *in_tensor, const ITensor *out_tensor,
+ const ir::operation::Softmax::Param &param)
+{
+ const float *in_ptr = reinterpret_cast<const float *>(in_tensor->bufferRO());
+ float *out_ptr = reinterpret_cast<float *>(out_tensor->buffer());
+
+ float beta = param.beta;
+
+ if (in_tensor->num_dimensions() == 2)
+ {
+ uint32_t batch_size = in_tensor->dimension(0);
+ uint32_t input_size = in_tensor->dimension(1);
+
+ nnfw::cker::Softmax(in_ptr, input_size, batch_size, beta, out_ptr);
+ }
+ else if (in_tensor->num_dimensions() == 4)
+ {
+ const auto in_shape = convertShape(in_tensor->tensorInfo().shape());
+ const auto out_shape = convertShape(out_tensor->tensorInfo().shape());
+
+ nnfw::cker::SoftmaxParams cker_param;
+ cker_param.beta = beta;
+
+ nnfw::cker::Softmax(cker_param, in_shape, in_ptr, out_shape, out_ptr);
+ }
+ else
+ {
+ throw std::runtime_error{"Unsuported input dimension: support 2D or 4D"};
+ }
+}
+
+void invokeSoftMax(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &softmax_node = nnfw::misc::polymorphic_downcast<const ir::operation::Softmax &>(node);
+
+ const auto in_index = node.getInputs().at(0);
+ const auto out_index = node.getOutputs().at(0);
+
+ const auto in_tensor = env->tensorAt(in_index);
+ const auto out_tensor = env->tensorAt(out_index);
+
+ const auto in_data_type = in_tensor->data_type();
+ const auto out_data_type = out_tensor->data_type();
+ if ((in_data_type == ir::DataType::FLOAT32) && (out_data_type == ir::DataType::FLOAT32))
+ {
+ invoke(in_tensor, out_tensor, softmax_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Support float32 only"};
+ }
+}
+
+} // namespace
+
+OpKernel *getSoftmax()
+{
+ static OpKernel kernel = {prepareSoftMax, invokeSoftMax};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/interp/operations/TransposeConv.cc b/runtime/onert/core/src/interp/operations/TransposeConv.cc
new file mode 100644
index 000000000..cc2ced26b
--- /dev/null
+++ b/runtime/onert/core/src/interp/operations/TransposeConv.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/TransposeConv.h>
+#include <misc/polymorphic_downcast.h>
+
+#include "OperationUtil.h"
+
+#include "interp/Registration.h"
+#include "ir/operation/TransposeConv.h"
+
+namespace onert
+{
+namespace interp
+{
+namespace
+{
+
+void prepareTransposeConv(ExecEnv *env, const ir::Operation &node)
+{
+ const auto ifm_index = node.getInputs().at(ir::operation::TransposeConv::INPUT);
+ const auto ker_index = node.getInputs().at(ir::operation::TransposeConv::KERNEL);
+ const auto ofm_shape_index = node.getInputs().at(ir::operation::TransposeConv::OUTPUT_SHAPE);
+ const auto ofm_index = node.getOutputs().at(0);
+
+ const auto ifm_tensor = env->tensorAt(ifm_index);
+ const auto ker_tensor = env->tensorAt(ker_index);
+ const auto ofm_shape_tensor = env->tensorAt(ofm_shape_index);
+
+ assert(ifm_tensor->num_dimensions() == 4);
+ assert(ker_tensor->num_dimensions() == 4);
+ assert(ofm_shape_tensor->num_dimensions() == 1);
+
+ UNUSED_RELEASE(ifm_tensor);
+ UNUSED_RELEASE(ker_tensor);
+ UNUSED_RELEASE(ofm_shape_tensor);
+
+ const auto output_info = env->graph().operands().at(ofm_index).info();
+ if (output_info.total_size() == 0)
+ {
+ // TODO: Handle unspecified output shape
+ throw std::runtime_error{"Interp(TConv): NYI unspecified output shape"};
+ }
+ else
+ {
+ env->allocateIfNeeded(ofm_index, output_info);
+ }
+
+ auto ofm_tensor = env->tensorAt(ofm_index);
+ UNUSED_RELEASE(ofm_tensor);
+
+ // Handle same ifm & ofm data type only
+ if (ifm_tensor->data_type() != ofm_tensor->data_type())
+ {
+ throw std::runtime_error{"Interp(TConv): Different I/O data dype"};
+ }
+
+ if (ofm_tensor->num_dimensions() != 4)
+ {
+ throw std::runtime_error{"Interp(TConv): Invalid output rank"};
+ }
+}
+
+void invoke(const ITensor *ifm_tensor, const ITensor *ker_tensor, const ITensor *ofm_tensor,
+ const ir::operation::TransposeConv::Param &param)
+{
+ const auto ifm_shape = ifm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC);
+ const auto ofm_shape = ofm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC);
+ // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
+ const auto ker_shape = ker_tensor->tensorInfo().shape();
+ const auto ker_height = ker_shape.dim(1);
+ const auto ker_width = ker_shape.dim(2);
+ const auto padding = ir::calculatePadding(param.padding, ofm_shape, ifm_shape, param.stride,
+ ker_width, ker_height);
+
+ nnfw::cker::TransposeConvParams cker_param;
+ cker_param.padding_values.width = padding.left;
+ cker_param.padding_values.height = padding.top;
+ cker_param.stride_width = param.stride.horizontal;
+ cker_param.stride_height = param.stride.vertical;
+ cker_param.dilation_width_factor = 1;
+ cker_param.dilation_height_factor = 1;
+
+ const auto cker_ifm_shape = convertShape(ifm_tensor->tensorInfo().shape());
+ const auto cker_ker_shape = convertShape(ker_tensor->tensorInfo().shape());
+ const auto cker_ofm_shape = convertShape(ofm_tensor->tensorInfo().shape());
+ const float *ifm_ptr = reinterpret_cast<const float *>(ifm_tensor->bufferRO());
+ const float *ker_ptr = reinterpret_cast<const float *>(ker_tensor->bufferRO());
+ float *ofm_ptr = reinterpret_cast<float *>(ofm_tensor->buffer());
+
+ nnfw::cker::TransposeConv(cker_param, cker_ifm_shape, ifm_ptr, cker_ker_shape, ker_ptr,
+ cker_ofm_shape, ofm_ptr);
+}
+
+void invokeTransposeConv(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &tconv_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::TransposeConv &>(node);
+
+ const auto ifm_index = node.getInputs().at(ir::operation::TransposeConv::INPUT);
+ const auto ker_index = node.getInputs().at(ir::operation::TransposeConv::KERNEL);
+ const auto ofm_index = node.getOutputs().at(0);
+
+ const auto ifm_tensor = env->tensorAt(ifm_index);
+ const auto ker_tensor = env->tensorAt(ker_index);
+ const auto ofm_tensor = env->tensorAt(ofm_index);
+
+ const auto data_type = ifm_tensor->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(ifm_tensor, ker_tensor, ofm_tensor, tconv_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"Interp(TConv): Support float32 only"};
+ }
+}
+
+} // namespace
+
+OpKernel *getTransposeConv()
+{
+ static OpKernel kernel = {prepareTransposeConv, invokeTransposeConv};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/Coordinates.cc b/runtime/onert/core/src/ir/Coordinates.cc
new file mode 100644
index 000000000..a02a56567
--- /dev/null
+++ b/runtime/onert/core/src/ir/Coordinates.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Coordinates.h"
+
+#include <cassert>
+
+namespace onert
+{
+namespace ir
+{
+
+Coordinates convertCoordinates(const Coordinates &from_coordinates, Layout from_layout,
+ Layout to_layout)
+{
+ assert(from_coordinates.size() == 4);
+ Coordinates to{from_coordinates};
+ if (from_layout == Layout::NHWC && to_layout == Layout::NCHW)
+ {
+ to.set(0, from_coordinates[0]);
+ to.set(1, from_coordinates[3]);
+ to.set(2, from_coordinates[1]);
+ to.set(3, from_coordinates[2]);
+ }
+ else if (from_layout == Layout::NCHW && to_layout == Layout::NHWC)
+ {
+ to.set(0, from_coordinates[0]);
+ to.set(1, from_coordinates[2]);
+ to.set(2, from_coordinates[3]);
+ to.set(3, from_coordinates[1]);
+ }
+
+ return to;
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/DataType.cc b/runtime/onert/core/src/ir/DataType.cc
new file mode 100644
index 000000000..9eedcd21a
--- /dev/null
+++ b/runtime/onert/core/src/ir/DataType.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/DataType.h"
+
+#include <stdexcept>
+#include <Half.h>
+
+using float16 = Half;
+
+namespace onert
+{
+namespace ir
+{
+
+size_t sizeOfDataType(DataType data_type)
+{
+ switch (data_type)
+ {
+ case DataType::FLOAT32:
+ return sizeof(float);
+ case DataType::INT32:
+ return sizeof(int32_t);
+ case DataType::UINT32:
+ return sizeof(uint32_t);
+ case DataType::BOOL8:
+ case DataType::QUANT_UINT8_ASYMM:
+ case DataType::UINT8:
+ return sizeof(uint8_t);
+ case DataType::QUANT_INT8_SYMM:
+ case DataType::QUANT_INT8_ASYMM:
+ return sizeof(int8_t);
+ case DataType::FLOAT16:
+ return sizeof(float16);
+ case DataType::INT64:
+ return sizeof(int64_t);
+ case DataType::QUANT_INT16_ASYMM:
+ return sizeof(int16_t);
+ default:
+ throw std::runtime_error{"Unsupported type size"};
+ }
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/Graph.cc b/runtime/onert/core/src/ir/Graph.cc
new file mode 100644
index 000000000..1b8300f40
--- /dev/null
+++ b/runtime/onert/core/src/ir/Graph.cc
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Graph.h"
+
+#include "OperationValidator.h"
+
+#include <algorithm>
+#include <bitset>
+#include <sstream>
+
+#include "util/logging.h"
+#include "verifier/Verifier.h"
+#include "ir/operation/LowerInfo.h"
+#include "ir/operand/LowerInfo.h"
+#include "ir/operand/PermuteFactor.h"
+#include "ir/OperandIndexMap.h"
+#include "ir/GraphIterator.h"
+#include "backend/IConfig.h"
+
+namespace onert
+{
+namespace ir
+{
+
+Graph::Graph() = default;
+
+Graph::~Graph(void) = default;
+
+OperandIndex Graph::addOperand(const Shape &shape, const TypeInfo &type)
+{
+ return _operands.emplace(shape, type);
+}
+
+OperationIndex Graph::addOperation(std::unique_ptr<Operation> &&node)
+{
+ assert(isBuildingPhase());
+ return _operations.push(std::move(node));
+}
+
+void Graph::setOperandValue(const OperandIndex &ind, std::shared_ptr<Data> data)
+{
+ assert(isBuildingPhase());
+ assert(_operands.exist(ind));
+ _operands.at(ind).data(std::move(data));
+}
+
+void Graph::addInput(const OperandIndex &ind, const std::string &name)
+{
+ assert(isBuildingPhase());
+ if (!name.empty())
+ _name_to_input.emplace(name, IOIndex{_inputs.size()});
+ _inputs.append(ind);
+}
+
+void Graph::addOutput(const OperandIndex &ind, const std::string &name)
+{
+ assert(isBuildingPhase());
+ if (!name.empty())
+ _name_to_output.emplace(name, IOIndex{_outputs.size()});
+ _outputs.append(ind);
+}
+
+IOIndex Graph::getInputIndex(const std::string &name) const
+{
+ auto itr = _name_to_input.find(name);
+ return (itr == _name_to_input.end()) ? IOIndex{} : itr->second;
+}
+
+IOIndex Graph::getOutputIndex(const std::string &name) const
+{
+ auto itr = _name_to_output.find(name);
+ return (itr == _name_to_output.end()) ? IOIndex{} : itr->second;
+}
+
+void Graph::finishBuilding(void)
+{
+ assert(isBuildingPhase());
+ _phase = Phase::MODEL;
+
+ initializeUseDef();
+ sweepGarbageOperands();
+
+ // Call graph verifications for the MODEL phase
+ {
+ // Except for edge consistency, the user might have been given a bad model
+ // so here it throws an execption rather than assertion.
+ if (!verifier::InputOutputChecker().verify(*this))
+ throw std::runtime_error{"One of model input and output operands does not exist."};
+ if (!verifier::DAGChecker().verify(*this))
+ throw std::runtime_error{"The graph is cyclic."};
+ assert(verifier::EdgeConsistencyChecker().verify(*this));
+ }
+
+ // Check shape independent operation feature
+ // - Operand type
+ // - Shape independent parameter
+ OperationValidator{*this}();
+}
+
+void Graph::initializeUseDef()
+{
+ operations().iterate([&](const OperationIndex &index, const Operation &node) -> void {
+ auto outputs = node.getOutputs();
+ for (auto output : outputs | ir::Remove::UNDEFINED)
+ {
+ operands().at(output).setDef(index);
+ }
+
+ for (auto input : node.getInputs() | ir::Remove::UNDEFINED)
+ {
+ operands().at(input).insertUse(index);
+ }
+ });
+}
+
+void Graph::sweepGarbageOperands()
+{
+ // Remove operands that are not used by any operations, except Graph inputs/outputs
+ ir::OperandIndexMap<bool> visited;
+
+ operations().iterate([&](const OperationIndex &, const Operation &node) {
+ for (auto ind : node.getInputs() + node.getOutputs())
+ {
+ visited[ind] = true;
+ }
+ });
+
+ // Graph's inputs/outputs are always reachable
+ for (auto ind : getInputs() + getOutputs())
+ {
+ visited[ind] = true;
+ }
+
+ operands().iterate([&](const OperandIndex &ind, const Operand &) {
+ if (!visited[ind])
+ {
+ VERBOSE(Graph::sweepGarbageOperands) << "Sweep garbage operand " << ind.value() << std::endl;
+ operands().remove(ind);
+ }
+ });
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/GraphIterator.cc b/runtime/onert/core/src/ir/GraphIterator.cc
new file mode 100644
index 000000000..ac67771c4
--- /dev/null
+++ b/runtime/onert/core/src/ir/GraphIterator.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GraphIterator.h"
+
+#include "ir/OperationIndexMap.h"
+#include "compiler/LoweredGraph.h"
+
+namespace onert
+{
+namespace ir
+{
+
+//
+// Graph::DefaultIterator
+//
+
+template <bool is_const>
+void DefaultIterator<is_const>::iterate(GraphRef graph, const IterFn &fn) const
+{
+ graph.operations().iterate(
+ [&](const OperationIndex &index, NodeRef node) -> void { fn(index, node); });
+}
+
+//
+// Graph::PostDfsIterator
+//
+
+template <bool is_const>
+void PostDfsIterator<is_const>::iterate(GraphRef graph, const IterFn &fn) const
+{
+ assert(!graph.isBuildingPhase()); // Restrict iteration condition
+
+ OperationIndexMap<bool> visited;
+ graph.operations().iterate([&](const OperationIndex &index, NodeRef) { visited[index] = false; });
+
+ std::function<void(const OperationIndex &, NodeRef)> dfs_recursive =
+ [&](const OperationIndex &index, NodeRef node) -> void {
+ if (visited[index])
+ return;
+ visited[index] = true;
+
+ for (const auto output : node.getOutputs() | Remove::DUPLICATED | Remove::UNDEFINED)
+ {
+ const auto &operand = graph.operands().at(output);
+ for (const auto &use : operand.getUses())
+ {
+ dfs_recursive(use, graph.operations().at(use));
+ }
+ }
+
+ fn(index, node);
+ };
+
+ graph.operations().iterate(dfs_recursive);
+
+ // All of the operations(nodes) must have been visited.
+ assert(std::all_of(visited.begin(), visited.end(),
+ [](const std::pair<const OperationIndex, bool> &v) { return v.second; }));
+}
+
+template <bool is_const>
+void PostDfsIterator<is_const>::iterateOpSeqs(LoweredGraphRef lowered_graph,
+ const OpSeqIterFn &fn) const
+{
+ std::unordered_map<OpSequenceIndex, bool> visited;
+ lowered_graph.op_seqs().iterate(
+ [&](const OpSequenceIndex &index, OpSequenceRef) { visited[index] = false; });
+
+ std::function<void(const OpSequenceIndex &, OpSequenceRef)> dfs_recursive =
+ [&](const OpSequenceIndex &index, OpSequenceRef op_seq) -> void {
+ if (visited[index])
+ return;
+ visited[index] = true;
+
+ for (const auto output : op_seq.getOutputs() | Remove::DUPLICATED | Remove::UNDEFINED)
+ {
+ const auto &operand = lowered_graph.graph().operands().at(output);
+ for (const auto &use : operand.getUses())
+ {
+ const auto use_op_seq_index = lowered_graph.op_seqs().getOperation(use);
+ dfs_recursive(use_op_seq_index, lowered_graph.op_seqs().at(use_op_seq_index));
+ }
+ }
+
+ fn(index, op_seq);
+ };
+
+ lowered_graph.op_seqs().iterate(dfs_recursive);
+
+ // All of the operations(nodes) must have been visited.
+ assert(std::all_of(visited.begin(), visited.end(),
+ [](const std::pair<const OpSequenceIndex, bool> &v) { return v.second; }));
+}
+
+// Explicit instantiations to have implementation in the source file.
+// NOTE If these instatiations were in the top of this file, `iterate` is compiled and saved in
+// `GraphIterator.cc.o` but `iterateOpSeqs`. This happens only when cross-building for Android.
+// (Maybe a bug of NDK toolchain(clang)?)
+
+template class DefaultIterator<true>;
+template class DefaultIterator<false>;
+
+template class PostDfsIterator<true>;
+template class PostDfsIterator<false>;
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/GraphIterator.h b/runtime/onert/core/src/ir/GraphIterator.h
new file mode 100644
index 000000000..b54314e0e
--- /dev/null
+++ b/runtime/onert/core/src/ir/GraphIterator.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_GRAPH_ITERATOR_H__
+#define __ONERT_IR_GRAPH_ITERATOR_H__
+
+#include <type_traits>
+
+#include "ir/Index.h"
+
+namespace onert
+{
+namespace compiler
+{
+class LoweredGraph;
+} // namespace compiler
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+
+class Graph;
+class Operation;
+class OpSequence;
+
+template <bool is_const> class Iterator
+{
+public:
+ using GraphRef = typename std::conditional<is_const, const Graph &, Graph &>::type;
+ using IndexRef = const OperationIndex &;
+ using NodeRef = typename std::conditional<is_const, const Operation &, Operation &>::type;
+ using IterFn = std::function<void(IndexRef, NodeRef)>;
+
+public:
+ virtual ~Iterator() = default;
+ virtual void iterate(GraphRef graph, const IterFn &fn) const = 0;
+};
+
+template <bool is_const = false> class DefaultIterator final : public Iterator<is_const>
+{
+public:
+ using GraphRef = typename Iterator<is_const>::GraphRef;
+ using IndexRef = typename Iterator<is_const>::IndexRef;
+ using NodeRef = typename Iterator<is_const>::NodeRef;
+ using IterFn = typename Iterator<is_const>::IterFn;
+
+public:
+ void iterate(GraphRef graph, const IterFn &fn) const;
+};
+using DefaultConstIterator = DefaultIterator<true>;
+
+template <bool is_const = false> class PostDfsIterator final : public Iterator<is_const>
+{
+public:
+ using GraphRef = typename Iterator<is_const>::GraphRef;
+ using IndexRef = typename Iterator<is_const>::IndexRef;
+ using NodeRef = typename Iterator<is_const>::NodeRef;
+ using IterFn = typename Iterator<is_const>::IterFn;
+ using LoweredGraphRef =
+ typename std::conditional<is_const, const typename compiler::LoweredGraph &,
+ typename compiler::LoweredGraph &>::type;
+ using OpSequenceRef = typename std::conditional<is_const, const OpSequence &, OpSequence &>::type;
+ using OpSeqIndexRef = const OpSequenceIndex &;
+ using OpSeqIterFn = std::function<void(OpSeqIndexRef, OpSequenceRef)>;
+
+public:
+ void iterate(GraphRef graph, const IterFn &fn) const;
+ void iterateOpSeqs(LoweredGraphRef lowered_graph, const OpSeqIterFn &f) const;
+};
+using PostDfsConstIterator = PostDfsIterator<true>;
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_GRAPH_ITERATOR_H__
diff --git a/runtime/onert/core/src/ir/LayoutSet.cc b/runtime/onert/core/src/ir/LayoutSet.cc
new file mode 100644
index 000000000..bd3f438ad
--- /dev/null
+++ b/runtime/onert/core/src/ir/LayoutSet.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayoutSet.h"
+
+namespace onert
+{
+namespace ir
+{
+
+LayoutSet::LayoutSet(std::initializer_list<Layout> layouts)
+{
+ for (auto layout : layouts)
+ {
+ _set.insert(layout);
+ }
+}
+
+LayoutSet LayoutSet::operator|(const LayoutSet &other) const
+{
+ auto ret = *this;
+ for (auto layout : other)
+ {
+ ret.add(layout);
+ }
+ return ret;
+}
+
+LayoutSet LayoutSet::operator&(const LayoutSet &other) const
+{
+ LayoutSet ret;
+ for (auto layout : other)
+ {
+ if (contains(layout))
+ {
+ ret.add(layout);
+ }
+ }
+ return ret;
+}
+
+LayoutSet LayoutSet::operator-(const LayoutSet &other) const
+{
+ auto ret = *this;
+ for (auto layout : other)
+ {
+ ret.remove(layout);
+ }
+ return ret;
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/LayoutSet.h b/runtime/onert/core/src/ir/LayoutSet.h
new file mode 100644
index 000000000..6ce4e38c6
--- /dev/null
+++ b/runtime/onert/core/src/ir/LayoutSet.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_LAYOUT_SET_H__
+#define __ONERT_IR_LAYOUT_SET_H__
+
+#include <initializer_list>
+#include <unordered_set>
+
+#include "ir/Layout.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class LayoutSet
+{
+public:
+ LayoutSet() = default;
+ LayoutSet(std::initializer_list<Layout> layouts);
+
+public:
+ void add(const Layout &layout) { _set.insert(layout); }
+ void remove(const Layout &layout) { _set.erase(layout); }
+ uint32_t size() const { return static_cast<uint32_t>(_set.size()); }
+ bool contains(const Layout &layout) const { return _set.find(layout) != _set.end(); }
+
+public:
+ LayoutSet operator|(const LayoutSet &other) const; // Union
+ LayoutSet operator&(const LayoutSet &other) const; // Intersect
+ LayoutSet operator-(const LayoutSet &other) const; // Minus
+
+public:
+ std::unordered_set<Layout>::const_iterator begin() const { return _set.begin(); }
+ std::unordered_set<Layout>::const_iterator end() const { return _set.end(); }
+
+private:
+ std::unordered_set<Layout> _set;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_LAYOUT_SET_H__
diff --git a/runtime/onert/core/src/ir/OpCode.cc b/runtime/onert/core/src/ir/OpCode.cc
new file mode 100644
index 000000000..ef3411f6d
--- /dev/null
+++ b/runtime/onert/core/src/ir/OpCode.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/OpCode.h"
+
+#include <unordered_map>
+
+namespace onert
+{
+namespace ir
+{
+
+const char *toString(OpCode opcode)
+{
+ static const std::unordered_map<OpCode, const char *> map{{OpCode::Invalid, "Invalid"},
+#define OP(Name) {OpCode::Name, #Name},
+#include "ir/Operations.lst"
+#undef OP
+ {OpCode::COUNT, "COUNT"}};
+ return map.at(opcode);
+}
+
+OpCode toOpCode(const std::string str)
+{
+ static const std::unordered_map<std::string, OpCode> map{
+#define OP(Name) {#Name, OpCode::Name},
+#include "ir/Operations.lst"
+#undef OP
+ };
+ return map.at(str);
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/OpSequence.cc b/runtime/onert/core/src/ir/OpSequence.cc
new file mode 100644
index 000000000..e2b989d8c
--- /dev/null
+++ b/runtime/onert/core/src/ir/OpSequence.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/OpSequence.h"
+
+#include "ir/Operations.h"
+#include "ir/OperationVisitor.h"
+#include <sstream>
+
+namespace
+{
+
+std::string getStrFromIndice(const onert::ir::OperandIndexSequence &indice)
+{
+ std::string str;
+ for (const auto &ind : indice)
+ {
+ str += std::to_string(ind.value());
+ str.push_back(',');
+ }
+ if (str.back() == ',')
+ str.pop_back();
+
+ return str;
+}
+}
+
+namespace onert
+{
+namespace ir
+{
+
+OpSequence::OpSequence(Layout layout) : _layout{layout}, _has_dynamic_tensor{false}
+{
+ // DO NOTHING
+}
+
+void OpSequence::accept(OperationVisitor &v) const { v.visit(*this); }
+
+// TODO: Impl Dumper instead of this method
+std::string getStrFromOpSeq(const OpSequence &op_seq, const Operations &operations)
+{
+ // " OpSequence IN(0,1,2) -> { op0(0,1,2:3), op1(3:4), op2(4:5) } -> OUT(5)"
+ std::stringstream ss;
+ ss << " OpSequence IN(" << getStrFromIndice(op_seq.getInputs()) << ") -> {";
+ for (const auto &op_idx : op_seq)
+ {
+ ss << " " << op_idx.value() << "(" << operations.at(op_idx).name() << ":"
+ << getStrFromIndice(operations.at(op_idx).getInputs()) << ":"
+ << getStrFromIndice(operations.at(op_idx).getOutputs()) << ")";
+ }
+ ss << " } -> OUT(" << getStrFromIndice(op_seq.getOutputs()) << ")";
+ return ss.str();
+}
+
+void OpSequence::remove(const OperationIndex &index)
+{
+ assert(exist(index));
+ for (auto it = _operations.cbegin(); it != _operations.cend(); ++it)
+ {
+ if (*it == index)
+ {
+ _operations.erase(it);
+ break;
+ }
+ }
+}
+
+bool OpSequence::exist(const OperationIndex &index) const
+{
+ for (const auto &inner_op_idx : _operations)
+ {
+ if (inner_op_idx == index)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/OpSequences.cc b/runtime/onert/core/src/ir/OpSequences.cc
new file mode 100644
index 000000000..68884783e
--- /dev/null
+++ b/runtime/onert/core/src/ir/OpSequences.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/OpSequences.h"
+#include "util/logging.h"
+#include <memory>
+
+#include <cassert>
+#include <string>
+
+namespace onert
+{
+namespace ir
+{
+
+OpSequenceIndex OpSequences::emplace(const OperationIndex &index, Layout layout)
+{
+ std::unique_ptr<OpSequence> op_seq = std::make_unique<OpSequence>(layout);
+ op_seq->appendOperation(index);
+ const OpSequenceIndex &seq_index = push(std::move(op_seq));
+ cacheSequenceIndex(seq_index, index);
+ return seq_index;
+}
+
+OpSequenceIndex OpSequences::emplace(std::unique_ptr<OpSequence> &&op_seq)
+{
+ auto &operations = op_seq->operations();
+ const OpSequenceIndex &seq_index = push(std::move(op_seq));
+ for (const auto &op_idx : operations)
+ {
+ cacheSequenceIndex(seq_index, op_idx);
+ }
+ return seq_index;
+}
+
+void OpSequences::cacheSequenceIndex(const OpSequenceIndex &seq_index,
+ const OperationIndex &op_index) const
+{
+ _seq_indexes.emplace(op_index, seq_index);
+}
+
+OpSequenceIndex *OpSequences::findSequenceIndex(const OperationIndex &operation_index) const
+{
+ // If opration_index is cached, return sequence_index from cache
+ if (_seq_indexes.count(operation_index))
+ {
+ auto &op_seq_index = _seq_indexes.at(operation_index);
+ if (_objects.count(op_seq_index) && _objects.at(op_seq_index)->exist(operation_index))
+ {
+ return &op_seq_index;
+ }
+ else
+ {
+ _seq_indexes.erase(operation_index);
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
+bool OpSequences::containsOperation(const OperationIndex &operation_index) const
+{
+ return findOperation(operation_index).valid();
+}
+
+OpSequenceIndex OpSequences::getOperation(const OperationIndex &operation_index) const
+{
+ OpSequenceIndex ret = findOperation(operation_index);
+ assert(ret.valid());
+ return ret;
+}
+
+void OpSequences::removeFromOpSequence(const OperationIndex &operation_index)
+{
+ const auto op_seq_index = findOperation(operation_index);
+ auto &op_seq = at(op_seq_index);
+ _seq_indexes.erase(operation_index);
+ op_seq.remove(operation_index);
+ if (op_seq.size() == 0)
+ {
+ remove(op_seq_index);
+ }
+}
+
+OpSequenceIndex OpSequences::findOperation(const OperationIndex &operation_index) const
+{
+ if (OpSequenceIndex *op_seq_index = findSequenceIndex(operation_index))
+ return *op_seq_index;
+
+ for (auto &e : _objects)
+ {
+ OpSequence &object = *e.second;
+ auto it = find(object.operations().begin(), object.operations().end(), operation_index);
+ if (it != object.operations().end())
+ {
+ cacheSequenceIndex(e.first, operation_index);
+ return e.first;
+ }
+ }
+ throw std::runtime_error("Operation not found");
+}
+
+void dumpOpSequences(const OpSequences &op_seqs, const Operations &operations)
+{
+ op_seqs.iterate([&](const OpSequenceIndex &idx, const OpSequence &op_seq) {
+ VERBOSE(OpSequences) << idx.value() << "] " << getStrFromOpSeq(op_seq, operations) << std::endl;
+ });
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/Operand.cc b/runtime/onert/core/src/ir/Operand.cc
new file mode 100644
index 000000000..e29c7a6ec
--- /dev/null
+++ b/runtime/onert/core/src/ir/Operand.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Operand.h"
+
+namespace onert
+{
+namespace ir
+{
+
+size_t Operand::operandSize(void) const
+{
+ const uint32_t ranks = shape().rank();
+ int32_t elements = 1;
+
+ for (uint32_t rank = 0; rank < ranks; rank++)
+ {
+ elements *= shape().dim(rank);
+ }
+
+ DataType type = typeInfo().type();
+ size_t element_size = sizeOfDataType(type);
+
+ // Value of type is matched with OperandCode enum in NeuralNetworks.h
+ return element_size * elements;
+}
+
+void Operand::insertUse(const OperationIndex &idx) { _uses.insert(idx); }
+
+void Operand::removeUse(const OperationIndex &idx) { _uses.remove(idx); }
+
+void Operand::setDef(const OperationIndex &idx) { _def = idx; }
+
+void Operand::unsetDef() { _def = OperationIndex{}; }
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/OperandIndexSequence.cc b/runtime/onert/core/src/ir/OperandIndexSequence.cc
new file mode 100644
index 000000000..73f928280
--- /dev/null
+++ b/runtime/onert/core/src/ir/OperandIndexSequence.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/OperandIndexSequence.h"
+
+#include <algorithm>
+#include <sstream>
+
+namespace onert
+{
+namespace ir
+{
+
+OperandIndexSequence::OperandIndexSequence(std::initializer_list<OperandIndex> list) : _vec(list)
+{
+ // DO NOTHING
+}
+
+OperandIndexSequence::OperandIndexSequence(std::initializer_list<int32_t> list)
+{
+ for (auto val : list)
+ {
+ _vec.emplace_back(static_cast<uint32_t>(val));
+ }
+}
+
+OperandIndexSequence::OperandIndexSequence(std::initializer_list<uint32_t> list)
+{
+ for (auto val : list)
+ {
+ _vec.emplace_back(val);
+ }
+}
+
+bool OperandIndexSequence::contains(const OperandIndex &index) const
+{
+ return std::find(_vec.begin(), _vec.end(), index) != _vec.end();
+}
+
+void OperandIndexSequence::replace(const OperandIndex &from, const OperandIndex &to)
+{
+ std::replace(_vec.begin(), _vec.end(), from, to);
+}
+
+OperandIndexSequence OperandIndexSequence::operator+(const OperandIndexSequence &other) const
+{
+ OperandIndexSequence ret = *this;
+ ret.append(other);
+ return ret;
+}
+
+std::ostream &operator<<(std::ostream &o, const OperandIndexSequence &op_seq)
+{
+ std::string delimeter;
+ for (const auto &ind : op_seq._vec)
+ {
+ o << delimeter << ind;
+ delimeter = ',';
+ }
+ return o;
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/Operands.cc b/runtime/onert/core/src/ir/Operands.cc
new file mode 100644
index 000000000..ab32e478a
--- /dev/null
+++ b/runtime/onert/core/src/ir/Operands.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Operands.h"
+
+#include <memory>
+#include "util/logging.h"
+
+namespace onert
+{
+namespace ir
+{
+
+Operands::Operands(const Operands &obj)
+{
+ obj.iterate([&](const OperandIndex &index, const Operand &operand) {
+ _objects.emplace(index, std::make_unique<Operand>(operand));
+ });
+ _index_count = obj._index_count;
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/Operation.cc b/runtime/onert/core/src/ir/Operation.cc
new file mode 100644
index 000000000..4af878541
--- /dev/null
+++ b/runtime/onert/core/src/ir/Operation.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Operation.h"
+
+#include <cassert>
+
+namespace onert
+{
+namespace ir
+{
+
+Operation::Operation(OperandConstraint input_constr, const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, OperandConstraint output_constr)
+ : _input_constr{input_constr}, _output_constr{output_constr}
+{
+ setInputs(inputs);
+ setOutputs(outputs);
+}
+
+Operation::Operation(OperandConstraint input_constr, OperandConstraint output_constr)
+ : _input_constr{input_constr}, _output_constr{output_constr}
+{
+}
+
+Operation::~Operation() = default;
+
+void Operation::setInputs(const OperandIndexSequence &indexes)
+{
+ if (!_input_constr.check(indexes.size()))
+ throw std::runtime_error{"Invalid number of input tensors for this operation."};
+ _inputs = indexes;
+}
+
+void Operation::setOutputs(const OperandIndexSequence &indexes)
+{
+ if (!_output_constr.check(indexes.size()))
+ throw std::runtime_error{"Invalid number of output tensors for this operation."};
+ _outputs = indexes;
+}
+
+void Operation::replaceInputs(const OperandIndex &from, const OperandIndex &to)
+{
+ _inputs.replace(from, to);
+}
+
+void Operation::replaceOutputs(const OperandIndex &from, const OperandIndex &to)
+{
+ _outputs.replace(from, to);
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/OperationCloner.cc b/runtime/onert/core/src/ir/OperationCloner.cc
new file mode 100644
index 000000000..b4e60f0bc
--- /dev/null
+++ b/runtime/onert/core/src/ir/OperationCloner.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OperationCloner.h"
+
+#include <assert.h>
+
+namespace onert
+{
+namespace ir
+{
+
+#define OP(Name) \
+ void OperationCloner::visit(const operation::Name &o) \
+ { \
+ assert(!_return_op); \
+ _return_op = std::make_unique<operation::Name>(o); \
+ }
+#include "ir/Operations.lst"
+#undef OP
+
+std::unique_ptr<Operation> OperationCloner::releaseClone()
+{
+ assert(_return_op);
+ return std::move(_return_op);
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/OperationCloner.h b/runtime/onert/core/src/ir/OperationCloner.h
new file mode 100644
index 000000000..0e8cda2a0
--- /dev/null
+++ b/runtime/onert/core/src/ir/OperationCloner.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_CLONER_H__
+#define __ONERT_IR_OPERATION_CLONER_H__
+
+#include <memory>
+#include "ir/OperationVisitor.h"
+#include "ir/Operation.h"
+
+namespace onert
+{
+namespace ir
+{
+
+class OperationCloner : public OperationVisitor
+{
+public:
+#define OP(Name) void visit(const operation::Name &o) override;
+#include "ir/Operations.lst"
+#undef OP
+
+public:
+ std::unique_ptr<Operation> releaseClone();
+
+private:
+ std::unique_ptr<Operation> _return_op;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_CLONER_H__
diff --git a/runtime/onert/core/src/ir/OperationDumper.cc b/runtime/onert/core/src/ir/OperationDumper.cc
new file mode 100644
index 000000000..eecfe81cc
--- /dev/null
+++ b/runtime/onert/core/src/ir/OperationDumper.cc
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OperationDumper.h"
+
+#include <string>
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace ir
+{
+
+using namespace operation;
+
+namespace
+{
+void dumpUnaryInputOp(const Operation &node, const std::string &adding_input = "")
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(0) << ") " << adding_input
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void dumpBinaryInputOp(const Operation &node, const std::string &adding_input = "")
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(0) << ", " << node.getInputs().at(1)
+ << ") " << adding_input << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void dumpConvOp(const Operation &node, const std::string &padding_type)
+{
+ VERBOSE(LIR) << "* " << node.name() << "(" << padding_type << ")" << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(Conv2D::Input::INPUT) << ") Kernel("
+ << node.getInputs().at(Conv2D::Input::KERNEL) << ") Bias("
+ << node.getInputs().at(Conv2D::Input::BIAS) << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void dumpPackingOp(const Operation &node)
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ std::string inputs;
+ for (auto i : node.getInputs())
+ {
+ inputs += std::to_string(i.value()) + ",";
+ }
+ VERBOSE(LIR) << " - Inputs : Inputs(" << inputs << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+} // namespace
+
+OperationDumper::OperationDumper(const std::string &start_msg)
+{
+ VERBOSE(LIR) << start_msg << std::endl;
+}
+
+void OperationDumper::visit(const ArgMax &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const BatchToSpaceND &node)
+{
+ std::string block_size =
+ "BlockSize(" +
+ std::to_string(node.getInputs().at(BatchToSpaceND::Input::BLOCK_SIZE).value()) + ")";
+ dumpUnaryInputOp(node, block_size);
+}
+
+void OperationDumper::visit(const BCQFullyConnected &node)
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(BCQFullyConnected::Input::INPUT)
+ << ") WeightsBinary("
+ << node.getInputs().at(BCQFullyConnected::Input::WEIGHTS_BINARY)
+ << ") WeightsScales("
+ << node.getInputs().at(BCQFullyConnected::Input::WEIGHTS_SCALES)
+ << ") WeightsClusters("
+ << node.getInputs().at(BCQFullyConnected::Input::WEIGHTS_CLUSTERS) << ") Bias("
+ << node.getInputs().at(BCQFullyConnected::Input::BIAS) << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const BinaryArithmetic &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const operation::BroadcastTo &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const Comparison &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const Concat &node) { dumpPackingOp(node); }
+
+void OperationDumper::visit(const Conv2D &node)
+{
+ std::string padding_type =
+ node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
+ dumpConvOp(node, padding_type);
+}
+
+void OperationDumper::visit(const ConvertFp16ToFp32 &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const ConvertFp32ToFp16 &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const DepthToSpace &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const DepthwiseConv2D &node)
+{
+ std::string padding_type =
+ node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
+ dumpConvOp(node, padding_type);
+}
+
+void OperationDumper::visit(const ElementwiseActivation &node)
+{
+ std::string params;
+ if (node.param().op_type == ElementwiseActivation::Type::RELU)
+ {
+ params = " lower value(" + std::to_string(node.param().alpha) + ") upper value(" +
+ std::to_string(node.param().beta) + ")";
+ }
+ else if (node.param().op_type == ElementwiseActivation::Type::LEAKY_RELU)
+ {
+ params = " alpha value(" + std::to_string(node.param().alpha) + ")";
+ }
+ dumpUnaryInputOp(node, params);
+}
+
+void OperationDumper::visit(const ElementwiseBinary &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const ElementwiseUnary &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const EmbeddingLookup &node)
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ VERBOSE(LIR) << " - Inputs : Lookups(" << node.getInputs().at(EmbeddingLookup::Input::LOOKUPS)
+ << ") VALUES(" << node.getInputs().at(EmbeddingLookup::Input::VALUES) << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const ExpandDims &node)
+{
+ std::string axis =
+ "AXIS(" + std::to_string(node.getInputs().at(ExpandDims::Input::AXIS).value()) + ")";
+ dumpUnaryInputOp(node, axis);
+}
+
+void OperationDumper::visit(const FullyConnected &node)
+{
+ std::string inputs =
+ "Weight(" + std::to_string(node.getInputs().at(FullyConnected::Input::WEIGHT).value()) +
+ ") Bias(" + std::to_string(node.getInputs().at(FullyConnected::Input::BIAS).value()) + ")";
+ dumpUnaryInputOp(node, inputs);
+}
+
+void OperationDumper::visit(const Gather &node)
+{
+ std::string indices =
+ "Indices(" + std::to_string(node.getInputs().at(Gather::Input::INDICES).value()) + ")";
+ dumpUnaryInputOp(node, indices);
+}
+
+void OperationDumper::visit(const HashtableLookup &node)
+{
+ VERBOSE(LIR) << "* HashTableLookup" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Lookups(" << node.getInputs().at(HashtableLookup::Input::LOOKUPS)
+ << ") Keys(" << node.getInputs().at(HashtableLookup::Input::KEYS) << ") Values("
+ << node.getInputs().at(HashtableLookup::Input::VALUES) << ")" << std::endl;
+ VERBOSE(LIR) << " - Outputs : Output(" << node.getInputs().at(HashtableLookup::Output::OUTPUT)
+ << ") Hits(" << node.getInputs().at(HashtableLookup::Output::HITS) << ")"
+ << std::endl;
+}
+
+void OperationDumper::visit(const InstanceNorm &node)
+{
+ std::string inputs =
+ "Gamma(" + std::to_string(node.getInputs().at(InstanceNorm::Input::GAMMA).value()) +
+ ") Beta(" + std::to_string(node.getInputs().at(InstanceNorm::Input::BETA).value()) + ")";
+ dumpUnaryInputOp(node, inputs);
+}
+
+void OperationDumper::visit(const L2Normalization &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const LocalResponseNormalization &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const LSTM &node)
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ VERBOSE(LIR)
+ << " - Inputs : Input(" << node.getInputs().at(LSTM::Input::INPUT)
+ << ") Input To Input Weights(" << node.getInputs().at(LSTM::Input::INPUT_TO_INPUT_WEIGHTS)
+ << ") Input To Forget Weights(" << node.getInputs().at(LSTM::Input::INPUT_TO_FORGET_WEIGHTS)
+ << ") Input To Cell Weights(" << node.getInputs().at(LSTM::Input::INPUT_TO_CELL_WEIGHTS)
+ << ") Input To Output Weights(" << node.getInputs().at(LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)
+ << ") Recurrent To Input Weights("
+ << node.getInputs().at(LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)
+ << ") Recurrent To Forget Weights("
+ << node.getInputs().at(LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS)
+ << ") Recurrent To Cell Weights("
+ << node.getInputs().at(LSTM::Input::RECURRENT_TO_CELL_WEIGHTS)
+ << ") Recurrent To Output Weights("
+ << node.getInputs().at(LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS) << ") Cell To Input Weights("
+ << node.getInputs().at(LSTM::Input::CELL_TO_INPUT_WEIGHTS) << ") Cell To Forget Weights("
+ << node.getInputs().at(LSTM::Input::CELL_TO_FORGET_WEIGHTS) << ") Cell To OUTPUT Weights("
+ << node.getInputs().at(LSTM::Input::CELL_TO_OUTPUT_WEIGHTS) << ") Input Gate Bias("
+ << node.getInputs().at(LSTM::Input::INPUT_GATE_BIAS) << ") Forget Gate Bias("
+ << node.getInputs().at(LSTM::Input::FORGET_GATE_BIAS) << ") Cell Bias("
+ << node.getInputs().at(LSTM::Input::CELL_BIAS) << ") Output Gate Bias("
+ << node.getInputs().at(LSTM::Input::OUTPUT_GATE_BIAS) << ") Projection Weights("
+ << node.getInputs().at(LSTM::Input::PROJECTION_WEIGHTS) << ") Projection Bias("
+ << node.getInputs().at(LSTM::Input::PROJECTION_BIAS) << ") Output State In("
+ << node.getInputs().at(LSTM::Input::OUTPUT_STATE_IN) << ") Cell State In("
+ << node.getInputs().at(LSTM::Input::CELL_STATE_IN);
+ if (node.getInputs().size() == 24)
+ {
+ VERBOSE(LIR) << ") Input Layer Normalization Weights("
+ << node.getInputs().at(LSTM::Input::INPUT_LAYER_NORMALIZATION_WEIGHTS)
+ << ") Forget Layer Normalization Weights("
+ << node.getInputs().at(LSTM::Input::FORGET_LAYER_NORMALIZATION_WEIGHTS)
+ << ") Cell Layer Normalization Weights("
+ << node.getInputs().at(LSTM::Input::CELL_LAYER_NORMALIZATION_WEIGHTS)
+ << ") Ouput Layer Normalization Weights("
+ << node.getInputs().at(LSTM::Input::OUTPUT_LAYER_NORMALIZATION_WEIGHTS);
+ }
+ VERBOSE(LIR) << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Scratch Buffer("
+ << node.getOutputs().at(LSTM::Output::SCRATCH_BUFFER) << ") Output State Out("
+ << node.getOutputs().at(LSTM::Output::OUTPUT_STATE_OUT) << ") Cell State Out("
+ << node.getOutputs().at(LSTM::Output::CELL_STATE_OUT) << ") Output("
+ << node.getOutputs().at(LSTM::Output::OUTPUT) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const Pack &node) { dumpPackingOp(node); }
+
+void OperationDumper::visit(const Pad &node)
+{
+ std::string pad = "Pad(" + std::to_string(node.getInputs().at(Pad::Input::PAD).value()) + ")";
+ dumpUnaryInputOp(node, pad);
+}
+
+void OperationDumper::visit(const Permute &node)
+{
+ std::string permute_type = "Unknown";
+ switch (node.getPermuteType())
+ {
+ case Permute::Type::COPY:
+ permute_type = "Copy";
+ break;
+ case Permute::Type::NHWC_TO_NCHW:
+ permute_type = "NHWC to NCHW";
+ break;
+ case Permute::Type::NCHW_TO_NHWC:
+ permute_type = "NCHW to NHWC";
+ break;
+ }
+
+ VERBOSE(LIR) << "* Permute(" + permute_type + ")" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(0) << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const Pool2D &node)
+{
+ std::string padding_type =
+ node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
+ VERBOSE(LIR) << "* " << node.name() << "(" << padding_type << ")" << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(Pool2D::Input::INPUT) << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const Pow &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const PReLU &node)
+{
+ std::string alpha =
+ "Alpha(" + std::to_string(node.getInputs().at(PReLU::Input::ALPHA).value()) + ")";
+ dumpUnaryInputOp(node, alpha);
+}
+
+void OperationDumper::visit(const Rank &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const Reduce &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const Reshape &node)
+{
+ // optional param
+ std::string shape =
+ node.getInputs().size() == 2
+ ? "Shape(" + std::to_string(node.getInputs().at(Reshape::Input::SHAPE).value()) + ")"
+ : "Shape(not provided)";
+ dumpUnaryInputOp(node, shape);
+}
+
+void OperationDumper::visit(const ResizeBilinear &node)
+{
+ if (node.getInputs().size() == 1)
+ {
+ dumpUnaryInputOp(node);
+ }
+ else if (node.getInputs().size() == 2)
+ {
+ dumpBinaryInputOp(node);
+ }
+ else
+ {
+ VERBOSE(LIR) << "* " << node.name() << " is set wrong" << std::endl;
+ }
+}
+
+void OperationDumper::visit(const ResizeNearestNeighbor &node)
+{
+ if (node.getInputs().size() == 1)
+ {
+ dumpUnaryInputOp(node);
+ }
+ else if (node.getInputs().size() == 2)
+ {
+ dumpBinaryInputOp(node);
+ }
+ else
+ {
+ VERBOSE(LIR) << "* " << node.name() << " is set wrong" << std::endl;
+ }
+}
+
+void OperationDumper::visit(const Reverse &node)
+{
+ std::string axis =
+ "Axis(" + std::to_string(node.getInputs().at(Reverse::Input::AXIS).value()) + ")";
+ dumpUnaryInputOp(node, axis);
+}
+
+void OperationDumper::visit(const RNN &node)
+{
+ VERBOSE(LIR) << "* RNN" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(RNN::Input::INPUT) << ") Weights("
+ << node.getInputs().at(RNN::Input::WEIGHTS) << ") Recurrent Weights("
+ << node.getInputs().at(RNN::Input::RECURRENT_WEIGHTS) << ") Bias("
+ << node.getInputs().at(RNN::Input::BIAS) << ") Hidden State("
+ << node.getInputs().at(RNN::Input::HIDDEN_STATE_IN) << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(RNN::Output::OUTPUT)
+ << ") Hidden State(" << node.getInputs().at(RNN::Output::HIDDEN_STATE_OUT) << ")"
+ << std::endl;
+}
+
+void OperationDumper::visit(const Range &node)
+{
+ VERBOSE(LIR) << "* Range" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Start(" << node.getInputs().at(Range::Input::START) << ")"
+ << " Limit(" << node.getInputs().at(Range::Input::LIMIT) << ")"
+ << " Delta(" << node.getInputs().at(Range::Input::DELTA) << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const Select &node)
+{
+ VERBOSE(LIR) << "* Select" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Condition(" << node.getInputs().at(Select::Input::CONDITION) << ")"
+ << " Input_X(" << node.getInputs().at(Select::Input::INPUT_TRUE) << ")"
+ << " Input_Y(" << node.getInputs().at(Select::Input::INPUT_FALSE) << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const ir::operation::Shape &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const Softmax &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const SpaceToBatchND &node)
+{
+ std::string inputs =
+ "BlockSize(" +
+ std::to_string(node.getInputs().at(SpaceToBatchND::Input::BLOCK_SIZE).value()) +
+ ") Paddings(" + std::to_string(node.getInputs().at(SpaceToBatchND::Input::PADDINGS).value()) +
+ ")";
+ dumpUnaryInputOp(node, inputs);
+}
+
+void OperationDumper::visit(const SpaceToDepth &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const Split &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const SquaredDifference &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const StatelessRandomUniform &node)
+{
+ VERBOSE(LIR) << "* StatelessRandomUniform" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Shape(" << node.getInputs().at(StatelessRandomUniform::Input::SHAPE)
+ << " Seed(" << node.getInputs().at(StatelessRandomUniform::Input::SEED) << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const Squeeze &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const Slice &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const StridedSlice &node) { dumpUnaryInputOp(node); }
+
+void OperationDumper::visit(const Tile &node)
+{
+ std::string multiples =
+ "Multiples(" + std::to_string(node.getInputs().at(Tile::Input::MULTIPLES).value()) + ")";
+ dumpUnaryInputOp(node, multiples);
+}
+
+void OperationDumper::visit(const TopKV2 &node)
+{
+ VERBOSE(LIR) << "* TopKV2" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(TopKV2::Input::INPUT) << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Outputs : Values(" << node.getOutputs().at(TopKV2::Output::OUTPUT_VALUES)
+ << ") Indices(" << node.getOutputs().at(TopKV2::Output::OUTPUT_INDICES) << ")"
+ << std::endl;
+}
+
+void OperationDumper::visit(const TransposeConv &node)
+{
+ std::string padding_type =
+ node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
+ VERBOSE(LIR) << "* TransposeConv(" << padding_type << ")" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Output Shape("
+ << node.getInputs().at(TransposeConv::Input::OUTPUT_SHAPE) << ") KERNEL("
+ << node.getInputs().at(TransposeConv::Input::KERNEL) << ") IFM("
+ << node.getInputs().at(TransposeConv::Input::INPUT) << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const Transpose &node) { dumpBinaryInputOp(node); }
+
+void OperationDumper::visit(const Unpack &node)
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Unpack::Input::INPUT) << ")"
+ << std::endl;
+ std::string outputs;
+ const auto &output_indices = node.getOutputs();
+ for (auto it = std::begin(output_indices); it != std::end(output_indices); ++it)
+ {
+ outputs += std::to_string(it->value());
+ if (std::next(it) != std::end(output_indices))
+ outputs += ", ";
+ }
+ VERBOSE(LIR) << " - Outputs : Outputs(" << outputs << ")" << std::endl;
+}
+
+void OperationDumper::visit(const OneHot &node)
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ VERBOSE(LIR) << " - Inputs : "
+ << "Indices(" << node.getInputs().at(OneHot::Input::INDICES) << ") " << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
+}
+
+void OperationDumper::visit(const If &node)
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ std::string inputs;
+ const auto &input_indices = node.getInputs();
+ for (auto it = std::begin(input_indices); it != std::end(input_indices); ++it)
+ {
+ inputs += std::to_string(it->value());
+ if (std::next(it) != std::end(input_indices))
+ inputs += ", ";
+ }
+ VERBOSE(LIR) << " - Inputs : "
+ << "Then subgraph (" << node.param().then_subg_index << ") Else subgraph ("
+ << node.param().else_subg_index << ") Inputs(" << inputs << ")" << std::endl;
+ std::string outputs;
+ const auto &output_indices = node.getOutputs();
+ for (auto it = std::begin(output_indices); it != std::end(output_indices); ++it)
+ {
+ outputs += std::to_string(it->value());
+ if (std::next(it) != std::end(output_indices))
+ outputs += ", ";
+ }
+ VERBOSE(LIR) << " - Output : Outputs(" << outputs << ")" << std::endl;
+}
+
+void OperationDumper::visit(const While &node)
+{
+ VERBOSE(LIR) << "* " << node.name() << std::endl;
+ std::string inputs;
+ const auto &input_indices = node.getInputs();
+ for (auto it = std::begin(input_indices); it != std::end(input_indices); ++it)
+ {
+ inputs += std::to_string(it->value());
+ if (std::next(it) != std::end(input_indices))
+ inputs += ", ";
+ }
+ VERBOSE(LIR) << " - Inputs : "
+ << "Cond subgraph (" << node.param().cond_subg_index << ") Body subgraph ("
+ << node.param().cond_subg_index << ") Inputs(" << inputs << ")" << std::endl;
+ std::string outputs;
+ const auto &output_indices = node.getOutputs();
+ for (auto it = std::begin(output_indices); it != std::end(output_indices); ++it)
+ {
+ outputs += std::to_string(it->value());
+ if (std::next(it) != std::end(output_indices))
+ outputs += ", ";
+ }
+ VERBOSE(LIR) << " - Output : Outputs(" << outputs << ")" << std::endl;
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/OperationDumper.h b/runtime/onert/core/src/ir/OperationDumper.h
new file mode 100644
index 000000000..91642ab13
--- /dev/null
+++ b/runtime/onert/core/src/ir/OperationDumper.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_OPERATION_DUMPER_H__
+#define __ONERT_OPERATION_DUMPER_H__
+
+#include "ir/OperationVisitor.h"
+#include <string>
+
+namespace onert
+{
+namespace ir
+{
+
+class OperationDumper : public OperationVisitor
+{
+public:
+ OperationDumper(const std::string &start_msg);
+
+public:
+ void visit(const operation::ArgMax &) override;
+ void visit(const operation::BatchToSpaceND &node) override;
+ void visit(const operation::BCQFullyConnected &node) override;
+ void visit(const operation::BinaryArithmetic &node) override;
+ void visit(const operation::BroadcastTo &) override;
+ void visit(const operation::Comparison &) override;
+ void visit(const operation::Concat &node) override;
+ void visit(const operation::Conv2D &node) override;
+ void visit(const operation::ConvertFp16ToFp32 &node) override;
+ void visit(const operation::ConvertFp32ToFp16 &node) override;
+ void visit(const operation::DepthToSpace &) override;
+ void visit(const operation::DepthwiseConv2D &node) override;
+ void visit(const operation::ElementwiseActivation &) override;
+ void visit(const operation::ElementwiseBinary &) override;
+ void visit(const operation::ElementwiseUnary &) override;
+ void visit(const operation::EmbeddingLookup &) override;
+ void visit(const operation::ExpandDims &) override;
+ void visit(const operation::FullyConnected &node) override;
+ void visit(const operation::Gather &) override;
+ void visit(const operation::HashtableLookup &) override;
+ void visit(const operation::InstanceNorm &) override;
+ void visit(const operation::L2Normalization &) override;
+ void visit(const operation::LocalResponseNormalization &) override;
+ void visit(const operation::LSTM &) override;
+ void visit(const operation::Pack &) override;
+ void visit(const operation::Pad &) override;
+ void visit(const operation::Permute &node) override;
+ void visit(const operation::Pool2D &node) override;
+ void visit(const operation::Pow &node) override;
+ void visit(const operation::PReLU &) override;
+ void visit(const operation::Range &) override;
+ void visit(const operation::Rank &) override;
+ void visit(const operation::Reduce &) override;
+ void visit(const operation::Reshape &node) override;
+ void visit(const operation::ResizeBilinear &) override;
+ void visit(const operation::ResizeNearestNeighbor &) override;
+ void visit(const operation::Reverse &) override;
+ void visit(const operation::RNN &) override;
+ void visit(const operation::Select &node) override;
+ void visit(const operation::Shape &node) override;
+ void visit(const operation::Softmax &node) override;
+ void visit(const operation::SpaceToBatchND &) override;
+ void visit(const operation::SpaceToDepth &) override;
+ void visit(const operation::Split &) override;
+ void visit(const operation::SquaredDifference &) override;
+ void visit(const operation::Squeeze &) override;
+ void visit(const operation::Slice &) override;
+ void visit(const operation::StridedSlice &) override;
+ void visit(const operation::StatelessRandomUniform &) override;
+ void visit(const operation::Tile &) override;
+ void visit(const operation::TopKV2 &) override;
+ void visit(const operation::TransposeConv &) override;
+ void visit(const operation::Transpose &) override;
+ void visit(const operation::Unpack &) override;
+ void visit(const operation::OneHot &) override;
+ void visit(const operation::If &) override;
+ void visit(const operation::While &) override;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_OPERATION_DUMPER_H__
diff --git a/runtime/onert/core/src/ir/OperationIndexSet.cc b/runtime/onert/core/src/ir/OperationIndexSet.cc
new file mode 100644
index 000000000..750ffffa6
--- /dev/null
+++ b/runtime/onert/core/src/ir/OperationIndexSet.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/OperationIndexSet.h"
+
+#include <algorithm>
+
+namespace onert
+{
+namespace ir
+{
+
+OperationIndexSet::OperationIndexSet(std::initializer_list<OperationIndex> list) : _set(list)
+{
+ // DO NOTHING
+}
+
+bool OperationIndexSet::contains(const OperationIndex &index) const
+{
+ return std::find(_set.begin(), _set.end(), index) != _set.end();
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/OperationValidator.cc b/runtime/onert/core/src/ir/OperationValidator.cc
new file mode 100644
index 000000000..da08e81fc
--- /dev/null
+++ b/runtime/onert/core/src/ir/OperationValidator.cc
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OperationValidator.h"
+
+#include "ir/Graph.h"
+
+#define OP_REQUIRES(EXP) \
+ do \
+ { \
+ if (!(EXP)) \
+ throw std::runtime_error("OperationValidator failed at line " + std::to_string(__LINE__)); \
+ } while (0)
+
+namespace onert
+{
+namespace ir
+{
+
+OperationValidator::OperationValidator(const Graph &graph)
+ : _operations{graph.operations()}, _operands{graph.operands()}
+{
+}
+
+void OperationValidator::operator()()
+{
+ _operations.iterate([&](const OperationIndex &, const Operation &node) { node.accept(*this); });
+}
+
+DataType OperationValidator::operandType(const OperandIndex &idx)
+{
+ return _operands.at(idx).typeInfo().type();
+}
+
+bool OperationValidator::isConstant(const OperandIndex &idx)
+{
+ return _operands.at(idx).isConstant();
+}
+
+bool OperationValidator::isSameType(const OperandIndex &idx1, const OperandIndex &idx2)
+{
+ return operandType(idx1) == operandType(idx2);
+}
+
+bool OperationValidator::isValidType(const OperandIndex &idx, const DataType &type)
+{
+ return operandType(idx) == type;
+}
+
+bool OperationValidator::isValidType(const OperandIndex &idx,
+ std::initializer_list<DataType> valid_types)
+{
+ for (auto type_to_check : valid_types)
+ {
+ if (isValidType(idx, type_to_check))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void OperationValidator::visit(const operation::AddN &node)
+{
+ int size = node.getInputs().size();
+ for (int i = 0; i < size; i++)
+ {
+ const auto input_index(node.getInputs().at(i));
+ OP_REQUIRES(isValidType(input_index, {DataType::FLOAT32, DataType::INT32}));
+ }
+}
+
+void OperationValidator::visit(const operation::BatchMatMul &node)
+{
+ const auto lhs_index(node.getInputs().at(operation::BatchMatMul::Input::LHS));
+ const auto rhs_index(node.getInputs().at(operation::BatchMatMul::Input::RHS));
+
+ // Constant lhs and rhs is not implemented yet
+ OP_REQUIRES(!isConstant(lhs_index) && !isConstant(rhs_index));
+}
+
+void OperationValidator::visit(const operation::BatchToSpaceND &node)
+{
+ const auto block_size_index{node.getInputs().at(operation::BatchToSpaceND::Input::BLOCK_SIZE)};
+
+ // Non-constant block_size is not implemented yet
+ OP_REQUIRES(isConstant(block_size_index));
+}
+
+void OperationValidator::visit(const operation::BinaryArithmetic &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(operation::BinaryArithmetic::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(operation::BinaryArithmetic::Input::RHS)};
+
+ OP_REQUIRES(isSameType(lhs_index, rhs_index));
+ OP_REQUIRES(isSameType(lhs_index, output_index));
+}
+
+void OperationValidator::visit(const operation::Comparison &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+
+ const auto lhs_index{node.getInputs().at(operation::Comparison::Input::INPUT0)};
+ const auto rhs_index{node.getInputs().at(operation::Comparison::Input::INPUT1)};
+
+ OP_REQUIRES(isSameType(lhs_index, rhs_index));
+ OP_REQUIRES(isValidType(output_index, DataType::BOOL8));
+}
+
+void OperationValidator::visit(const operation::DepthToSpace &node)
+{
+ int32_t block_size = node.param().block_size;
+
+ OP_REQUIRES(block_size > 0);
+}
+
+void OperationValidator::visit(const operation::DepthwiseConv2D &node)
+{
+ const auto input_index{node.getInputs().at(operation::DepthwiseConv2D::Input::INPUT)};
+ const auto output_index{node.getOutputs().at(0)};
+
+ uint32_t stride_horizontal = node.param().stride.horizontal;
+ uint32_t stride_vertical = node.param().stride.vertical;
+ uint32_t dilation_width = node.param().dilation.width_factor;
+ uint32_t dilation_height = node.param().dilation.height_factor;
+
+ OP_REQUIRES((stride_horizontal > 0) && (stride_vertical > 0));
+ OP_REQUIRES((dilation_width > 0) && (dilation_height > 0));
+ OP_REQUIRES(isSameType(input_index, output_index));
+}
+
+void OperationValidator::visit(const operation::ElementwiseActivation &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ // Check if I/O types match
+ OP_REQUIRES(isSameType(output_index, input_index));
+}
+
+void OperationValidator::visit(const operation::ElementwiseBinary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(operation::ElementwiseBinary::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(operation::ElementwiseBinary::Input::RHS)};
+
+ OP_REQUIRES(isSameType(lhs_index, rhs_index));
+ OP_REQUIRES(isSameType(lhs_index, output_index));
+}
+
+void OperationValidator::visit(const operation::ElementwiseUnary &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(operation::ElementwiseUnary::Input::INPUT)};
+
+ // Check if I/O types match
+ if (node.param().op_type == operation::ElementwiseUnary::Type::DEQUANTIZE)
+ {
+ // NNAPI allow QUANT_INT8_SYMM type input
+ OP_REQUIRES(isValidType(input_index, {DataType::QUANT_UINT8_ASYMM, DataType::QUANT_INT8_SYMM,
+ DataType::QUANT_INT8_ASYMM}));
+ OP_REQUIRES(isValidType(output_index, DataType::FLOAT32));
+ }
+ else if (node.param().op_type == operation::ElementwiseUnary::Type::QUANTIZE)
+ {
+ OP_REQUIRES(isValidType(input_index, DataType::FLOAT32));
+ OP_REQUIRES(isValidType(output_index, DataType::QUANT_UINT8_ASYMM));
+ }
+ else if (node.param().op_type == operation::ElementwiseUnary::Type::FLOOR)
+ {
+ OP_REQUIRES(isValidType(input_index, DataType::FLOAT32));
+ OP_REQUIRES(isSameType(output_index, input_index));
+ }
+ else if (node.param().op_type != operation::ElementwiseUnary::Type::CAST)
+ {
+ OP_REQUIRES(isSameType(output_index, input_index));
+ }
+}
+
+void OperationValidator::visit(const operation::EmbeddingLookup &node)
+{
+ const auto lookups_index{node.getInputs().at(operation::EmbeddingLookup::Input::LOOKUPS)};
+
+ OP_REQUIRES(isValidType(lookups_index, DataType::INT32));
+}
+
+void OperationValidator::visit(const operation::ExpandDims &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(operation::ExpandDims::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(operation::ExpandDims::Input::AXIS)};
+
+ OP_REQUIRES(isSameType(output_index, input_index));
+ OP_REQUIRES(isValidType(axis_index, DataType::INT32));
+}
+
+void OperationValidator::visit(const operation::HashtableLookup &node)
+{
+ const auto hits_index{node.getOutputs().at(operation::HashtableLookup::Output::HITS)};
+ const auto lookups_index{node.getInputs().at(operation::HashtableLookup::Input::LOOKUPS)};
+ const auto keys_index{node.getInputs().at(operation::HashtableLookup::Input::KEYS)};
+
+ OP_REQUIRES(isValidType(lookups_index, DataType::INT32));
+ OP_REQUIRES(isValidType(keys_index, DataType::INT32));
+ OP_REQUIRES(isValidType(hits_index, DataType::QUANT_UINT8_ASYMM));
+}
+
+void OperationValidator::visit(const operation::Pack &node)
+{
+ const auto num{node.param().num};
+
+ OP_REQUIRES(num == static_cast<int32_t>(node.getInputs().size()));
+}
+
+void OperationValidator::visit(const operation::Pad &node)
+{
+ const auto pad_index{node.getInputs().at(operation::Pad::Input::PAD)};
+
+ OP_REQUIRES(isValidType(pad_index, DataType::INT32));
+}
+
+void OperationValidator::visit(const operation::Rank &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+
+ OP_REQUIRES(isValidType(output_index, DataType::INT32));
+}
+
+void OperationValidator::visit(const operation::ResizeBilinear &node)
+{
+ auto align_corners = node.param().align_corners;
+ auto half_pixel_centers = node.param().half_pixel_centers;
+
+ OP_REQUIRES(!align_corners || !half_pixel_centers);
+}
+
+void OperationValidator::visit(const operation::Reverse &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(operation::Reverse::Input::INPUT)};
+ const auto axis_index{node.getInputs().at(operation::Reverse::Input::AXIS)};
+
+ OP_REQUIRES(isValidType(axis_index, DataType::INT32));
+ OP_REQUIRES(isSameType(output_index, input_index));
+}
+
+void OperationValidator::visit(const operation::Select &node)
+{
+ const auto condition_index{node.getInputs().at(operation::Select::Input::CONDITION)};
+ const auto input_true_index{node.getInputs().at(operation::Select::Input::INPUT_TRUE)};
+ const auto input_false_index{node.getInputs().at(operation::Select::Input::INPUT_FALSE)};
+
+ OP_REQUIRES(isValidType(condition_index, DataType::BOOL8));
+ OP_REQUIRES(isSameType(input_true_index, input_false_index));
+}
+
+void OperationValidator::visit(const operation::Shape &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+
+ OP_REQUIRES(isValidType(output_index, {DataType::UINT32, DataType::INT32, DataType::INT64}));
+}
+
+void OperationValidator::visit(const operation::SpaceToBatchND &node)
+{
+ const auto block_size_index{node.getInputs().at(operation::SpaceToBatchND::Input::BLOCK_SIZE)};
+ const auto paddings_index{node.getInputs().at(operation::SpaceToBatchND::Input::PADDINGS)};
+
+ // Non-constant block_size and padding is not implemented yet
+ OP_REQUIRES(isConstant(block_size_index));
+ OP_REQUIRES(isConstant(paddings_index));
+}
+
+void OperationValidator::visit(const operation::SpaceToDepth &node)
+{
+ const auto block_size = node.param().block_size;
+ OP_REQUIRES(block_size >= 1);
+}
+
+void OperationValidator::visit(const operation::Split &node)
+{
+ const auto num_splits = node.param().num_splits;
+
+ OP_REQUIRES(num_splits > 0 && num_splits <= 0xFFFF);
+ OP_REQUIRES(node.getOutputs().size() == static_cast<uint32_t>(num_splits));
+}
+
+void OperationValidator::visit(const operation::SquaredDifference &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(operation::SquaredDifference::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(operation::SquaredDifference::Input::RHS)};
+
+ OP_REQUIRES(isSameType(output_index, lhs_index));
+ OP_REQUIRES(isSameType(lhs_index, rhs_index));
+}
+
+void OperationValidator::visit(const operation::StridedSlice &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(operation::StridedSlice::Input::INPUT)};
+
+ OP_REQUIRES(isSameType(output_index, input_index));
+}
+
+void OperationValidator::visit(const operation::TransposeConv &node)
+{
+ OP_REQUIRES((node.param().padding.type == PaddingType::SAME) ||
+ (node.param().padding.type == PaddingType::VALID));
+}
+
+void OperationValidator::visit(const operation::Unpack &node)
+{
+ const auto num{node.param().num};
+ OP_REQUIRES(num == static_cast<int32_t>(node.getOutputs().size()));
+}
+
+void OperationValidator::visit(const operation::While &node)
+{
+ OP_REQUIRES(node.getInputs().size() == node.getOutputs().size());
+}
+
+} // namespace compiler
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/OperationValidator.h b/runtime/onert/core/src/ir/OperationValidator.h
new file mode 100644
index 000000000..2ea8000e5
--- /dev/null
+++ b/runtime/onert/core/src/ir/OperationValidator.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_IR_OPERATION_VALIDATOR_H__
+#define __ONERT_IR_OPERATION_VALIDATOR_H__
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+class Graph;
+class Operands;
+} // namespace ir
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+
+class OperationValidator : public OperationVisitor
+{
+public:
+ OperationValidator(void) = delete;
+ OperationValidator(const Graph &graph);
+
+public:
+ void operator()();
+
+public:
+ void visit(const operation::AddN &node) override;
+ void visit(const operation::BatchMatMul &node) override;
+ void visit(const operation::BatchToSpaceND &node) override;
+ void visit(const operation::BinaryArithmetic &node) override;
+ void visit(const operation::Comparison &node) override;
+ void visit(const operation::DepthToSpace &node) override;
+ void visit(const operation::DepthwiseConv2D &node) override;
+ void visit(const operation::ElementwiseActivation &node) override;
+ void visit(const operation::ElementwiseBinary &node) override;
+ void visit(const operation::ElementwiseUnary &node) override;
+ void visit(const operation::EmbeddingLookup &node) override;
+ void visit(const operation::ExpandDims &node) override;
+ void visit(const operation::HashtableLookup &node) override;
+ void visit(const operation::Pack &node) override;
+ void visit(const operation::Pad &node) override;
+ void visit(const operation::Rank &node) override;
+ void visit(const operation::ResizeBilinear &node) override;
+ void visit(const operation::Reverse &node) override;
+ void visit(const operation::Select &node) override;
+ void visit(const operation::Shape &node) override;
+ void visit(const operation::SpaceToBatchND &node) override;
+ void visit(const operation::SpaceToDepth &node) override;
+ void visit(const operation::Split &node) override;
+ void visit(const operation::SquaredDifference &node) override;
+ void visit(const operation::StridedSlice &node) override;
+ void visit(const operation::TransposeConv &node) override;
+ void visit(const operation::Unpack &node) override;
+ void visit(const operation::While &node) override;
+
+private:
+ DataType operandType(const OperandIndex &idx);
+ bool isConstant(const OperandIndex &idx);
+ bool isSameType(const OperandIndex &idx1, const OperandIndex &idx2);
+ bool isValidType(const OperandIndex &idx, const DataType &type);
+ bool isValidType(const OperandIndex &idx, std::initializer_list<DataType> valid_types);
+
+private:
+ const Operations &_operations;
+ const Operands &_operands;
+};
+
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_IR_OPERATION_VALIDATOR_H__
diff --git a/runtime/onert/core/src/ir/Operations.cc b/runtime/onert/core/src/ir/Operations.cc
new file mode 100644
index 000000000..64d0bd6f0
--- /dev/null
+++ b/runtime/onert/core/src/ir/Operations.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Operations.h"
+
+#include "OperationCloner.h"
+
+namespace onert
+{
+namespace ir
+{
+
+Operations::Operations(const Operations &obj)
+{
+ obj.iterate([&](const OperationIndex &index, const Operation &op) {
+ OperationCloner cloner;
+ op.accept(cloner);
+ _objects.emplace(index, cloner.releaseClone());
+ });
+ _index_count = obj._index_count;
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/Padding.cc b/runtime/onert/core/src/ir/Padding.cc
new file mode 100644
index 000000000..d74f80217
--- /dev/null
+++ b/runtime/onert/core/src/ir/Padding.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Padding.h"
+
+#include "util/Utils.h"
+
+#include <stdexcept>
+#include <cassert>
+
+namespace onert
+{
+namespace ir
+{
+namespace
+{
+
+inline ExplicitPadding validPadding(void)
+{
+ //
+ // ANEURALNETWORKS_PADDING_VALID
+ //
+ // VALID padding. No padding.
+ //
+ // When the input size is not evenly divisible by the filter size,
+ // the input at the end that could not fill the whole filter tile
+ // will simply be ignored.
+ //
+ ExplicitPadding padding;
+
+ padding.top = 0;
+ padding.bottom = 0;
+ padding.left = 0;
+ padding.right = 0;
+
+ return padding;
+}
+
+inline ExplicitPadding samePaddingUsingIFM(const FeatureShape &ifm_shape, const Stride &stride,
+ uint32_t kw, uint32_t kh, uint32_t dwf, uint32_t dhf)
+{
+ ExplicitPadding padding;
+
+ // ANEURALNETWORKS_PADDING_SAME (from NNAPI spec)
+ //
+ // SAME padding. Padding on both ends are the "same":
+ //
+ // padding_to_beginning = total_padding / 2
+ // padding_to_end = (total_padding + 1)/2.
+ //
+ const int32_t effective_filter_h_size = (kh - 1) * dhf + 1;
+ const int32_t effective_filter_w_size = (kw - 1) * dwf + 1;
+
+ const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical;
+ const int32_t horizontal_expected_output =
+ (ifm_shape.W + stride.horizontal - 1) / stride.horizontal;
+
+ const int32_t vertical_needed_input =
+ (vertical_expected_output - 1) * stride.vertical + effective_filter_h_size;
+ const int32_t vertical_total_padding = std::max(0, vertical_needed_input - ifm_shape.H);
+
+ const int32_t horizontal_needed_input =
+ (horizontal_expected_output - 1) * stride.horizontal + effective_filter_w_size;
+ const int32_t horizontal_total_padding = std::max(0, horizontal_needed_input - ifm_shape.W);
+
+ padding.top = vertical_total_padding / 2;
+ padding.bottom = (vertical_total_padding + 1) / 2;
+ padding.left = horizontal_total_padding / 2;
+ padding.right = (horizontal_total_padding + 1) / 2;
+
+ return padding;
+}
+
+inline ExplicitPadding samePadding(const FeatureShape &ifm_shape, const FeatureShape &ofm_shape,
+ const Stride &stride, uint32_t kw, uint32_t kh, uint32_t dwf,
+ uint32_t dhf)
+{
+ const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical;
+ const int32_t horizontal_expected_output =
+ (ifm_shape.W + stride.horizontal - 1) / stride.horizontal;
+ assert(vertical_expected_output == ofm_shape.H);
+ assert(horizontal_expected_output == ofm_shape.W);
+
+ UNUSED_RELEASE(ofm_shape);
+ UNUSED_RELEASE(vertical_expected_output);
+ UNUSED_RELEASE(horizontal_expected_output);
+
+ return samePaddingUsingIFM(ifm_shape, stride, kw, kh, dwf, dhf);
+}
+
+} // namespace
+
+inline std::string to_string(const PaddingType type)
+{
+ switch (type)
+ {
+ case PaddingType::EXPLICIT:
+ return "Padding::EXPLICIT";
+ case PaddingType::SAME:
+ return "Padding::SAME";
+ case PaddingType::VALID:
+ return "Padding::VALID";
+ default:
+ throw std::runtime_error{"Fail to convert string: wrong padding type"};
+ }
+}
+
+Padding::Padding(void) : type{PaddingType::EXPLICIT}, param{0, 0, 0, 0}
+{
+ // DO NOTHING
+}
+
+Padding::Padding(PaddingType paddingType) : type{paddingType}, param{0, 0, 0, 0}
+{
+ assert(paddingType != PaddingType::EXPLICIT);
+}
+
+Padding::Padding(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom)
+ : type{PaddingType::EXPLICIT}, param{left, right, top, bottom}
+{
+ // DO NOTHING
+}
+
+const ExplicitPadding calculatePadding(const Padding &padding, const FeatureShape &ifm_shape,
+ const FeatureShape &ofm_shape, const Stride &stride,
+ uint32_t kw, uint32_t kh, uint32_t dwf, uint32_t dhf)
+{
+ if (padding.type == PaddingType::EXPLICIT)
+ {
+ return padding.param;
+ }
+ else if (padding.type == PaddingType::SAME)
+ {
+ return samePadding(ifm_shape, ofm_shape, stride, kw, kh, dwf, dhf);
+ }
+ else if (padding.type == PaddingType::VALID)
+ {
+ return validPadding();
+ }
+ else
+ {
+ throw std::runtime_error{"Cannot handle padding type"};
+ }
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/Shape.cc b/runtime/onert/core/src/ir/Shape.cc
new file mode 100644
index 000000000..322df7b4c
--- /dev/null
+++ b/runtime/onert/core/src/ir/Shape.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Shape.h"
+
+#include <cassert>
+#include <functional>
+#include <numeric>
+#include <algorithm>
+
+namespace onert
+{
+namespace ir
+{
+
+int32_t const Shape::UNSPECIFIED_DIM = -1;
+
+// NNFW_MAX_RANK is 6
+int32_t const Shape::MAX_RANK = 6;
+
+FeatureShape Shape::asFeature(Layout layout) const
+{
+ assert(rank() == 4);
+
+ if (layout == Layout::NHWC)
+ {
+ // Feature Map in NHWC layout
+ // - Dimension(0) -> Batch
+ // - Dimension(1) -> Height
+ // - Dimension(2) -> Width
+ // - Dimension(3) -> Depth
+ const auto batch = dim(0);
+ const auto depth = dim(3);
+ const auto height = dim(1);
+ const auto width = dim(2);
+
+ return {batch, depth, height, width};
+ }
+ else if (layout == Layout::NCHW)
+ {
+ // Feature Map in NHWC layout
+ // - Dimension(0) -> Batch
+ // - Dimension(1) -> Depth
+ // - Dimension(2) -> Height
+ // - Dimension(3) -> Width
+ const auto batch = dim(0);
+ const auto depth = dim(1);
+ const auto height = dim(2);
+ const auto width = dim(3);
+
+ return {batch, depth, height, width};
+ }
+ else
+ {
+ throw std::runtime_error("Wrong Layout");
+ }
+}
+
+// Extended dimension is filled with 1.
+void Shape::extendRank(int to_rank)
+{
+ assert(to_rank - rank() >= 0);
+ _dimensions.insert(_dimensions.cbegin(), to_rank - rank(), 1);
+}
+
+uint64_t Shape::num_elements() const
+{
+ // if dimension is 0, it means unspecified and cannot calculate the total number of elements
+ if (std::any_of(_dimensions.begin(), _dimensions.end(),
+ [](const int32_t &v) { return v == UNSPECIFIED_DIM; }))
+ throw std::runtime_error("num_elements() cannot calculate when any dimension is unspecified");
+
+ return std::accumulate(_dimensions.cbegin(), _dimensions.cend(), UINT64_C(1),
+ std::multiplies<uint64_t>());
+}
+
+Shape permuteShape(const Shape &shape, Layout frontend_layout, Layout backend_layout)
+{
+ assert(shape.rank() <= Shape::MAX_RANK);
+ Shape backend_shape{shape};
+ if (shape.rank() >= 4 && frontend_layout == Layout::NHWC && backend_layout == Layout::NCHW)
+ {
+ // Permutation changing layout beyond 4-D is not supported yet
+ assert(shape.rank() <= 4);
+ backend_shape.dim(1) = shape.dim(3);
+ backend_shape.dim(2) = shape.dim(1);
+ backend_shape.dim(3) = shape.dim(2);
+ }
+ else if (shape.rank() >= 4 && frontend_layout == Layout::NCHW && backend_layout == Layout::NHWC)
+ {
+ // Permutation changing layout beyond 4-D is not supported yet
+ assert(shape.rank() <= 4);
+ backend_shape.dim(1) = shape.dim(2);
+ backend_shape.dim(2) = shape.dim(3);
+ backend_shape.dim(3) = shape.dim(1);
+ }
+ return backend_shape;
+}
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/TypeInfo.cc b/runtime/onert/core/src/ir/TypeInfo.cc
new file mode 100644
index 000000000..ab8af287e
--- /dev/null
+++ b/runtime/onert/core/src/ir/TypeInfo.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/TypeInfo.h"
+
+namespace onert
+{
+namespace ir
+{
+
+bool operator==(const TypeInfo &lhs, const TypeInfo &rhs)
+{
+ if (lhs.type() != rhs.type())
+ {
+ return false;
+ }
+
+ if (lhs.offset() != rhs.offset())
+ {
+ return false;
+ }
+
+ if (lhs.scale() != rhs.scale())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool operator!=(const TypeInfo &lhs, const TypeInfo &rhs) { return !(lhs == rhs); }
+
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/AddN.cc b/runtime/onert/core/src/ir/operation/AddN.cc
new file mode 100644
index 000000000..ce471252d
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/AddN.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/AddN.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void AddN::accept(OperationVisitor &v) const { v.visit(*this); }
+
+AddN::AddN(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(inputs.size()), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ArgMax.cc b/runtime/onert/core/src/ir/operation/ArgMax.cc
new file mode 100644
index 000000000..f3bd8fd73
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ArgMax.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ArgMax.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ArgMax::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ArgMax::ArgMax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/BCQFullyConnected.cc b/runtime/onert/core/src/ir/operation/BCQFullyConnected.cc
new file mode 100644
index 000000000..9dc54e6e9
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/BCQFullyConnected.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/BCQFullyConnected.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void BCQFullyConnected::accept(OperationVisitor &v) const { v.visit(*this); }
+
+BCQFullyConnected::BCQFullyConnected(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createExact(5u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/BCQGather.cc b/runtime/onert/core/src/ir/operation/BCQGather.cc
new file mode 100644
index 000000000..80efa6460
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/BCQGather.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/BCQGather.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void BCQGather::accept(OperationVisitor &v) const { v.visit(*this); }
+
+BCQGather::BCQGather(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(4u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/BatchMatMul.cc b/runtime/onert/core/src/ir/operation/BatchMatMul.cc
new file mode 100644
index 000000000..b9616158d
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/BatchMatMul.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/BatchMatMul.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void BatchMatMul::accept(OperationVisitor &v) const { v.visit(*this); }
+
+BatchMatMul::BatchMatMul(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/BatchToSpaceND.cc b/runtime/onert/core/src/ir/operation/BatchToSpaceND.cc
new file mode 100644
index 000000000..34be79dd2
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/BatchToSpaceND.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/BatchToSpaceND.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void BatchToSpaceND::accept(OperationVisitor &v) const { v.visit(*this); }
+
+BatchToSpaceND::BatchToSpaceND(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createInRange(2u, 3u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/BinaryArithmetic.cc b/runtime/onert/core/src/ir/operation/BinaryArithmetic.cc
new file mode 100644
index 000000000..2b1422c73
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/BinaryArithmetic.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/BinaryArithmetic.h"
+
+#include <cassert>
+#include <unordered_map>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void BinaryArithmetic::accept(OperationVisitor &v) const { v.visit(*this); }
+
+BinaryArithmetic::BinaryArithmetic(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+std::string BinaryArithmetic::name() const
+{
+ using ArithmeticType = onert::ir::operation::BinaryArithmetic::ArithmeticType;
+ static const std::unordered_map<ArithmeticType, std::string> name_map{
+ {ArithmeticType::ADD, std::string{"Add"}},
+ {ArithmeticType::SUB, std::string{"Sub"}},
+ {ArithmeticType::MUL, std::string{"Mul"}},
+ {ArithmeticType::DIV, std::string{"Div"}}};
+ return name_map.at(_param.arithmetic_type);
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/BroadcastTo.cc b/runtime/onert/core/src/ir/operation/BroadcastTo.cc
new file mode 100644
index 000000000..a8f5e59cf
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/BroadcastTo.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/BroadcastTo.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+void BroadcastTo::accept(OperationVisitor &v) const { v.visit(*this); }
+
+BroadcastTo::BroadcastTo(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Comparison.cc b/runtime/onert/core/src/ir/operation/Comparison.cc
new file mode 100644
index 000000000..2f6775411
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Comparison.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Comparison.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Comparison::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Comparison::Comparison(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Concat.cc b/runtime/onert/core/src/ir/operation/Concat.cc
new file mode 100644
index 000000000..608bc29a6
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Concat.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Concat.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Concat::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Concat::Concat(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createAtLeast(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Conv2D.cc b/runtime/onert/core/src/ir/operation/Conv2D.cc
new file mode 100644
index 000000000..3a2e1d1fe
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Conv2D.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Conv2D.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Conv2D::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Conv2D::Conv2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ConvertFp16ToFp32.cc b/runtime/onert/core/src/ir/operation/ConvertFp16ToFp32.cc
new file mode 100644
index 000000000..676e039fa
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ConvertFp16ToFp32.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ConvertFp16ToFp32.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ConvertFp16ToFp32::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ConvertFp16ToFp32::ConvertFp16ToFp32(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ConvertFp32ToFp16.cc b/runtime/onert/core/src/ir/operation/ConvertFp32ToFp16.cc
new file mode 100644
index 000000000..bcfcbfc04
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ConvertFp32ToFp16.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ConvertFp32ToFp16.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ConvertFp32ToFp16::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ConvertFp32ToFp16::ConvertFp32ToFp16(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Custom.cc b/runtime/onert/core/src/ir/operation/Custom.cc
new file mode 100644
index 000000000..25c53e1ba
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Custom.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Custom.h"
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Custom::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Custom::Custom(OperandConstraint input_constr, const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, std::string id, const Userdata &userdata)
+ : Operation{input_constr, inputs, outputs}, _id(std::move(id)), _userdata(userdata)
+{
+}
+
+const std::string &Custom::id() const { return _id; }
+
+const Custom::Userdata &Custom::userdata() const { return _userdata; }
+
+std::string Custom::name() const { return id(); }
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/DepthToSpace.cc b/runtime/onert/core/src/ir/operation/DepthToSpace.cc
new file mode 100644
index 000000000..f2d6c7c1b
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/DepthToSpace.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/DepthToSpace.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void DepthToSpace::accept(OperationVisitor &v) const { v.visit(*this); }
+
+DepthToSpace::DepthToSpace(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/DepthwiseConv2D.cc b/runtime/onert/core/src/ir/operation/DepthwiseConv2D.cc
new file mode 100644
index 000000000..d587a5591
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/DepthwiseConv2D.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/DepthwiseConv2D.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void DepthwiseConv2D::accept(OperationVisitor &v) const { v.visit(*this); }
+
+DepthwiseConv2D::DepthwiseConv2D(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Einsum.cc b/runtime/onert/core/src/ir/operation/Einsum.cc
new file mode 100644
index 000000000..3c1473aaa
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Einsum.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Einsum.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Einsum::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Einsum::Einsum(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createAtLeast(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ElementwiseActivation.cc b/runtime/onert/core/src/ir/operation/ElementwiseActivation.cc
new file mode 100644
index 000000000..f6718b656
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ElementwiseActivation.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ElementwiseActivation.h"
+
+#include <cassert>
+#include <unordered_map>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ElementwiseActivation::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ElementwiseActivation::ElementwiseActivation(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+ if (param.op_type == Type::LOGISTIC)
+ {
+ assert(param.alpha == 0.0f && param.beta == 0.0f && "Logistic will be supported only as "
+ "sigmoid function(L=1, k=1, x0=0). So, do "
+ "not use alpha and beta");
+ }
+ else if (param.op_type == Type::RELU)
+ {
+ assert(param.alpha >= param.beta && "ReLU's alpha must be equal or greater than beta");
+ }
+ else if (param.op_type == Type::TANH)
+ {
+ assert(param.alpha == 1.0f && param.beta == 1.0f && "f(x) = alpha * tanh(beta * x), Tanh is "
+ "supported only the values of alpha and "
+ "beta are 1.f");
+ }
+}
+
+std::string ElementwiseActivation::name() const
+{
+ using ElementwiseActivationType = onert::ir::operation::ElementwiseActivation::Type;
+ static const std::unordered_map<Type, std::string> name_map{
+ {ElementwiseActivationType::ELU, "ELU"},
+ {ElementwiseActivationType::LOGISTIC, "Logistic"},
+ {ElementwiseActivationType::RELU, "ReLU"},
+ {ElementwiseActivationType::TANH, "Tanh"},
+ {ElementwiseActivationType::LEAKY_RELU, "LeakyRelu"}};
+ return name_map.at(_param.op_type);
+}
+
+float ElementwiseActivation::infinity = std::numeric_limits<float>::infinity();
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ElementwiseBinary.cc b/runtime/onert/core/src/ir/operation/ElementwiseBinary.cc
new file mode 100644
index 000000000..3287fc0a3
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ElementwiseBinary.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ElementwiseBinary.h"
+
+#include <cassert>
+#include <unordered_map>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ElementwiseBinary::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ElementwiseBinary::ElementwiseBinary(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+std::string ElementwiseBinary::name() const
+{
+ using ElementwiseBinaryType = onert::ir::operation::ElementwiseBinary::ElementwiseBinaryType;
+ static const std::unordered_map<ElementwiseBinaryType, std::string> name_map{
+ {ElementwiseBinaryType::LOGICAL_AND, std::string{"LogicalAnd"}},
+ {ElementwiseBinaryType::LOGICAL_OR, std::string{"LogicalOr"}},
+ {ElementwiseBinaryType::MAX, std::string{"Max"}},
+ {ElementwiseBinaryType::MIN, std::string{"Min"}}};
+ return name_map.at(_param.op_type);
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ElementwiseUnary.cc b/runtime/onert/core/src/ir/operation/ElementwiseUnary.cc
new file mode 100644
index 000000000..6a0be7eb8
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ElementwiseUnary.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ElementwiseUnary.h"
+
+#include <cassert>
+#include <unordered_map>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ElementwiseUnary::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ElementwiseUnary::ElementwiseUnary(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs,
+ OperandConstraint::createExact(1u)},
+ _param{param}
+{
+}
+
+std::string ElementwiseUnary::name() const
+{
+ using ElementwiseUnaryType = onert::ir::operation::ElementwiseUnary::Type;
+ static const std::unordered_map<ElementwiseUnaryType, std::string> name_map{
+ {ElementwiseUnaryType::ABS, std::string{"Abs"}},
+ {ElementwiseUnaryType::CAST, std::string{"Cast"}},
+ {ElementwiseUnaryType::COS, std::string{"Cos"}},
+ {ElementwiseUnaryType::DEQUANTIZE, std::string{"Dequantize"}},
+ {ElementwiseUnaryType::ERF, std::string{"Erf"}},
+ {ElementwiseUnaryType::EXP, std::string{"Exp"}},
+ {ElementwiseUnaryType::FLOOR, std::string{"Floor"}},
+ {ElementwiseUnaryType::LOG, std::string{"Log"}},
+ {ElementwiseUnaryType::LOGICAL_NOT, std::string{"LogicalNot"}},
+ {ElementwiseUnaryType::NEG, std::string{"Neg"}},
+ {ElementwiseUnaryType::QUANTIZE, std::string{"Quantize"}},
+ {ElementwiseUnaryType::ROUND, std::string{"Round"}},
+ {ElementwiseUnaryType::RSQRT, std::string{"RSqrt"}},
+ {ElementwiseUnaryType::SIN, std::string{"Sin"}},
+ {ElementwiseUnaryType::SQRT, std::string{"Sqrt"}},
+ {ElementwiseUnaryType::SQURE, std::string{"Squre"}},
+ {ElementwiseUnaryType::ZEROS_LIKE, std::string{"ZerosLike"}}};
+ return name_map.at(_param.op_type);
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/EmbeddingLookup.cc b/runtime/onert/core/src/ir/operation/EmbeddingLookup.cc
new file mode 100644
index 000000000..b300b004e
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/EmbeddingLookup.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/EmbeddingLookup.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void EmbeddingLookup::accept(OperationVisitor &v) const { v.visit(*this); }
+
+EmbeddingLookup::EmbeddingLookup(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ExpandDims.cc b/runtime/onert/core/src/ir/operation/ExpandDims.cc
new file mode 100644
index 000000000..3f555bd23
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ExpandDims.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ExpandDims.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ExpandDims::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ExpandDims::ExpandDims(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Fill.cc b/runtime/onert/core/src/ir/operation/Fill.cc
new file mode 100644
index 000000000..b8b97d1c0
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Fill.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Fill.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Fill::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Fill::Fill(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/FullyConnected.cc b/runtime/onert/core/src/ir/operation/FullyConnected.cc
new file mode 100644
index 000000000..9837a3137
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/FullyConnected.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/FullyConnected.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void FullyConnected::accept(OperationVisitor &v) const { v.visit(*this); }
+
+FullyConnected::FullyConnected(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createInRange(2u, 3u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/FusedBatchNorm.cc b/runtime/onert/core/src/ir/operation/FusedBatchNorm.cc
new file mode 100644
index 000000000..7b9301ea6
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/FusedBatchNorm.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/FusedBatchNorm.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void FusedBatchNorm::accept(OperationVisitor &v) const { v.visit(*this); }
+
+FusedBatchNorm::FusedBatchNorm(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createAtLeast(5u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Gather.cc b/runtime/onert/core/src/ir/operation/Gather.cc
new file mode 100644
index 000000000..11d46e75b
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Gather.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Gather.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Gather::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Gather::Gather(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/HashtableLookup.cc b/runtime/onert/core/src/ir/operation/HashtableLookup.cc
new file mode 100644
index 000000000..e9a7a82ff
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/HashtableLookup.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/HashtableLookup.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void HashtableLookup::accept(OperationVisitor &v) const { v.visit(*this); }
+
+HashtableLookup::HashtableLookup(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/If.cc b/runtime/onert/core/src/ir/operation/If.cc
new file mode 100644
index 000000000..599751dfd
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/If.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ir/operation/If.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+void If::accept(OperationVisitor &v) const { v.visit(*this); }
+If::If(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createAny(), inputs, outputs}, _param{param}
+{
+}
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/InstanceNorm.cc b/runtime/onert/core/src/ir/operation/InstanceNorm.cc
new file mode 100644
index 000000000..2334560ef
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/InstanceNorm.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/InstanceNorm.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void InstanceNorm::accept(OperationVisitor &v) const { v.visit(*this); }
+
+InstanceNorm::InstanceNorm(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/L2Normalization.cc b/runtime/onert/core/src/ir/operation/L2Normalization.cc
new file mode 100644
index 000000000..9a7d3eb61
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/L2Normalization.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/L2Normalization.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void L2Normalization::accept(OperationVisitor &v) const { v.visit(*this); }
+
+L2Normalization::L2Normalization(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/LSTM.cc b/runtime/onert/core/src/ir/operation/LSTM.cc
new file mode 100644
index 000000000..5cd7c793a
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/LSTM.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/LSTM.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void LSTM::accept(OperationVisitor &v) const { v.visit(*this); }
+
+LSTM::LSTM(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createInRange(20u, 24u), inputs, outputs}, _param{param}
+{
+}
+
+std::string LSTM::name() const
+{
+ if (getOutputs().at(Output::SCRATCH_BUFFER).undefined())
+ return std::string{"UnidirectionalSequenceLSTM"};
+ else
+ return Operation::name();
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/LocalResponseNormalization.cc b/runtime/onert/core/src/ir/operation/LocalResponseNormalization.cc
new file mode 100644
index 000000000..1ae97c142
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/LocalResponseNormalization.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/LocalResponseNormalization.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void LocalResponseNormalization::accept(OperationVisitor &v) const { v.visit(*this); }
+
+LocalResponseNormalization::LocalResponseNormalization(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/LogSoftmax.cc b/runtime/onert/core/src/ir/operation/LogSoftmax.cc
new file mode 100644
index 000000000..73c6580ec
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/LogSoftmax.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/LogSoftmax.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void LogSoftmax::accept(OperationVisitor &v) const { v.visit(*this); }
+
+LogSoftmax::LogSoftmax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/LowerInfo.cc b/runtime/onert/core/src/ir/operation/LowerInfo.cc
new file mode 100644
index 000000000..249918bd6
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/LowerInfo.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/LowerInfo.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+LowerInfo::LowerInfo(const backend::Backend *backend, Layout layout)
+ : _permute_factor{backend, layout}
+{
+ // DO NOTHING
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/MatrixBandPart.cc b/runtime/onert/core/src/ir/operation/MatrixBandPart.cc
new file mode 100644
index 000000000..bac31f13e
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/MatrixBandPart.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/MatrixBandPart.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void MatrixBandPart::accept(OperationVisitor &v) const { v.visit(*this); }
+
+MatrixBandPart::MatrixBandPart(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/OneHot.cc b/runtime/onert/core/src/ir/operation/OneHot.cc
new file mode 100644
index 000000000..22935e7d6
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/OneHot.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/OneHot.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void OneHot::accept(OperationVisitor &v) const { v.visit(*this); }
+
+OneHot::OneHot(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(4u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/PReLU.cc b/runtime/onert/core/src/ir/operation/PReLU.cc
new file mode 100644
index 000000000..a2e37e0ad
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/PReLU.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/PReLU.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void PReLU::accept(OperationVisitor &v) const { v.visit(*this); }
+
+PReLU::PReLU(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Pack.cc b/runtime/onert/core/src/ir/operation/Pack.cc
new file mode 100644
index 000000000..784d4162a
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Pack.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ir/operation/Pack.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+void Pack::accept(OperationVisitor &v) const { v.visit(*this); }
+Pack::Pack(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createAtLeast(1u), inputs, outputs}, _param{param}
+{
+}
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Pad.cc b/runtime/onert/core/src/ir/operation/Pad.cc
new file mode 100644
index 000000000..0c56e92e3
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Pad.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Pad.h"
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Pad::accept(OperationVisitor &v) const { v.visit(*this); }
+
+// PAD: 2 inputs
+// PADV2: 3 inputs
+Pad::Pad(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createInRange(2u, 3u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Permute.cc b/runtime/onert/core/src/ir/operation/Permute.cc
new file mode 100644
index 000000000..eefb6c542
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Permute.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Permute.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Permute::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Permute::Permute(const OperandIndex &input, const OperandIndex &output, Type type)
+ : Operation{OperandConstraint::createExact(1u)}, _type{type}
+{
+ setInputs({input});
+ setOutputs({output});
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Pool2D.cc b/runtime/onert/core/src/ir/operation/Pool2D.cc
new file mode 100644
index 000000000..761d14c3d
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Pool2D.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Pool2D.h"
+
+#include <cassert>
+#include <unordered_map>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Pool2D::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Pool2D::Pool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+std::string Pool2D::name() const
+{
+ using PoolType = onert::ir::operation::Pool2D::PoolType;
+ static const std::unordered_map<PoolType, std::string> name_map{
+ {PoolType::AVG, "Avg" + std::string{toString(opcode())}},
+ {PoolType::L2, "L2" + std::string{toString(opcode())}},
+ {PoolType::MAX, "Max" + std::string{toString(opcode())}}};
+ return name_map.at(_param.op_type);
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Pow.cc b/runtime/onert/core/src/ir/operation/Pow.cc
new file mode 100644
index 000000000..940b1391a
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Pow.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Pow.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Pow::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Pow::Pow(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/RNN.cc b/runtime/onert/core/src/ir/operation/RNN.cc
new file mode 100644
index 000000000..298c5e745
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/RNN.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/RNN.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void RNN::accept(OperationVisitor &v) const { v.visit(*this); }
+
+RNN::RNN(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(5u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Range.cc b/runtime/onert/core/src/ir/operation/Range.cc
new file mode 100644
index 000000000..96ab04c1b
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Range.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Range.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Range::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Range::Range(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Rank.cc b/runtime/onert/core/src/ir/operation/Rank.cc
new file mode 100644
index 000000000..c357e9018
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Rank.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Rank.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Rank::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Rank::Rank(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Reduce.cc b/runtime/onert/core/src/ir/operation/Reduce.cc
new file mode 100644
index 000000000..d6a1d953c
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Reduce.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Reduce.h"
+
+#include <cassert>
+#include <unordered_map>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Reduce::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Reduce::Reduce(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+std::string Reduce::name() const
+{
+ using ReduceType = onert::ir::operation::Reduce::ReduceType;
+ static const std::unordered_map<ReduceType, std::string> name_map{
+ {ReduceType::ALL, std::string{toString(opcode())} + "All"},
+ {ReduceType::ANY, std::string{toString(opcode())} + "Any"},
+ {ReduceType::MAX, std::string{toString(opcode())} + "Max"},
+ {ReduceType::MEAN, std::string{toString(opcode())} + "Mean"},
+ {ReduceType::MIN, std::string{toString(opcode())} + "Min"},
+ {ReduceType::PROD, std::string{toString(opcode())} + "Prod"},
+ {ReduceType::SUM, std::string{toString(opcode())} + "SUM"}};
+ return name_map.at(_param.reduce_type);
+ // return std::string(toString(opcode())) + reduce_type_str_map.at(_param.reduce_type);
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Reshape.cc b/runtime/onert/core/src/ir/operation/Reshape.cc
new file mode 100644
index 000000000..92aa89ac6
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Reshape.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Reshape.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Reshape::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Reshape::Reshape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param(param)
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ResizeBilinear.cc b/runtime/onert/core/src/ir/operation/ResizeBilinear.cc
new file mode 100644
index 000000000..71925bb44
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ResizeBilinear.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ResizeBilinear.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ResizeBilinear::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ResizeBilinear::ResizeBilinear(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createInRange(1u, 2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/ResizeNearestNeighbor.cc b/runtime/onert/core/src/ir/operation/ResizeNearestNeighbor.cc
new file mode 100644
index 000000000..98d0b5f26
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/ResizeNearestNeighbor.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/ResizeNearestNeighbor.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void ResizeNearestNeighbor::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ResizeNearestNeighbor::ResizeNearestNeighbor(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createInRange(1u, 2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Reverse.cc b/runtime/onert/core/src/ir/operation/Reverse.cc
new file mode 100644
index 000000000..4b3c1e1af
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Reverse.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Reverse.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Reverse::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Reverse::Reverse(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Select.cc b/runtime/onert/core/src/ir/operation/Select.cc
new file mode 100644
index 000000000..1f22b5234
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Select.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Select.h"
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Select::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Select::Select(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Shape.cc b/runtime/onert/core/src/ir/operation/Shape.cc
new file mode 100644
index 000000000..2a63d6dcf
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Shape.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Shape.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Shape::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Shape::Shape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Slice.cc b/runtime/onert/core/src/ir/operation/Slice.cc
new file mode 100644
index 000000000..888b563fb
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Slice.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Slice.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Slice::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Slice::Slice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Softmax.cc b/runtime/onert/core/src/ir/operation/Softmax.cc
new file mode 100644
index 000000000..3f1aa0af1
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Softmax.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Softmax.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Softmax::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Softmax::Softmax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/SpaceToBatchND.cc b/runtime/onert/core/src/ir/operation/SpaceToBatchND.cc
new file mode 100644
index 000000000..53fab4fa9
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/SpaceToBatchND.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/SpaceToBatchND.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void SpaceToBatchND::accept(OperationVisitor &v) const { v.visit(*this); }
+
+SpaceToBatchND::SpaceToBatchND(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/SpaceToDepth.cc b/runtime/onert/core/src/ir/operation/SpaceToDepth.cc
new file mode 100644
index 000000000..d8a45aee5
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/SpaceToDepth.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/SpaceToDepth.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void SpaceToDepth::accept(OperationVisitor &v) const { v.visit(*this); }
+
+SpaceToDepth::SpaceToDepth(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Split.cc b/runtime/onert/core/src/ir/operation/Split.cc
new file mode 100644
index 000000000..b538e9206
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Split.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ir/operation/Split.h"
+#include <cassert>
+#include "ir/OperationVisitor.h"
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+void Split::accept(OperationVisitor &v) const { v.visit(*this); }
+Split::Split(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/SplitV.cc b/runtime/onert/core/src/ir/operation/SplitV.cc
new file mode 100644
index 000000000..e638c9ac9
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/SplitV.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ir/operation/SplitV.h"
+#include <cassert>
+#include "ir/OperationVisitor.h"
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+void SplitV::accept(OperationVisitor &v) const { v.visit(*this); }
+SplitV::SplitV(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param}
+{
+}
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/SquaredDifference.cc b/runtime/onert/core/src/ir/operation/SquaredDifference.cc
new file mode 100644
index 000000000..49e58aaf2
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/SquaredDifference.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/SquaredDifference.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void SquaredDifference::accept(OperationVisitor &v) const { v.visit(*this); }
+
+SquaredDifference::SquaredDifference(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Squeeze.cc b/runtime/onert/core/src/ir/operation/Squeeze.cc
new file mode 100644
index 000000000..8cf928fb4
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Squeeze.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Squeeze.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Squeeze::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Squeeze::Squeeze(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param(param)
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/StatelessRandomUniform.cc b/runtime/onert/core/src/ir/operation/StatelessRandomUniform.cc
new file mode 100644
index 000000000..cbb0ff251
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/StatelessRandomUniform.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/StatelessRandomUniform.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+void StatelessRandomUniform::accept(OperationVisitor &v) const { v.visit(*this); }
+
+StatelessRandomUniform::StatelessRandomUniform(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/StridedSlice.cc b/runtime/onert/core/src/ir/operation/StridedSlice.cc
new file mode 100644
index 000000000..2a7905995
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/StridedSlice.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/StridedSlice.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void StridedSlice::accept(OperationVisitor &v) const { v.visit(*this); }
+
+StridedSlice::StridedSlice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(4u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Tile.cc b/runtime/onert/core/src/ir/operation/Tile.cc
new file mode 100644
index 000000000..5ba3df2ad
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Tile.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Tile.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Tile::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Tile::Tile(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/TopKV2.cc b/runtime/onert/core/src/ir/operation/TopKV2.cc
new file mode 100644
index 000000000..a5e6c6a85
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/TopKV2.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/TopKV2.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void TopKV2::accept(OperationVisitor &v) const { v.visit(*this); }
+
+TopKV2::TopKV2(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Transpose.cc b/runtime/onert/core/src/ir/operation/Transpose.cc
new file mode 100644
index 000000000..997f98ab0
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Transpose.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Transpose.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void Transpose::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Transpose::Transpose(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/TransposeConv.cc b/runtime/onert/core/src/ir/operation/TransposeConv.cc
new file mode 100644
index 000000000..7f29ca44e
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/TransposeConv.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/TransposeConv.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+
+void TransposeConv::accept(OperationVisitor &v) const { v.visit(*this); }
+
+TransposeConv::TransposeConv(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/Unpack.cc b/runtime/onert/core/src/ir/operation/Unpack.cc
new file mode 100644
index 000000000..67aa54ab5
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/Unpack.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ir/operation/Unpack.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+void Unpack::accept(OperationVisitor &v) const { v.visit(*this); }
+Unpack::Unpack(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/operation/While.cc b/runtime/onert/core/src/ir/operation/While.cc
new file mode 100644
index 000000000..2505c60e3
--- /dev/null
+++ b/runtime/onert/core/src/ir/operation/While.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ir/operation/While.h"
+#include "ir/OperationVisitor.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace operation
+{
+void While::accept(OperationVisitor &v) const { v.visit(*this); }
+While::While(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createAny(), inputs, outputs}, _param{param}
+{
+}
+} // namespace operation
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/verifier/Verifier.cc b/runtime/onert/core/src/ir/verifier/Verifier.cc
new file mode 100644
index 000000000..7d05acb28
--- /dev/null
+++ b/runtime/onert/core/src/ir/verifier/Verifier.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Verifier.h"
+
+#include "ir/Graph.h"
+#include "ir/OperationIndexMap.h"
+
+#include "util/logging.h"
+
+namespace onert
+{
+namespace ir
+{
+namespace verifier
+{
+
+//
+// DAGChecker
+//
+
+bool DAGChecker::verify(const Graph &graph) const noexcept
+{
+ auto &operations = graph.operations();
+ bool cyclic = false;
+
+ OperationIndexMap<bool> visited;
+ operations.iterate(
+ [&](const OperationIndex &index, const Operation &) { visited[index] = false; });
+ OperationIndexMap<bool> on_stack = visited; // Copy from visited
+
+ std::function<void(const OperationIndex &index, const Operation &)> dfs_recursive =
+ [&](const OperationIndex &index, const Operation &node) -> void {
+ if (on_stack[index])
+ cyclic = true;
+ if (visited[index])
+ return;
+ visited[index] = true;
+ on_stack[index] = true;
+
+ for (auto output : node.getOutputs() | Remove::DUPLICATED | Remove::UNDEFINED)
+ {
+ const auto &operand = graph.operands().at(output);
+ for (const auto &use : operand.getUses())
+ {
+ dfs_recursive(use, graph.operations().at(use));
+ }
+ }
+
+ on_stack[index] = false;
+ };
+
+ operations.iterate(dfs_recursive);
+
+ return !cyclic;
+}
+
+//
+// EdgeConsistencyVerifier
+//
+
+bool EdgeConsistencyChecker::verify(const Graph &graph) const noexcept
+{
+ auto &operations = graph.operations();
+ uint32_t errors = 0;
+ operations.iterate([&](const OperationIndex &index, const Operation &node) {
+ for (auto operand_index : node.getInputs() | ir::Remove::UNDEFINED)
+ {
+ try
+ {
+ auto &operand = graph.operands().at(operand_index);
+ bool operand_has_use = operand.getUses().contains(index);
+ if (!operand_has_use)
+ {
+ VERBOSE(EdgeConsistencyChecker) << "[ERROR] EDGE MISMATCH : Missing USE edge - Operand "
+ << operand_index << " to Operation " << index
+ << std::endl;
+ errors += 1;
+ }
+ }
+ catch (const std::out_of_range &e)
+ {
+ VERBOSE(EdgeConsistencyChecker)
+ << "[ERROR] OPEARAND NOT FOUND : Operation " << index << " has Operand "
+ << operand_index << ", but the operand object is not present in the graph" << std::endl;
+ errors += 1;
+ }
+ }
+ for (auto operand_index : node.getOutputs() | ir::Remove::UNDEFINED)
+ {
+ try
+ {
+ auto &operand = graph.operands().at(operand_index);
+ if (operand.getDef() != index)
+ {
+ VERBOSE(EdgeConsistencyChecker) << "[ERROR] EDGE MISMATCH : Missing DEF edge - Operand"
+ << operand_index << " to Operation " << index
+ << std::endl;
+ errors += 1;
+ }
+ }
+ catch (const std::out_of_range &e)
+ {
+ VERBOSE(EdgeConsistencyChecker)
+ << "[ERROR] OPEARAND NOT FOUND : Operation " << index << " has Operand "
+ << operand_index << ", but the operand object is not present in the graph" << std::endl;
+ errors += 1;
+ }
+ }
+ });
+
+ VERBOSE(EdgeConsistencyChecker) << "Total Number of errors : " << errors << std::endl;
+
+ return errors == 0;
+}
+
+bool InputOutputChecker::verify(const Graph &graph) const noexcept
+{
+ for (auto operand_ind :
+ (graph.getInputs() + graph.getOutputs()) | Remove::DUPLICATED | Remove::UNDEFINED)
+ {
+ if (!graph.operands().exist(operand_ind))
+ {
+ VERBOSE(InputOutputChecker) << "Input or Output tensor " << operand_ind << " does not exist.";
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace verifier
+} // namespace ir
+} // namespace onert
diff --git a/runtime/onert/core/src/ir/verifier/Verifier.h b/runtime/onert/core/src/ir/verifier/Verifier.h
new file mode 100644
index 000000000..143db343a
--- /dev/null
+++ b/runtime/onert/core/src/ir/verifier/Verifier.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_GRAPH_VERIFIER_VERIFIER_H__
+#define __ONERT_GRAPH_VERIFIER_VERIFIER_H__
+
+namespace onert
+{
+namespace ir
+{
+class Graph;
+} // namespace ir
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+namespace verifier
+{
+
+struct IVerifier
+{
+ virtual ~IVerifier() = default;
+ virtual bool verify(const Graph &graph) const noexcept = 0;
+};
+
+} // namespace verifier
+} // namespace ir
+} // namespace onert
+
+namespace onert
+{
+namespace ir
+{
+namespace verifier
+{
+
+class DAGChecker : public IVerifier
+{
+public:
+ bool verify(const Graph &graph) const noexcept override;
+};
+
+class EdgeConsistencyChecker : public IVerifier
+{
+public:
+ bool verify(const Graph &graph) const noexcept override;
+};
+
+/**
+ * @brief Check model input and output operands are really exist in the graph
+ */
+class InputOutputChecker : public IVerifier
+{
+public:
+ bool verify(const Graph &graph) const noexcept override;
+};
+
+} // namespace verifier
+} // namespace ir
+} // namespace onert
+
+#endif // __ONERT_GRAPH_VERIFIER_VERIFIER_H__
diff --git a/runtime/onert/core/src/library_info.cc b/runtime/onert/core/src/library_info.cc
new file mode 100644
index 000000000..6d7579cca
--- /dev/null
+++ b/runtime/onert/core/src/library_info.cc
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+volatile const char info[] = "library information : runtime=onert";
diff --git a/runtime/onert/core/src/util/ConfigSource.cc b/runtime/onert/core/src/util/ConfigSource.cc
new file mode 100644
index 000000000..45cce662e
--- /dev/null
+++ b/runtime/onert/core/src/util/ConfigSource.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/ConfigSource.h"
+#include "util/GeneralConfigSource.h"
+#include "util/EnvConfigSource.h"
+
+#include <array>
+#include <algorithm>
+#include <cassert>
+
+#include <memory>
+
+namespace onert
+{
+namespace util
+{
+
+static std::unique_ptr<IConfigSource> _source;
+
+void config_source(std::unique_ptr<IConfigSource> &&source) { _source = std::move(source); }
+
+static IConfigSource *config_source()
+{
+ if (!_source)
+ {
+#ifdef ENVVAR_FOR_DEFAULT_CONFIG
+ // Default ConfigSource is EnvConfigSource
+ _source = std::make_unique<EnvConfigSource>();
+#else
+ _source = std::make_unique<GeneralConfigSource>();
+#endif // ENVVAR_FOR_DEFAULT_CONFIG
+ }
+ return _source.get();
+}
+
+static std::string getConfigOrDefault(const std::string &key)
+{
+ static std::unordered_map<std::string, std::string> defaults;
+ if (defaults.empty())
+ {
+#define CONFIG(Name, Type, Default) \
+ { \
+ auto name = std::string{#Name}; \
+ defaults.emplace(name, std::string{Default}); \
+ }
+
+#include "util/Config.lst"
+
+#undef CONFIG
+ }
+
+ // Treat empty string and absence of the value to be the same
+ auto ret = config_source()->get(key);
+ if (ret.empty())
+ {
+ auto itr = defaults.find(key);
+ if (itr != defaults.end())
+ {
+ // Return the default value if exists
+ ret = itr->second;
+ }
+ }
+
+ return ret;
+}
+
+bool toBool(const std::string &val)
+{
+ static const std::array<std::string, 5> false_list{"0", "OFF", "FALSE", "N", "NO"};
+ auto false_found = std::find(false_list.begin(), false_list.end(), val);
+ return false_found == false_list.end();
+}
+
+int toInt(const std::string &val) { return std::stoi(val); }
+
+bool getConfigBool(const std::string &key)
+{
+ auto raw = getConfigOrDefault(key);
+ return toBool(raw);
+}
+
+int getConfigInt(const std::string &key)
+{
+ auto raw = getConfigOrDefault(key);
+ return toInt(raw);
+}
+
+std::string getConfigString(const std::string &key) { return getConfigOrDefault(key); }
+
+} // namespace util
+} // namespace onert
+
+namespace onert
+{
+namespace util
+{
+namespace config
+{
+
+#define CONFIG(Name, Type, Default) const char *Name = #Name;
+
+#include "util/Config.lst"
+
+#undef CONFIG
+
+} // namespace config
+} // namespace util
+} // namespace onert
diff --git a/runtime/onert/core/src/util/EnvConfigSource.cc b/runtime/onert/core/src/util/EnvConfigSource.cc
new file mode 100644
index 000000000..0d25b7353
--- /dev/null
+++ b/runtime/onert/core/src/util/EnvConfigSource.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/EnvConfigSource.h"
+
+#include <cstdlib>
+
+namespace onert
+{
+namespace util
+{
+
+std::string EnvConfigSource::get(const std::string &key) const
+{
+ const char *value = std::getenv(key.c_str());
+ if (value != nullptr)
+ {
+ return value;
+ }
+ else
+ {
+ return GeneralConfigSource::get(key);
+ }
+}
+
+} // namespace util
+} // namespace onert
diff --git a/runtime/onert/core/src/util/EventCollector.cc b/runtime/onert/core/src/util/EventCollector.cc
new file mode 100644
index 000000000..de37276bf
--- /dev/null
+++ b/runtime/onert/core/src/util/EventCollector.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/EventCollector.h"
+
+// C++ standard libraries
+#include <chrono>
+
+// POSIX standard libraries
+#include <sys/time.h>
+#include <sys/resource.h>
+
+namespace
+{
+
+std::string timestamp(void)
+{
+ auto now = std::chrono::steady_clock::now();
+ return std::to_string(
+ std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count());
+}
+
+class DurationEventBuilder
+{
+public:
+ DurationEventBuilder(const std::string &ts) : _ts{ts} {}
+
+ DurationEvent build(const std::string &tid, const std::string &name, const std::string &ph) const
+ {
+ DurationEvent evt;
+
+ evt.name = name;
+ evt.tid = tid;
+ evt.ph = ph;
+ evt.ts = _ts;
+
+ return evt;
+ }
+
+private:
+ std::string _ts;
+};
+
+#ifdef DEBUG
+inline void emit_rusage(EventRecorder *rec, const std::string &ts)
+{
+ struct rusage ru;
+
+ getrusage(RUSAGE_SELF, &ru);
+ {
+ CounterEvent evt;
+
+ evt.name = "maxrss";
+ evt.ph = "C";
+ evt.ts = ts;
+ evt.values["value"] = std::to_string(ru.ru_maxrss);
+
+ rec->emit(evt);
+ }
+
+ {
+ CounterEvent evt;
+
+ evt.name = "minflt";
+ evt.ph = "C";
+ evt.ts = ts;
+ evt.values["value"] = std::to_string(ru.ru_minflt);
+
+ rec->emit(evt);
+ }
+}
+#endif
+
+} // namespace
+
+void EventCollector::onEvent(const Event &event)
+{
+ auto ts = timestamp();
+
+ switch (event.edge)
+ {
+ case Edge::BEGIN:
+ _rec->emit(DurationEventBuilder(ts).build(event.backend, event.label, "B"));
+ break;
+
+ case Edge::END:
+ _rec->emit(DurationEventBuilder(ts).build(event.backend, event.label, "E"));
+ break;
+ }
+
+// TODO: Add resurece measurement(e.g. RSS)
+// when ready with low overhead in release build
+#ifdef DEBUG
+ emit_rusage(_rec, ts);
+#endif
+}
diff --git a/runtime/onert/core/src/util/EventCollector.h b/runtime/onert/core/src/util/EventCollector.h
new file mode 100644
index 000000000..8154be592
--- /dev/null
+++ b/runtime/onert/core/src/util/EventCollector.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_EVENT_COLLECTOR_H__
+#define __ONERT_UTIL_EVENT_COLLECTOR_H__
+
+#include "util/EventRecorder.h"
+
+class EventCollector
+{
+public:
+ enum class Edge
+ {
+ BEGIN,
+ END
+ };
+
+ struct Event
+ {
+ Edge edge;
+ std::string backend;
+ std::string label;
+ };
+
+public:
+ EventCollector(EventRecorder *rec) : _rec{rec}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void onEvent(const Event &event);
+
+protected:
+ EventRecorder *_rec;
+};
+
+#endif // __ONERT_UTIL_EVENT_COLLECTOR_H__
diff --git a/runtime/onert/core/src/util/EventCollectorGlobal.cc b/runtime/onert/core/src/util/EventCollectorGlobal.cc
new file mode 100644
index 000000000..6c03a5b9a
--- /dev/null
+++ b/runtime/onert/core/src/util/EventCollectorGlobal.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/EventCollectorGlobal.h"
+
+#include <cassert>
+#include <fstream>
+#include <iostream>
+
+#include "util/ConfigSource.h"
+#include "util/EventWriter.h"
+
+namespace onert
+{
+namespace util
+{
+
+EventCollectorGlobal::EventCollectorGlobal() : _recorder{}, _collector{&_recorder}
+{
+ // DO NOTHING
+}
+
+EventCollectorGlobal::~EventCollectorGlobal()
+{
+ if (!_recorder.empty())
+ {
+ try
+ {
+ // TODO Need better way for saved file path than the hardcoded path
+ EventWriter{_recorder}.writeToFile("trace.global.json",
+ EventWriter::WriteFormat::CHROME_TRACING);
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << "E: Fail to record event in EventCollectorGlobal: " << e.what() << std::endl;
+ }
+ }
+}
+
+EventCollectorGlobal &EventCollectorGlobal::get()
+{
+ static EventCollectorGlobal instance;
+ return instance;
+}
+
+EventDurationBlock::EventDurationBlock(const std::string &tag) : _tag{tag}
+{
+ auto &glob = EventCollectorGlobal::get();
+ glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "0", _tag});
+}
+EventDurationBlock::~EventDurationBlock()
+{
+ auto &glob = EventCollectorGlobal::get();
+ glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::END, "0", _tag});
+}
+
+EventDurationManual::EventDurationManual(const std::string &tag) : _tag{tag}, _pair{true} {}
+
+EventDurationManual::~EventDurationManual()
+{
+ // Check if it has called begin-end pair
+ assert(_pair);
+}
+
+void EventDurationManual::begin()
+{
+ _pair = false;
+ auto &glob = EventCollectorGlobal::get();
+ glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "0", _tag});
+}
+
+void EventDurationManual::end()
+{
+ assert(!_pair);
+ _pair = true;
+ auto &glob = EventCollectorGlobal::get();
+ glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::END, "0", _tag});
+}
+
+} // namespace util
+} // namespace onert
diff --git a/runtime/onert/core/src/util/EventCollectorGlobal.h b/runtime/onert/core/src/util/EventCollectorGlobal.h
new file mode 100644
index 000000000..1027ec84d
--- /dev/null
+++ b/runtime/onert/core/src/util/EventCollectorGlobal.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_EVENT_COLLECTOR_GLOBAL_H__
+#define __ONERT_UTIL_EVENT_COLLECTOR_GLOBAL_H__
+
+#include "util/EventRecorder.h"
+#include "util/EventCollector.h"
+
+namespace onert
+{
+namespace util
+{
+
+/**
+ * @brief Singleton class for event collection from anywhere in code
+ *
+ */
+class EventCollectorGlobal
+{
+public:
+ /**
+ * @brief Get the singleton object of this class
+ *
+ * @return EventCollectorGlobal& Singleton object
+ */
+ static EventCollectorGlobal &get();
+
+public:
+ /**
+ * @brief Getter for event collector object
+ *
+ * @return EventCollector& Collector object
+ */
+ EventCollector &collector() { return _collector; }
+
+private:
+ EventCollectorGlobal();
+ ~EventCollectorGlobal();
+
+private:
+ EventRecorder _recorder;
+ EventCollector _collector;
+};
+
+/**
+ * @brief Helper class for emitting duration event which is handled automatically with ctor/dtor
+ *
+ */
+class EventDurationBlock
+{
+public:
+ /**
+ * @brief Raise a duration event with type of BEGIN
+ *
+ * @param tag A label for the duration event
+ */
+ EventDurationBlock(const std::string &tag);
+ /**
+ * @brief Raise a duration event with type of END
+ *
+ */
+ ~EventDurationBlock();
+
+private:
+ std::string _tag;
+};
+
+/**
+ * @brief Helper class for emitting duration event which is handled manually
+ *
+ * Usage:
+ * {
+ * ...
+ * EventDurationManual duration("some tag");
+ * duration.begin();
+ * ...
+ * ... // Code for duration
+ * ...
+ * duration.end();
+ * }
+ *
+ */
+class EventDurationManual
+{
+public:
+ /**
+ * @brief Construct a new Event Duration Manual object
+ *
+ * @param tag A label for the duration object
+ */
+ EventDurationManual(const std::string &tag);
+ /**
+ * @brief Destroy the Event Duration Manual object
+ *
+ */
+ ~EventDurationManual();
+
+ /**
+ * @brief Raise a duration event with type of BEGIN
+ *
+ */
+ void begin();
+ /**
+ * @brief Raise a duration event with type of END
+ *
+ */
+ void end();
+
+private:
+ std::string _tag;
+ bool _pair;
+};
+
+} // namespace util
+} // namespace onert
+
+/**
+ * Helper Macro Definitions
+ *
+ * HOW TO USE
+ *
+ * void f(args)
+ * {
+ * EVENT_DURATION_FUNCTION();
+ * ...
+ * if(cond)
+ * {
+ * EVENT_DURATION_REGION("if branch");
+ * ...
+ * }
+ * ...
+ * }
+ */
+
+#define EVENT_DURATION_FUNCTION() \
+ ::onert::util::EventDurationBlock __event_duration__##__LINE__ { __FUNCTION__ }
+
+#define EVENT_DURATION_REGION(tag) \
+ ::onert::util::EventDurationBlock __event_duration__##__LINE__ { tag }
+
+#endif // __ONERT_UTIL_EVENT_COLLECTOR_GLOBAL_H__
diff --git a/runtime/onert/core/src/util/EventRecorder.cc b/runtime/onert/core/src/util/EventRecorder.cc
new file mode 100644
index 000000000..3714e4f02
--- /dev/null
+++ b/runtime/onert/core/src/util/EventRecorder.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/EventRecorder.h"
+
+void EventRecorder::emit(const DurationEvent &evt)
+{
+ std::lock_guard<std::mutex> lock{_mu};
+
+ _duration_events.push_back(evt);
+}
+
+void EventRecorder::emit(const CounterEvent &evt)
+{
+ std::lock_guard<std::mutex> lock{_mu};
+
+ _counter_events.push_back(evt);
+}
diff --git a/runtime/onert/core/src/util/EventRecorder.h b/runtime/onert/core/src/util/EventRecorder.h
new file mode 100644
index 000000000..7af4c7ddb
--- /dev/null
+++ b/runtime/onert/core/src/util/EventRecorder.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_EVENT_RECORDER_H__
+#define __ONERT_UTIL_EVENT_RECORDER_H__
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+#include <vector>
+
+struct Event
+{
+ std::string name;
+ std::string tid;
+ std::string ph; /* REQUIRED */
+ std::string ts; /* REQUIRED */
+};
+
+struct DurationEvent : public Event
+{
+ // TO BE FILLED
+};
+
+struct CounterEvent : public Event
+{
+ std::map<std::string, std::string> values;
+};
+
+//
+// Record Event as Chrome Trace Event File Format
+//
+// Refrence: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit
+//
+class EventRecorder
+{
+public:
+ EventRecorder() = default;
+
+public:
+ void emit(const DurationEvent &evt);
+ void emit(const CounterEvent &evt);
+
+public:
+ bool empty() { return _duration_events.empty() && _counter_events.empty(); }
+ const std::vector<DurationEvent> &duration_events() const { return _duration_events; }
+ const std::vector<CounterEvent> &counter_events() const { return _counter_events; }
+
+private:
+ std::mutex _mu;
+ std::vector<DurationEvent> _duration_events;
+ std::vector<CounterEvent> _counter_events;
+};
+
+#endif // __ONERT_UTIL_EVENT_RECORDER_H__
diff --git a/runtime/onert/core/src/util/EventWriter.cc b/runtime/onert/core/src/util/EventWriter.cc
new file mode 100644
index 000000000..dacb40e64
--- /dev/null
+++ b/runtime/onert/core/src/util/EventWriter.cc
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/EventWriter.h"
+
+#include <sstream>
+#include <vector>
+#include <unordered_map>
+#include <json/json.h>
+#include <assert.h>
+#include <utility>
+#include <map>
+#include <set>
+#include <stdint.h>
+#include <fstream>
+
+// json type for Chrome Event Trace
+namespace
+{
+
+std::string quote(const std::string &value)
+{
+ std::stringstream ss;
+ ss << '"' << value << '"';
+ return ss.str();
+}
+
+std::string field(const std::string &k, const std::string &v)
+{
+ std::stringstream ss;
+ ss << quote(k) << " : " << quote(v);
+ return ss.str();
+}
+
+struct Content // One Entry in Chrome Event Trace
+{
+ std::vector<std::pair<std::string, std::string>> flds;
+ std::vector<std::pair<std::string, std::string>> args;
+};
+
+std::string object(const Content &content)
+{
+ std::stringstream ss;
+
+ ss << "{ ";
+
+ ss << field(content.flds[0].first, content.flds[0].second);
+
+ for (uint32_t n = 1; n < content.flds.size(); ++n)
+ {
+ ss << ", " << field(content.flds.at(n).first, content.flds.at(n).second);
+ }
+
+ if (content.args.size() > 0)
+ {
+ ss << ", " << quote("args") << " : { ";
+ ss << field(content.args.at(0).first, content.args.at(0).second);
+
+ for (uint32_t n = 1; n < content.args.size(); ++n)
+ {
+ ss << ", " << field(content.args.at(n).first, content.args.at(n).second);
+ }
+
+ ss << "}";
+ }
+
+ ss << " }";
+
+ return ss.str();
+}
+
+void fill(Content &content, const Event &evt)
+{
+ content.flds.emplace_back("name", evt.name);
+ content.flds.emplace_back("pid", "0");
+ content.flds.emplace_back("tid", evt.tid);
+ content.flds.emplace_back("ph", evt.ph);
+ content.flds.emplace_back("ts", evt.ts);
+}
+
+std::string object(const DurationEvent &evt)
+{
+ Content content;
+
+ fill(content, evt);
+
+ return ::object(content);
+}
+
+std::string object(const CounterEvent &evt)
+{
+ Content content;
+
+ fill(content, evt);
+
+ for (auto it = evt.values.begin(); it != evt.values.end(); ++it)
+ {
+ content.args.emplace_back(it->first, it->second);
+ }
+
+ return ::object(content);
+}
+
+} // namespace
+
+// md table type
+namespace
+{
+
+void writeMDTableRow(std::ostream &os, const std::vector<std::string> &list)
+{
+ os << "| ";
+ for (auto &key : list)
+ {
+ os << key << " | ";
+ }
+ os << "\n";
+}
+
+struct MDContent
+{
+ std::string name;
+ uint64_t begin_ts;
+ uint64_t end_ts;
+ uint32_t min_rss;
+ uint32_t max_rss;
+ uint32_t min_page_reclaims;
+ uint32_t max_page_reclaims;
+
+ MDContent()
+ : begin_ts(0), end_ts(0), min_rss(UINT32_MAX), max_rss(0), min_page_reclaims(UINT32_MAX),
+ max_page_reclaims(0)
+ {
+ // DO NOTHING
+ }
+
+ virtual ~MDContent() = default;
+
+ void updateRss(uint32_t rss)
+ {
+ if (min_rss == UINT32_MAX)
+ min_rss = rss;
+ if (max_rss == 0)
+ max_rss = rss;
+
+ if (min_rss > rss)
+ min_rss = rss;
+ else if (max_rss < rss)
+ max_rss = rss;
+ }
+
+ void updateMinflt(uint32_t minflt)
+ {
+ if (min_page_reclaims == UINT32_MAX)
+ min_page_reclaims = minflt;
+ if (max_page_reclaims == 0)
+ max_page_reclaims = minflt;
+
+ if (min_page_reclaims > minflt)
+ min_page_reclaims = minflt;
+ else if (max_page_reclaims < minflt)
+ max_page_reclaims = minflt;
+ }
+
+ virtual void write(std::ostream &os) const = 0;
+};
+
+struct OpSeq : public MDContent
+{
+ std::string backend;
+ uint64_t graph_latency;
+
+ struct OpSeqCmp
+ {
+ bool operator()(const OpSeq &lhs, const OpSeq &rhs) const
+ {
+ return lhs.begin_ts < rhs.begin_ts;
+ }
+ bool operator()(const OpSeq &lhs, const OpSeq &rhs) { return lhs.begin_ts < rhs.begin_ts; }
+ bool operator()(OpSeq &lhs, OpSeq &rhs) { return lhs.begin_ts < rhs.begin_ts; }
+ };
+
+ void write(std::ostream &os) const override
+ {
+ uint64_t opseq_latency = end_ts - begin_ts;
+ double opseq_per = static_cast<double>(opseq_latency) / graph_latency * 100.0;
+ writeMDTableRow(os, {name, backend, std::to_string(opseq_latency), std::to_string(opseq_per),
+ std::to_string(min_rss), std::to_string(max_rss),
+ std::to_string(min_page_reclaims), std::to_string(max_page_reclaims)});
+ }
+};
+
+struct Graph : public MDContent
+{
+ std::set<OpSeq, OpSeq::OpSeqCmp> opseqs;
+
+ void setOpSeqs(const std::map<std::string, OpSeq> &name_to_opseq)
+ {
+ uint64_t graph_latency = end_ts - begin_ts;
+ for (auto it : name_to_opseq)
+ {
+ auto opseq = it.second;
+ opseq.graph_latency = graph_latency;
+
+ opseqs.insert(opseq);
+
+ updateRss(opseq.min_rss);
+ updateRss(opseq.max_rss);
+ updateMinflt(opseq.min_page_reclaims);
+ updateMinflt(opseq.max_page_reclaims);
+ }
+ }
+
+ void write(std::ostream &os) const override
+ {
+ static std::vector<std::string> graph_headers{"latency(us)", "rss_min(kb)", "rss_max(kb)",
+ "page_reclaims_min", "page_reclaims_max"};
+
+ static std::vector<std::string> graph_headers_line{"-----------", "-------", "-------",
+ "-----------------", "-----------------"};
+
+ // Graph's Header
+ writeMDTableRow(os, graph_headers);
+ writeMDTableRow(os, graph_headers_line);
+
+ // Graph's contents
+ writeMDTableRow(os, {std::to_string(end_ts - begin_ts), std::to_string(min_rss),
+ std::to_string(max_rss), std::to_string(min_page_reclaims),
+ std::to_string(max_page_reclaims)});
+
+ os << "\n";
+
+ static std::vector<std::string> opseq_headers{
+ "OpSeq name", "backend", "latency(us)", "latency(%)",
+ "rss_min(kb)", "rss_max(kb)", "page_reclaims_min", "page_reclaims_max"};
+
+ static std::vector<std::string> opseq_headers_line{
+ "----------", "-------", "-----------", "-----------",
+ "-------", "-------", "-----------------", "-----------------"};
+
+ os << "## OpSequences \n";
+
+ // OpSeq's Header
+ writeMDTableRow(os, opseq_headers);
+ writeMDTableRow(os, opseq_headers_line);
+
+ // OpSeq's contents
+ for (auto opseq : opseqs)
+ {
+ opseq.write(os);
+ }
+
+ os << "\n";
+ }
+};
+
+struct MDTableBuilder
+{
+ MDTableBuilder(const std::vector<DurationEvent> &duration_events,
+ const std::vector<CounterEvent> &counter_events)
+ : _duration_events(duration_events), _counter_events(counter_events)
+ {
+// when ready with low overhead in release build
+#ifdef DEBUG
+ for (const auto &evt : _counter_events)
+ {
+ uint64_t ts = std::stoull(evt.ts);
+ auto &name = evt.name;
+ assert(name.compare("maxrss") == 0 || name.compare("minflt") == 0);
+ assert(evt.values.size() == 1);
+ auto &val = evt.values.begin()->second;
+ if (_ts_to_values.find(ts) == _ts_to_values.end())
+ {
+ std::pair<uint32_t, uint32_t> values;
+ if (name.compare("maxrss") == 0)
+ values.first = std::stoul(val);
+ else
+ values.second = std::stoul(val);
+ _ts_to_values.insert({ts, values});
+ }
+ else
+ {
+ auto &values = _ts_to_values.at(ts);
+ if (name.compare("maxrss") == 0)
+ values.first = std::stoul(val);
+ else
+ values.second = std::stoul(val);
+ }
+ }
+#endif
+ }
+
+ MDTableBuilder &build()
+ {
+ for (auto &it : divideGraph())
+ {
+ size_t begin_idx = it.first;
+ size_t end_idx = it.second;
+ std::map<std::string, OpSeq> name_to_opseq;
+ for (size_t i = begin_idx + 1; i < end_idx; ++i)
+ {
+ const auto &evt = _duration_events[i];
+ assert(evt.name.compare("Graph") != 0);
+ assert(evt.ph.compare("B") == 0 || evt.ph.compare("E") == 0);
+ if (evt.ph.compare("B") == 0)
+ {
+ assert(name_to_opseq.find(evt.name) == name_to_opseq.end());
+ name_to_opseq.insert({evt.name, makeOpSeq(evt)});
+ }
+ else
+ {
+ assert(name_to_opseq.find(evt.name) != name_to_opseq.end());
+ auto &opseq = name_to_opseq.at(evt.name);
+ updateOpSeq(opseq, evt);
+ }
+ }
+
+ _graphs.emplace_back(makeGraph(begin_idx, end_idx, name_to_opseq));
+ }
+
+ return *this;
+ }
+
+ std::vector<std::pair<size_t, size_t>> divideGraph()
+ {
+ std::vector<std::pair<size_t, size_t>> graph_idx_list; // pair<begin_idx, end_idx>
+ for (size_t i = 0, begin_idx = 0; i < _duration_events.size(); ++i)
+ {
+ const auto &evt = _duration_events.at(i);
+ if (evt.name.compare("Graph") == 0)
+ {
+ if (evt.ph.compare("B") == 0)
+ begin_idx = i;
+ else
+ graph_idx_list.emplace_back(begin_idx, i);
+ }
+ }
+ return graph_idx_list;
+ }
+
+ OpSeq makeOpSeq(const DurationEvent &evt)
+ {
+ OpSeq opseq;
+ opseq.name = evt.name;
+ opseq.begin_ts = std::stoull(evt.ts);
+ opseq.backend = evt.tid;
+#ifdef DEBUG
+ opseq.updateRss(_ts_to_values.at(opseq.begin_ts).first);
+ opseq.updateMinflt(_ts_to_values.at(opseq.begin_ts).second);
+#else
+ opseq.updateRss(0);
+ opseq.updateMinflt(0);
+#endif
+ return opseq;
+ }
+
+ void updateOpSeq(OpSeq &opseq, const DurationEvent &evt)
+ {
+ opseq.end_ts = std::stoull(evt.ts);
+#ifdef DEBUG
+ opseq.updateRss(_ts_to_values.at(opseq.end_ts).first);
+ opseq.updateMinflt(_ts_to_values.at(opseq.end_ts).second);
+#else
+ opseq.updateRss(0);
+ opseq.updateMinflt(0);
+#endif
+ }
+
+ Graph makeGraph(size_t begin_idx, size_t end_idx,
+ const std::map<std::string, OpSeq> &name_to_opseq)
+ {
+ Graph graph;
+ graph.name = "Graph";
+ graph.begin_ts = std::stoull(_duration_events[begin_idx].ts);
+ graph.end_ts = std::stoull(_duration_events[end_idx].ts);
+ graph.setOpSeqs(name_to_opseq);
+#ifdef DEBUG
+ graph.updateRss(_ts_to_values.at(graph.begin_ts).first);
+ graph.updateMinflt(_ts_to_values.at(graph.begin_ts).second);
+ graph.updateRss(_ts_to_values.at(graph.end_ts).first);
+ graph.updateMinflt(_ts_to_values.at(graph.end_ts).second);
+#else
+ graph.updateRss(0);
+ graph.updateMinflt(0);
+#endif
+ return graph;
+ }
+
+ void write(std::ostream &os)
+ {
+ // Write contents
+ for (size_t i = 0; i < _graphs.size(); ++i)
+ {
+ os << "# Graph " << i << "\n";
+ _graphs.at(i).write(os);
+ }
+ }
+
+ const std::vector<DurationEvent> &_duration_events;
+ const std::vector<CounterEvent> &_counter_events;
+ // timestamp to std::pair<maxrss, minflt>
+ std::unordered_map<uint64_t, std::pair<uint32_t, uint32_t>> _ts_to_values;
+ std::vector<Graph> _graphs;
+};
+
+} // namespace
+
+EventWriter::EventWriter(const EventRecorder &recorder) : _recorder(recorder)
+{
+ // DO NOTHING
+}
+
+void EventWriter::writeToFiles(const std::string &base_filepath)
+{
+ // Note. According to an internal issue, let snpe json as just file name not '.snpe.json'
+ writeToFile(base_filepath, WriteFormat::SNPE_BENCHMARK);
+ writeToFile(base_filepath + ".chrome.json", WriteFormat::CHROME_TRACING);
+ writeToFile(base_filepath + ".table.md", WriteFormat::MD_TABLE);
+}
+
+void EventWriter::writeToFile(const std::string &filepath, WriteFormat write_format)
+{
+ std::ofstream os{filepath, std::ofstream::out};
+ switch (write_format)
+ {
+ case WriteFormat::CHROME_TRACING:
+ writeChromeTrace(os);
+ break;
+ case WriteFormat::SNPE_BENCHMARK:
+ writeSNPEBenchmark(os);
+ break;
+ case WriteFormat::MD_TABLE:
+ writeMDTable(os);
+ break;
+ default:
+ assert(!"Invalid value");
+ break;
+ }
+}
+
+void EventWriter::writeSNPEBenchmark(std::ostream &os)
+{
+ Json::Value root;
+ auto &exec_data = root["Execution_Data"] = Json::Value{Json::objectValue};
+
+ struct Stat
+ {
+ uint64_t sum = 0;
+ uint64_t count = 0;
+ uint64_t max = 0;
+ uint64_t min = std::numeric_limits<uint64_t>::max();
+
+ void accumulate(uint64_t val)
+ {
+ sum += val;
+ count++;
+ max = std::max(max, val);
+ min = std::min(min, val);
+ }
+ };
+
+ // Memory
+ {
+ std::unordered_map<std::string, Stat> mem_stats;
+ for (auto &evt : _recorder.counter_events())
+ {
+ auto &mem_stat = mem_stats[evt.name];
+ uint64_t val = std::stoull(evt.values.at("value"));
+ mem_stat.accumulate(val);
+ }
+
+ auto &mem = exec_data["memory"] = Json::Value{Json::objectValue};
+ for (auto &kv : mem_stats)
+ {
+ auto &key = kv.first;
+ auto &val = kv.second;
+ mem[key]["Avg_Size"] = val.sum / val.count;
+ mem[key]["Max_Size"] = val.max;
+ mem[key]["Min_Size"] = val.min;
+ mem[key]["Runtime"] = "NA";
+ }
+ }
+
+ // Operation Execution Time
+ {
+ // NOTE This assumes _duration_events is sorted by "ts" ascending
+
+ // 2D keys : stats[tid][name]
+ std::unordered_map<std::string, std::unordered_map<std::string, Stat>> stats;
+ std::unordered_map<std::string, std::unordered_map<std::string, uint64_t>> begin_timestamps;
+ for (auto &evt : _recorder.duration_events())
+ {
+ auto &stat = stats[evt.tid][evt.name];
+ auto &begin_ts = begin_timestamps[evt.tid][evt.name];
+ uint64_t timestamp = std::stoull(evt.ts);
+ if (evt.ph == "B")
+ {
+ if (begin_ts != 0)
+ throw std::runtime_error{"Invalid Data"};
+ begin_ts = timestamp;
+ }
+ else if (evt.ph == "E")
+ {
+ if (begin_ts == 0 || timestamp < begin_ts)
+ throw std::runtime_error{"Invalid Data"};
+ stat.accumulate(timestamp - begin_ts);
+ begin_ts = 0;
+ }
+ else
+ throw std::runtime_error{"Invalid Data - invalid value for \"ph\" : \"" + evt.ph + "\""};
+ }
+
+ for (auto &kv : begin_timestamps)
+ for (auto &kv2 : kv.second)
+ if (kv2.second != 0)
+ throw std::runtime_error{"Invalid Data - B and E pair does not match."};
+
+ for (auto &kv : stats)
+ {
+ auto &tid = kv.first;
+ auto &map = kv.second;
+ auto &json_tid = exec_data[tid] = Json::Value{Json::objectValue};
+ for (auto &kv : map)
+ {
+ auto &name = kv.first;
+ auto &val = kv.second;
+ json_tid[name]["Avg_Time"] = val.sum / val.count;
+ json_tid[name]["Max_Time"] = val.max;
+ json_tid[name]["Min_Time"] = val.min;
+ json_tid[name]["Runtime"] = tid;
+ }
+ }
+ }
+
+ os << root;
+}
+
+void EventWriter::writeChromeTrace(std::ostream &os)
+{
+ os << "{\n";
+ os << " " << quote("traceEvents") << ": [\n";
+
+ for (auto &evt : _recorder.duration_events())
+ {
+ os << " " << object(evt) << ",\n";
+ }
+
+ for (auto &evt : _recorder.counter_events())
+ {
+ os << " " << object(evt) << ",\n";
+ }
+
+ os << " { }\n";
+ os << " ]\n";
+ os << "}\n";
+}
+
+void EventWriter::writeMDTable(std::ostream &os)
+{
+ MDTableBuilder(_recorder.duration_events(), _recorder.counter_events()).build().write(os);
+}
diff --git a/runtime/onert/core/src/util/EventWriter.h b/runtime/onert/core/src/util/EventWriter.h
new file mode 100644
index 000000000..7e838ca82
--- /dev/null
+++ b/runtime/onert/core/src/util/EventWriter.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_UTIL_EVENT_WRITER_H__
+#define __ONERT_UTIL_EVENT_WRITER_H__
+
+#include "EventRecorder.h"
+
+#include <string>
+#include <ostream>
+
+class EventWriter
+{
+public:
+ enum class WriteFormat
+ {
+ CHROME_TRACING,
+ SNPE_BENCHMARK,
+ MD_TABLE,
+ };
+
+public:
+ EventWriter(const EventRecorder &recorder);
+
+public:
+ void writeToFiles(const std::string &base_filepath);
+ void writeToFile(const std::string &filepath, WriteFormat write_format);
+
+private:
+ void writeSNPEBenchmark(std::ostream &os);
+ void writeChromeTrace(std::ostream &os);
+ void writeMDTable(std::ostream &os);
+
+private:
+ const EventRecorder &_recorder;
+};
+
+#endif // __ONERT_UTIL_EVENT_WRITER_H__
diff --git a/runtime/onert/core/src/util/GeneralConfigSource.cc b/runtime/onert/core/src/util/GeneralConfigSource.cc
new file mode 100644
index 000000000..7d2757e58
--- /dev/null
+++ b/runtime/onert/core/src/util/GeneralConfigSource.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/GeneralConfigSource.h"
+#include "util/logging.h"
+
+namespace onert
+{
+namespace util
+{
+
+std::string GeneralConfigSource::get(const std::string &key) const
+{
+ auto itr = _map.find(key);
+ if (itr == _map.end())
+ {
+ return "";
+ }
+ else
+ {
+ return itr->second;
+ }
+}
+
+void GeneralConfigSource::set(const std::string &key, const std::string &val)
+{
+ VERBOSE(GeneralConfigSource) << key << " : " << val << std::endl;
+ _map[key] = val;
+}
+
+} // namespace util
+} // namespace onert
diff --git a/runtime/onert/core/src/util/ShapeInference.cc b/runtime/onert/core/src/util/ShapeInference.cc
new file mode 100644
index 000000000..1f468a8b5
--- /dev/null
+++ b/runtime/onert/core/src/util/ShapeInference.cc
@@ -0,0 +1,1131 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/Utils.h"
+#include "ir/InternalType.h"
+#include "ir/Shape.h"
+#include "util/ShapeInference.h"
+#include "util/logging.h"
+
+#include <cassert>
+#include <numeric>
+#include <sstream>
+#include <cmath>
+
+namespace onert
+{
+namespace shape_inference
+{
+
+//
+// Helper functions
+//
+
+namespace
+{
+
+template <typename T, typename U>
+typename std::enable_if<std::is_integral<T>::value && std::is_integral<U>::value,
+ typename std::common_type<T, U>::type>::type
+ceil_div(T dividend, U divisor)
+{
+ assert(dividend > 0 && divisor > 0 && "this implementations is for positive numbers only");
+ return (dividend + divisor - 1) / divisor;
+}
+
+// Calculate the result of broadcast of two shapes
+ir::Shape broadcastShapes(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape)
+{
+ ir::Shape out_shape;
+ auto max_rank = std::max(lhs_shape.rank(), rhs_shape.rank());
+
+ for (int idx = 0; idx < max_rank; ++idx)
+ {
+ // Go over operands dimensions from right to left
+ int lhs_idx = lhs_shape.rank() - idx - 1;
+ int rhs_idx = rhs_shape.rank() - idx - 1;
+
+ int32_t lhs_dim = lhs_idx >= 0 ? lhs_shape.dim(lhs_idx) : 1;
+ int32_t rhs_dim = rhs_idx >= 0 ? rhs_shape.dim(rhs_idx) : 1;
+
+ if (lhs_dim != 1 && rhs_dim != 1 && lhs_dim != rhs_dim)
+ throw std::runtime_error("Incompatible shapes for broadcast");
+
+ out_shape.prepend(std::max(lhs_dim, rhs_dim));
+ }
+
+ return out_shape;
+}
+
+} // namespace
+
+namespace bcq
+{
+inline int getOutputSize(const ir::Shape &cluster_shape, const int32_t *cluster_buf)
+{
+ int size = 0;
+ for (int idx = 0; idx < cluster_shape.dim(0); idx++)
+ {
+ size += cluster_buf[idx * 2 + 1];
+ }
+ return size;
+}
+} // namespace bcq
+
+//
+// Shape inference
+//
+
+// Calculate output height and width of convolution-like operation
+std::pair<int, int> calcConvLikeHeightAndWidth(const int in_h, const int in_w, const int ker_h,
+ const int ker_w, const ir::Padding pad,
+ const ir::Stride stride,
+ const ir::Dilation dilation = {1, 1})
+{
+ int32_t out_h = 0, out_w = 0;
+ int32_t effective_filter_w_size = (ker_w - 1) * dilation.width_factor + 1;
+ int32_t effective_filter_h_size = (ker_h - 1) * dilation.height_factor + 1;
+ switch (pad.type)
+ {
+ case ir::PaddingType::SAME:
+ out_h = ceil_div(in_h, stride.vertical);
+ out_w = ceil_div(in_w, stride.horizontal);
+ break;
+ case ir::PaddingType::VALID:
+ out_h = ceil_div(in_h - effective_filter_h_size + 1, stride.vertical);
+ out_w = ceil_div(in_w - effective_filter_w_size + 1, stride.horizontal);
+ break;
+ case ir::PaddingType::EXPLICIT:
+ out_h =
+ (in_h + pad.param.top + pad.param.bottom - effective_filter_h_size) / stride.vertical + 1;
+ out_w =
+ (in_w + pad.param.left + pad.param.right - effective_filter_w_size) / stride.horizontal +
+ 1;
+ break;
+ default:
+ assert(false);
+ }
+
+ return {out_h, out_w};
+}
+
+ir::Shape inferEltwiseShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape)
+{
+ return broadcastShapes(lhs_shape, rhs_shape);
+}
+
+ir::Shape inferArgMaxShape(const ir::Shape &input_shape, int axis, int rank)
+{
+ if (axis < 0 || axis >= rank)
+ {
+ throw std::runtime_error("ArgMax shape inference: Wrong axis value " + std::to_string(axis));
+ }
+
+ ir::Shape out_shape;
+ for (int idx = 0; idx < rank; ++idx)
+ {
+ if (idx != axis)
+ {
+ int32_t input_dim = input_shape.dim(idx);
+ out_shape.append(input_dim);
+ }
+ }
+
+ return out_shape;
+}
+
+ir::Shape inferReduceShape(const ir::Shape &input_shape, const std::vector<int> &axes,
+ bool keep_dims)
+{
+ int num_axis = axes.size();
+ int input_num_dims = input_shape.rank();
+ if (input_num_dims == 0)
+ {
+ ir::Shape out_shape(0);
+ return out_shape;
+ }
+ if (keep_dims)
+ {
+ ir::Shape out_shape;
+ for (int idx = 0; idx < input_num_dims; ++idx)
+ {
+ bool is_axis = false;
+ for (int axis_idx = 0; axis_idx < num_axis; ++axis_idx)
+ {
+ if (axes[axis_idx] == idx || axes[axis_idx] + input_num_dims == idx)
+ {
+ is_axis = true;
+ break;
+ }
+ }
+ if (is_axis)
+ {
+ out_shape.append(1);
+ }
+ else
+ {
+ out_shape.append(input_shape.dim(idx));
+ }
+ }
+ return out_shape;
+ }
+ else
+ {
+ // Calculates size of reducing axis.
+ int num_reduce_axis = num_axis;
+ for (int i = 0; i < num_axis; ++i)
+ {
+ int current = axes[i];
+ if (!(-input_num_dims <= current && current < input_num_dims))
+ throw std::runtime_error{"Invalid dim value " + std::to_string(current)};
+ if (current < 0)
+ {
+ current += input_num_dims;
+ }
+ for (int j = 0; j < i; ++j)
+ {
+ int previous = axes[j];
+ if (previous < 0)
+ {
+ previous += input_num_dims;
+ }
+ if (current == previous)
+ {
+ --num_reduce_axis;
+ break;
+ }
+ }
+ }
+ // Determines output dimensions.
+ ir::Shape out_shape;
+ int num_skip_axis = 0;
+ for (int idx = 0; idx < input_num_dims; ++idx)
+ {
+ bool is_axis = false;
+ for (int axis_idx = 0; axis_idx < num_axis; ++axis_idx)
+ {
+ if (axes[axis_idx] == idx || axes[axis_idx] + input_num_dims == idx)
+ {
+ ++num_skip_axis;
+ is_axis = true;
+ break;
+ }
+ }
+ if (!is_axis)
+ {
+ out_shape.append(input_shape.dim(idx));
+ }
+ }
+ return out_shape;
+ }
+}
+
+ir::Shape inferBatchMatMulShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape,
+ const ir::operation::BatchMatMul::Param &param)
+{
+ bool adj_x = param.adj_x;
+ bool adj_y = param.adj_y;
+ ir::Shape output_shape;
+
+ int output_rank = std::max(lhs_shape.rank(), rhs_shape.rank());
+
+ // Extend lhs and rhs shape
+ ir::Shape extended_lhs_shape(lhs_shape);
+ ir::Shape extended_rhs_shape(rhs_shape);
+ extended_lhs_shape.extendRank(output_rank);
+ extended_rhs_shape.extendRank(output_rank);
+
+ for (int i = 0; i < output_rank - 2; i++)
+ {
+ const int lhs_dim = extended_lhs_shape.dim(i);
+ const int rhs_dim = extended_rhs_shape.dim(i);
+ int broadcast_dim = lhs_dim;
+ if (lhs_dim != rhs_dim)
+ {
+ if (lhs_dim == 1)
+ {
+ broadcast_dim = rhs_dim;
+ }
+ else if (rhs_dim != 1)
+ {
+ throw std::runtime_error{"BatchMatMul shape inference: invalid brodcasting input shape"};
+ }
+ }
+
+ output_shape.append(broadcast_dim);
+ }
+
+ // Fill in the matmul dimensions.
+ int lhs_rows_index = adj_x ? output_rank - 1 : output_rank - 2;
+ int rhs_cols_index = adj_y ? output_rank - 2 : output_rank - 1;
+
+ output_shape.append(extended_lhs_shape.dim(lhs_rows_index));
+ output_shape.append(extended_rhs_shape.dim(rhs_cols_index));
+
+ return output_shape;
+}
+
+/*
+ * shp_shape : SHAPE input tensor's shape
+ * shp_buf : SHAPE input tensor's buffer
+ */
+ir::Shape inferBroadcastToShape(const ir::Shape shp_shape, const int32_t *shp_buf)
+{
+
+ const int num_elements = shp_shape.num_elements();
+
+ assert(num_elements != 0);
+ assert(shp_buf);
+
+ ir::Shape new_shape(num_elements);
+
+ for (int i = 0; i < num_elements; ++i)
+ {
+ assert(shp_buf[i] != 0); // It shouldn't be 0.
+ new_shape.dim(i) = shp_buf[i];
+ }
+
+ return new_shape;
+}
+
+ir::Shape inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param &param)
+{
+ const int32_t concat_axis = param.axis >= 0 ? param.axis : in_shapes[0].rank() + param.axis;
+ const auto &first_in_shape = in_shapes[0];
+
+ // Check that all shapes are equal except for concat axis dimension
+ for (const auto &in_shape : in_shapes)
+ {
+ if (in_shape.rank() != first_in_shape.rank())
+ throw std::runtime_error("Rank in all input tensors should be same");
+
+ for (int64_t dim_idx = 0; dim_idx < in_shape.rank(); ++dim_idx)
+ if (!(dim_idx == concat_axis || in_shape.dim(dim_idx) == first_in_shape.dim(dim_idx)))
+ throw std::runtime_error("All tensor should have same dimension "
+ "except dimension on passed axis");
+ }
+
+ // Calculate output shape
+ ir::Shape out_shape(first_in_shape);
+ out_shape.dim(concat_axis) = 0;
+ for (const auto &in_shape : in_shapes)
+ out_shape.dim(concat_axis) += in_shape.dim(concat_axis);
+ return out_shape;
+}
+
+ir::Shape inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::Conv2D::Param &param, ir::Layout layout)
+{
+ if (param.stride.horizontal == 0 || param.stride.vertical == 0)
+ throw std::runtime_error{"Conv2D: stride values must be positive"};
+
+ auto ifm_shape = in_shape.asFeature(layout);
+
+ // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]
+ auto kf_shape = ker_shape.asFeature(layout);
+ assert(ifm_shape.C == kf_shape.C);
+
+ const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, kf_shape.H, kf_shape.W,
+ param.padding, param.stride, param.dilation);
+
+ return ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.N};
+}
+
+ir::Shape inferDepthwiseConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::DepthwiseConv2D::Param &param,
+ ir::Layout layout)
+{
+ if (param.stride.horizontal == 0 || param.stride.vertical == 0)
+ throw std::runtime_error{"DepthwiseConv2D: stride values must be positive"};
+
+ assert(layout == ir::Layout::NHWC);
+ auto ifm_shape = in_shape.asFeature(layout);
+
+ // Kernel format is [1, kernel_height, kernel_width, depth_out]
+ auto kf_shape = ker_shape.asFeature(layout);
+ assert(kf_shape.C == static_cast<int32_t>(ifm_shape.C * param.multiplier));
+ assert(kf_shape.N == 1);
+
+ const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, kf_shape.H, kf_shape.W,
+ param.padding, param.stride, param.dilation);
+
+ return ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.C};
+}
+
+ir::Shape inferExpandDimsShape(const ir::Shape &in_shape, int32_t axis)
+{
+ ir::Shape out_shape(in_shape.rank() + 1);
+
+ axis = ((axis >= 0) ? axis : /* when axis < 0 */ (out_shape.rank() + axis));
+ if (!(0 <= axis && axis <= in_shape.rank()))
+ throw std::runtime_error("axis of dim is out of range");
+
+ for (int x = 0, out_x = 0; out_x < out_shape.rank(); ++out_x)
+ {
+ if (out_x == axis)
+ out_shape.dim(out_x) = 1;
+ else
+ out_shape.dim(out_x) = in_shape.dim(x++);
+ }
+
+ return out_shape;
+}
+
+ir::Shape inferFillShape(const ir::Shape &in_shape, const int32_t *in_buf)
+{
+ ir::Shape out_shape(in_shape.dim(0));
+
+ for (int out_x = 0; out_x < out_shape.rank(); ++out_x)
+ {
+ out_shape.dim(out_x) = in_buf[out_x];
+ }
+
+ return out_shape;
+}
+
+ir::Shape inferFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &ker_shape)
+{
+ assert(in_shape.rank() >= 2);
+ assert(ker_shape.rank() == 2);
+
+ const auto input_size_with_batch = in_shape.num_elements();
+ const auto num_units = ker_shape.dim(0);
+ const auto input_size = ker_shape.dim(1);
+ const auto batch_size = input_size_with_batch / input_size;
+ assert(input_size_with_batch % input_size == 0);
+
+ return {ir::Shape({static_cast<int32_t>(batch_size), num_units})};
+}
+
+ir::Shape inferBCQFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &cluster_shape,
+ const int32_t *cluster_buf)
+{
+ assert(cluster_shape.rank() == 2);
+ assert(cluster_shape.dim(1) == 2);
+
+ const auto input_size = in_shape.dim(1);
+ const auto output_size = bcq::getOutputSize(cluster_shape, cluster_buf);
+
+ return {ir::Shape({output_size, input_size})};
+}
+
+ir::Shape inferBCQGatherShape(const ir::Shape &indices_shape, const ir::Shape &cluster_shape,
+ const int32_t *cluster_buf, int rank,
+ const ir::operation::BCQGather::Param &param)
+{
+ ir::Shape out_shape;
+ ir::Shape in_original_shape;
+
+ assert(cluster_shape.rank() == 2);
+ assert(cluster_shape.dim(1) == 2);
+
+ auto hidden_size = param.input_hidden_size;
+ auto axis = param.axis;
+
+ in_original_shape.append(bcq::getOutputSize(cluster_shape, cluster_buf));
+ in_original_shape.append(hidden_size);
+
+ const int indices_rank = indices_shape.rank();
+ for (int idx = 0; idx < rank; ++idx)
+ {
+ if (idx == (int)axis)
+ {
+ for (int indices_idx = 0; indices_idx < indices_rank; indices_idx++)
+ {
+ out_shape.append(indices_shape.dim(indices_idx));
+ }
+ }
+ else
+ {
+ out_shape.append(in_original_shape.dim(idx));
+ }
+ }
+
+ return out_shape;
+}
+
+ir::Shape inferGatherShape(const ir::Shape &input_shape, const ir::Shape &indices_shape, int axis,
+ int rank)
+{
+ ir::Shape out_shape;
+
+ const int indices_rank = indices_shape.rank();
+
+ for (int idx = 0; idx < rank; ++idx)
+ {
+ if (idx == axis)
+ {
+ for (int indices_idx = 0; indices_idx < indices_rank; indices_idx++)
+ {
+ out_shape.append(indices_shape.dim(indices_idx));
+ }
+ }
+ else
+ {
+ out_shape.append(input_shape.dim(idx));
+ }
+ }
+
+ return out_shape;
+}
+
+ir::Shape inferOnehotShape(const ir::Shape &input_shape, const int depth, int axis)
+{
+ assert(depth >= 0);
+ const auto rank = input_shape.rank() + 1;
+ ir::Shape newShape(rank);
+
+ axis = (axis == -1) ? (rank - 1) : axis;
+
+ for (int i = 0; i < rank; ++i)
+ {
+ if (i < axis)
+ {
+ newShape.dim(i) = input_shape.dim(i);
+ }
+ else if (i == axis)
+ {
+ newShape.dim(i) = depth;
+ }
+ else
+ {
+ newShape.dim(i) = input_shape.dim(i - 1);
+ }
+ }
+
+ return newShape;
+}
+
+ir::Shape inferPackShape(const ir::Shape &input_shape, int axis, int rank, int num)
+{
+ ir::Shape out_shape;
+ int in_idx = 0;
+
+ for (int out_idx = 0; out_idx < rank; ++out_idx)
+ {
+ if (out_idx == axis)
+ {
+ out_shape.append(num);
+ }
+ else
+ {
+ out_shape.append(input_shape.dim(in_idx++));
+ }
+ }
+
+ return out_shape;
+}
+
+ir::Shape inferPadShape(const ir::Shape &in_shape, const int32_t *pad_buf, const size_t num_pads)
+{
+ assert(num_pads % 2 == 0);
+ const int32_t rank = num_pads / 2;
+
+ ir::Shape ret(rank);
+ for (int32_t i = 0; i < rank; ++i)
+ {
+ const auto before_padding = pad_buf[i * 2];
+ const auto after_padding = pad_buf[i * 2 + 1];
+
+ ret.dim(i) = in_shape.dim(i) + before_padding + after_padding;
+ }
+
+ return ret;
+}
+
+ir::Shape inferPoolShape(const ir::Shape &in_shape, const ir::operation::Pool2D::Param &param,
+ const ir::Layout layout)
+{
+ if (param.stride.horizontal == 0 || param.stride.vertical == 0)
+ throw std::runtime_error{"Pool2D: stride values must be positive"};
+
+ assert(layout == ir::Layout::NHWC);
+ auto ifm_shape = in_shape.asFeature(layout);
+ const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, param.kh, param.kw,
+ param.padding, param.stride);
+ // Pooling don't change number of channels and batch size
+ return ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, ifm_shape.C};
+}
+
+ir::Shape inferResizeBilinearShape(const ir::Shape &in_shape, const int32_t output_height,
+ const int32_t output_width)
+{
+ assert(in_shape.rank() == 4);
+ if (output_height < 0)
+ {
+ throw std::runtime_error{"ResizeBilinear: size value must be positive value, output_height = " +
+ std::to_string(output_height)};
+ }
+ if (output_width < 0)
+ {
+ throw std::runtime_error{"ResizeBilinear: size value must be positive value, output_width = " +
+ std::to_string(output_width)};
+ }
+
+ ir::Shape ret(in_shape.rank());
+
+ ret.dim(0) = in_shape.dim(0);
+ ret.dim(1) = output_height;
+ ret.dim(2) = output_width;
+ ret.dim(3) = in_shape.dim(3);
+
+ return ret;
+}
+
+template <typename T> ir::Shape inferRangeShape(T start_val, T limit_val, T delta_val)
+{
+ ir::Shape out_shape(static_cast<int>(1));
+
+ out_shape.dim(0) =
+ (std::is_integral<T>::value
+ ? ((std::abs(start_val - limit_val) + std::abs(delta_val) - 1) / std::abs(delta_val))
+ : std::ceil(std::abs((start_val - limit_val) / delta_val)));
+ return out_shape;
+}
+
+// template instantiation
+template ir::Shape inferRangeShape(int start_val, int limit_val, int delta_val);
+template ir::Shape inferRangeShape(float start_val, float limit_val, float delta_val);
+
+ir::Shape inferReshapeShape(const int32_t *shape_buf, const int32_t shape_num_elements,
+ const size_t total_num_elements)
+{
+ ir::Shape ret(shape_num_elements);
+ int32_t flatten_dim = ir::Shape::UNSPECIFIED_DIM;
+ for (int32_t i = 0; i < shape_num_elements; ++i)
+ {
+ if (shape_buf[i] < 0)
+ {
+ if (flatten_dim != ir::Shape::UNSPECIFIED_DIM)
+ throw std::runtime_error("Reshape: 2nd param has special dim(for flatten) more than twice");
+ flatten_dim = i;
+ ret.dim(i) = 1;
+ }
+ else
+ {
+ ret.dim(i) = shape_buf[i];
+ }
+ }
+ if (flatten_dim != ir::Shape::UNSPECIFIED_DIM)
+ ret.dim(flatten_dim) = total_num_elements / ret.num_elements();
+
+ // Check reshapable
+ if (total_num_elements != static_cast<size_t>(ret.num_elements()))
+ throw std::runtime_error("Reshape: 2nd param is not compatible with the shape of input");
+
+ return ret;
+}
+
+ir::Shape inferSelectShape(const ir::Shape &input_cond_shape, const ir::Shape &input_true_shape,
+ const ir::Shape &input_false_shape)
+{
+ auto haveSameShapes = [](const ir::Shape &input_cond_shape, const ir::Shape &input_true_shape,
+ const ir::Shape &input_false_shape) {
+ if ((input_cond_shape.rank() != input_true_shape.rank()) ||
+ input_cond_shape.rank() != input_false_shape.rank())
+ {
+ return false;
+ }
+
+ int rank = input_cond_shape.rank();
+ for (int i = 0; i < rank; ++i)
+ {
+ if (input_cond_shape.dim(i) != input_true_shape.dim(i) ||
+ input_cond_shape.dim(i) != input_false_shape.dim(i))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ auto calculateShape = [](const ir::Shape &input_cond_shape, const ir::Shape &input_true_shape,
+ const ir::Shape &input_false_shape, ir::Shape &new_shape) {
+ ir::Shape cond_shape = input_cond_shape;
+ ir::Shape true_shape = input_true_shape;
+ ir::Shape false_shape = input_false_shape;
+ int most_rank =
+ (cond_shape.rank() >= true_shape.rank()) && (cond_shape.rank() >= false_shape.rank())
+ ? cond_shape.rank()
+ : (false_shape.rank() >= true_shape.rank() ? false_shape.rank() : true_shape.rank());
+
+ ir::Shape calculate_shape(most_rank);
+
+ cond_shape.extendRank(most_rank);
+ true_shape.extendRank(most_rank);
+ false_shape.extendRank(most_rank);
+
+ for (int i = 0; i < most_rank; ++i)
+ {
+ calculate_shape.dim(i) =
+ (cond_shape.dim(i) >= true_shape.dim(i)) && (cond_shape.dim(i) >= false_shape.dim(i))
+ ? cond_shape.dim(i)
+ : (false_shape.dim(i) >= true_shape.dim(i) ? false_shape.dim(i) : true_shape.dim(i));
+
+ if ((cond_shape.dim(i) != calculate_shape.dim(i) && cond_shape.dim(i) != 1) ||
+ (true_shape.dim(i) != calculate_shape.dim(i) && true_shape.dim(i) != 1) ||
+ (false_shape.dim(i) != calculate_shape.dim(i) && false_shape.dim(i) != 1))
+ {
+ return false;
+ }
+ }
+
+ new_shape = calculate_shape;
+
+ return true;
+ };
+
+ bool havesame = haveSameShapes(input_cond_shape, input_true_shape, input_false_shape);
+ if (havesame)
+ {
+ return input_cond_shape;
+ }
+
+ ir::Shape new_shape;
+ bool possible = calculateShape(input_cond_shape, input_true_shape, input_false_shape, new_shape);
+
+ if (!possible)
+ {
+ throw std::runtime_error("Broadcasting is not possible.");
+ }
+
+ return new_shape;
+}
+
+ir::Shape inferSliceShape(const ir::Shape &input_shape, const int32_t *begins_buf,
+ const int32_t *sizes_buf)
+{
+ const uint32_t rank = input_shape.rank();
+ ir::Shape out_shape(rank);
+
+ for (uint32_t idx = 0; idx < rank; ++idx)
+ {
+ const auto input_dim = input_shape.dim(idx);
+
+ // begin is zero-based
+ auto begin = begins_buf[idx];
+ if (begin < 0)
+ throw std::runtime_error("shape inference Slice: Invalid begin.");
+
+ // size is one-based
+ auto size = sizes_buf[idx];
+ if (size < -1)
+ throw std::runtime_error("shape inference Slice: Invalid size.");
+
+ if (size == -1)
+ {
+ size = input_dim - begin;
+ }
+ else
+ {
+ if (input_dim < begin + size)
+ throw std::runtime_error("shape inference Slice: Invalid begin and size.");
+ }
+ out_shape.dim(idx) = size;
+ }
+
+ return out_shape;
+}
+
+ir::Shape inferSpaceToBatchNDShape(const ir::Shape &input_shape, const ir::Shape &block_shape_shape,
+ const ir::Shape &padding_shape, const int32_t *block_shape_buf,
+ const int32_t *padding_buf)
+{
+ const uint32_t rank = input_shape.rank();
+ ir::Shape out_shape(rank);
+
+ // Currently, only 4D NHWC input/output op_context are supported.
+ // The 4D array need to have exactly 2 spatial dimensions.
+ // TODO(nupurgarg): Support arbitrary dimension in SpaceToBatchND.
+ const int32_t kInputDimensionNum = 4;
+ const int32_t kBlockSizeDimensionNum = 1;
+ const int32_t kSpatialDimensionNum = 2;
+
+ UNUSED_RELEASE(kInputDimensionNum);
+ UNUSED_RELEASE(kBlockSizeDimensionNum);
+ UNUSED_RELEASE(block_shape_shape);
+ UNUSED_RELEASE(padding_shape);
+
+ assert(block_shape_shape.rank() == kBlockSizeDimensionNum);
+ assert(block_shape_shape.dim(0) == kSpatialDimensionNum);
+ assert(padding_shape.dim(0) == kSpatialDimensionNum);
+ assert(padding_shape.dim(1) == 2); // fixed, meaning left/right padding for each element
+ assert(padding_shape.rank() == 2); // fixed, meaning dimension(dim 0) and padding length(dim 1)
+
+ // Ensures the input height and width (with padding) is a multiple of block
+ // shape height and width.
+ for (int dim = 0; dim < kSpatialDimensionNum; ++dim)
+ {
+ int final_dim_size =
+ (input_shape.dim(dim + 1) + padding_buf[dim * 2] + padding_buf[dim * 2 + 1]);
+
+ assert(final_dim_size % block_shape_buf[dim] == 0);
+
+ out_shape.dim(dim + 1) = final_dim_size / block_shape_buf[dim];
+ }
+
+ const int output_batch_size = input_shape.dim(0) * block_shape_buf[0] * block_shape_buf[1];
+ const int output_channel_size = input_shape.dim(3);
+
+ out_shape.dim(0) = output_batch_size;
+ out_shape.dim(3) = output_channel_size;
+
+ return out_shape;
+}
+
+ir::Shape inferSplitShape(const ir::Shape input_shape, int axis_value, int num_splits)
+{
+ ir::Shape newShape(input_shape);
+
+ assert(axis_value >= 0);
+ assert(axis_value < input_shape.rank());
+
+ const int input_size = input_shape.dim(axis_value);
+ assert(input_size % num_splits == 0);
+ const int slice_size = input_size / num_splits;
+
+ newShape.dim(axis_value) = slice_size;
+
+ return newShape;
+}
+
+ir::Shape inferSqueezeShape(const ir::Shape &in_shape, const ir::operation::Squeeze::Param &param)
+{
+ const int ndims = param.ndim;
+ const int *squeeze_dims = param.dims;
+ bool should_squeeze[8] = {false};
+ int num_squeezed_dims = 0;
+ int shape_rank = in_shape.rank();
+ if (ndims == 0)
+ {
+ for (int idx = 0; idx < shape_rank; ++idx)
+ {
+ if (in_shape.dim(idx) == 1)
+ {
+ should_squeeze[idx] = true;
+ ++num_squeezed_dims;
+ }
+ }
+ }
+ else
+ {
+ for (int idx = 0; idx < ndims; ++idx)
+ {
+ int current = squeeze_dims[idx];
+ if (current < 0)
+ {
+ current += shape_rank;
+ }
+
+ if (!(current >= 0 && current < shape_rank && in_shape.dim(current) == 1))
+ {
+ throw std::runtime_error(
+ "The following conditions must be met: 0 <= dim < Shape rank, dim == 1");
+ }
+
+ if (!should_squeeze[current])
+ {
+ ++num_squeezed_dims;
+ }
+ should_squeeze[current] = true;
+ }
+ }
+
+ // Set output shape.
+ ir::Shape out_shape(shape_rank - num_squeezed_dims);
+ for (int in_idx = 0, out_idx = 0; in_idx < shape_rank; ++in_idx)
+ {
+ if (!should_squeeze[in_idx])
+ {
+ out_shape.dim(out_idx++) = in_shape.dim(in_idx);
+ }
+ }
+
+ return out_shape;
+}
+
+// helper for for StridedSlice
+template <typename T>
+StridedSliceParams buildStridedSliceParams(const T *begin, const T *end, const T *strides,
+ const uint32_t begin_mask, const uint32_t end_mask,
+ const uint32_t shrink_axis_mask, const uint8_t rank)
+{
+ StridedSliceParams op_params;
+ op_params.start_indices_count = rank;
+ op_params.stop_indices_count = rank;
+ op_params.strides_count = rank;
+
+ for (int i = 0; i < op_params.strides_count; ++i)
+ {
+ op_params.start_indices[i] = begin[i];
+ op_params.stop_indices[i] = end[i];
+ op_params.strides[i] = strides[i];
+
+ assert(op_params.strides[i] != 0);
+ }
+
+ op_params.begin_mask = begin_mask;
+ op_params.ellipsis_mask = 0; // NYI
+ op_params.end_mask = end_mask;
+ op_params.new_axis_mask = 0; // NYI
+ op_params.shrink_axis_mask = shrink_axis_mask;
+
+ assert(sizeof(op_params.begin_mask) * 4 >= rank);
+
+ return op_params;
+}
+
+// template instantiation
+template StridedSliceParams
+buildStridedSliceParams(const uint32_t *begin, const uint32_t *end, const uint32_t *strides,
+ const uint32_t begin_mask, const uint32_t end_mask,
+ const uint32_t shrink_axis_mask, const uint8_t rank);
+
+int Clamp(const int v, const int lo, const int hi)
+{
+ assert(!(hi < lo));
+ if (hi < v)
+ return hi;
+ if (v < lo)
+ return lo;
+ return v;
+}
+
+int StartForAxis(const StridedSliceParams &params, const ir::Shape &input_shape, int axis)
+{
+ const auto begin_mask = params.begin_mask;
+ const auto *start_indices = params.start_indices;
+ const auto *strides = params.strides;
+ // Begin with the specified index.
+ int start = start_indices[axis];
+
+ // begin_mask override
+ if (begin_mask & 1 << axis)
+ {
+ if (strides[axis] > 0)
+ {
+ // Forward iteration - use the first element. These values will get
+ // clamped below (Note: We could have set them to 0 and axis_size-1, but
+ // use lowest() and max() to maintain symmetry with StopForAxis())
+ start = std::numeric_limits<int>::lowest();
+ }
+ else
+ {
+ // Backward iteration - use the last element.
+ start = std::numeric_limits<int>::max();
+ }
+ }
+
+ // Handle negative indices
+ int axis_size = input_shape.dim(axis);
+ if (start < 0)
+ {
+ start += axis_size;
+ }
+
+ // Clamping
+ start = Clamp(start, 0, axis_size - 1);
+
+ return start;
+}
+
+// Return the "real" index for the end of iteration along that axis. This is an
+// "end" in the traditional C sense, in that it points to one past the last
+// element. ie. So if you were iterating through all elements of a 1D array of
+// size 4, this function would return 4 as the stop, because it is one past the
+// "real" indices of 0, 1, 2 & 3.
+int StopForAxis(const StridedSliceParams &params, const ir::Shape &input_shape, int axis,
+ int start_for_axis)
+{
+ const auto end_mask = params.end_mask;
+ const auto shrink_axis_mask = params.shrink_axis_mask;
+ const auto *stop_indices = params.stop_indices;
+ const auto *strides = params.strides;
+
+ // Begin with the specified index
+ const bool shrink_axis = shrink_axis_mask & (1 << axis);
+ int stop = stop_indices[axis];
+
+ // When shrinking an axis, the end position does not matter (and can be
+ // incorrect when negative indexing is used, see Issue #19260). Always use
+ // start_for_axis + 1 to generate a length 1 slice, since start_for_axis has
+ // already been adjusted for negative indices.
+ if (shrink_axis)
+ {
+ stop = start_for_axis + 1;
+ }
+
+ // end_mask override
+ if (end_mask & (1 << axis))
+ {
+ if (strides[axis] > 0)
+ {
+ // Forward iteration - use the last element. These values will get
+ // clamped below
+ stop = std::numeric_limits<int>::max();
+ }
+ else
+ {
+ // Backward iteration - use the first element.
+ stop = std::numeric_limits<int>::lowest();
+ }
+ }
+
+ // Handle negative indices
+
+ const int axis_size = input_shape.dim(axis);
+ if (stop < 0)
+ {
+ stop += axis_size;
+ }
+
+ // Clamping
+ // Because the end index points one past the last element, we need slightly
+ // different clamping ranges depending on the direction.
+ if (strides[axis] > 0)
+ {
+ // Forward iteration
+ stop = Clamp(stop, 0, axis_size);
+ }
+ else
+ {
+ // Backward iteration
+ stop = Clamp(stop, -1, axis_size - 1);
+ }
+
+ return stop;
+}
+
+ir::Shape inferStridedSliceShape(const ir::Shape &input_shape, const StridedSliceParams &op_params,
+ uint32_t rank)
+{
+ ir::Shape out_shape;
+
+ for (uint32_t idx = 0; idx < rank; ++idx)
+ {
+ int32_t stride = op_params.strides[idx];
+ int32_t begin = StartForAxis(op_params, input_shape, idx);
+ int32_t end = StopForAxis(op_params, input_shape, idx, begin);
+
+ // When shrinking an axis, the end position does not matter (and can be
+ // incorrect when negative indexing is used, see Issue #19260). Always use
+ // begin + 1 to generate a length 1 slice, since begin has
+ // already been adjusted for negative indices by StartForAxis.
+ const bool shrink_axis = op_params.shrink_axis_mask & (1 << idx);
+ if (shrink_axis)
+ {
+ end = begin + 1;
+ }
+
+ int32_t dim_shape = std::ceil((end - begin) / static_cast<float>(stride));
+ dim_shape = dim_shape < 0 ? 0 : dim_shape;
+ if (!shrink_axis)
+ {
+ out_shape.append(dim_shape);
+ }
+ }
+
+ return out_shape;
+}
+
+ir::Shape inferTileShape(const ir::Shape &in_shape, const int32_t *multiplier_buf,
+ const int32_t multiplier_size)
+{
+ if (multiplier_size != in_shape.rank())
+ {
+ throw std::runtime_error("inferTileShape failed, input rank: " +
+ std::to_string(in_shape.rank()) + ", bad multipliers size: " +
+ std::to_string(multiplier_size) + "");
+ }
+ ir::Shape new_Shape(in_shape.rank());
+
+ for (int i = 0; i < in_shape.rank(); ++i)
+ {
+ assert(multiplier_buf[i]); // multiplier_buf[i] shuld not be 0.
+ new_Shape.dim(i) = in_shape.dim(i) * multiplier_buf[i];
+ }
+ return new_Shape;
+}
+
+ir::Shape inferTransposeShape(const ir::Shape &in_shape, const int32_t *perm_buf,
+ const int32_t perm_size)
+{
+ const auto rank = in_shape.rank();
+ if (perm_size > rank)
+ {
+ throw std::runtime_error("inferTransposeShape failed, bad permutation size: " +
+ std::to_string(perm_size));
+ }
+
+ const int32_t *perm_data = perm_buf;
+ std::vector<int32_t> regular_perm_vec;
+ if (perm_size == 0)
+ {
+ // perm_data will be set to (n-1...0)
+ regular_perm_vec.resize(rank);
+ std::iota(regular_perm_vec.begin(), regular_perm_vec.end(), 0);
+ std::reverse(regular_perm_vec.begin(), regular_perm_vec.end());
+ perm_data = regular_perm_vec.data();
+ }
+ else
+ {
+ assert(rank == perm_size);
+ }
+
+ ir::Shape out_shape(rank);
+ std::vector<bool> visit_perms(rank, false);
+ for (int idx = 0; idx < rank; idx++)
+ {
+ const auto perm_val = perm_data[idx];
+ // Check invalid permutation value
+ if (perm_val < 0 || perm_val >= rank)
+ {
+ throw std::runtime_error("inferTransposeShape failed, bad permutation value: " +
+ std::to_string(perm_val));
+ }
+
+ // Check duplicated permutation value
+ if (visit_perms.at(perm_val))
+ {
+ throw std::runtime_error("inferTransposeShape failed, duplicated permutation value: " +
+ std::to_string(perm_val));
+ }
+ visit_perms.at(perm_val) = true;
+
+ out_shape.dim(idx) = in_shape.dim(perm_val);
+ }
+ return out_shape;
+}
+
+ir::Shape inferUnpackShape(const ir::Shape &input_shape, int axis, int rank)
+{
+ ir::Shape out_shape;
+
+ for (int out_idx = 0; out_idx < rank; out_idx++)
+ {
+ if (out_idx != axis)
+ {
+ out_shape.append(input_shape.dim(out_idx));
+ }
+ }
+
+ return out_shape;
+}
+
+} // namespace shape_inference
+} // namespace onert
diff --git a/runtime/onert/core/src/util/logging.cc b/runtime/onert/core/src/util/logging.cc
new file mode 100644
index 000000000..6309d25e5
--- /dev/null
+++ b/runtime/onert/core/src/util/logging.cc
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/logging.h"
+
+onert::util::logging::Context &onert::util::logging::Context::get() noexcept
+{
+ static Context ctx;
+ return ctx;
+}
diff --git a/runtime/onert/frontend/CMakeLists.txt b/runtime/onert/frontend/CMakeLists.txt
new file mode 100644
index 000000000..5ea6cdadd
--- /dev/null
+++ b/runtime/onert/frontend/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectories()
diff --git a/runtime/onert/frontend/base_loader/CMakeLists.txt b/runtime/onert/frontend/base_loader/CMakeLists.txt
new file mode 100644
index 000000000..6f700710c
--- /dev/null
+++ b/runtime/onert/frontend/base_loader/CMakeLists.txt
@@ -0,0 +1,11 @@
+if(NOT BUILD_TFLITE_LOADER AND NOT BUILD_CIRCLE_LOADER)
+ return()
+endif(NOT BUILD_TFLITE_LOADER AND NOT BUILD_CIRCLE_LOADER)
+
+nnfw_find_package(FlatBuffers REQUIRED)
+
+add_library(base_loader INTERFACE)
+target_include_directories(base_loader INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+target_link_libraries(base_loader INTERFACE onert_core)
+target_link_libraries(base_loader INTERFACE flatbuffers::flatbuffers)
diff --git a/runtime/onert/frontend/base_loader/include/base_loader.h b/runtime/onert/frontend/base_loader/include/base_loader.h
new file mode 100644
index 000000000..c0003e402
--- /dev/null
+++ b/runtime/onert/frontend/base_loader/include/base_loader.h
@@ -0,0 +1,1589 @@
+/*
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BASE_LOADER_BASE_LOADER_H__
+#define __BASE_LOADER_BASE_LOADER_H__
+
+#include "ir/Graph.h"
+#include "ir/Shape.h"
+#include "ir/Operations.Include.h"
+
+#include "flatbuffers/flexbuffers.h"
+
+#include <map>
+#include <memory>
+#include <fstream>
+#include <limits>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <util/logging.h>
+
+namespace onert
+{
+namespace base_loader
+{
+
+template <typename LoaderDomain> class BaseLoader
+{
+protected:
+ using Verifier = typename LoaderDomain::Verifier;
+ using ActivationFunctionType = typename LoaderDomain::ActivationFunctionType;
+ using Buffer = typename LoaderDomain::Buffer;
+ using BuiltinOperator = typename LoaderDomain::BuiltinOperator;
+ using CustomOptionsFormat = typename LoaderDomain::CustomOptionsFormat;
+ using Model = typename LoaderDomain::Model;
+ using Operator = typename LoaderDomain::Operator;
+ using Padding = typename LoaderDomain::Padding;
+ using Pool2DOptions = typename LoaderDomain::Pool2DOptions;
+ using SubGraph = typename LoaderDomain::SubGraph;
+ using Tensor = typename LoaderDomain::Tensor;
+ using TensorType = typename LoaderDomain::TensorType;
+ using DimensionType = typename LoaderDomain::DimensionType;
+ using SparseIndexVector = typename LoaderDomain::SparseIndexVector;
+
+protected:
+ bool isOptionalInputTensor(std::int32_t idx) { return idx == -1; }
+ virtual bool allowOptionalInputTensor(BuiltinOperator) = 0;
+
+public:
+ /**
+ * @brief Construct a new Loader object
+ *
+ * @param graph reference on subgraphs
+ */
+ explicit BaseLoader(std::unique_ptr<ir::Subgraphs> &subgs)
+ : _base{nullptr}, _pagesize(getpagesize()), _fd(-1), _subgraphs(subgs), _model{nullptr}
+ {
+ _use_mmaped_data = util::getConfigBool(util::config::USE_MMAPED_DATA);
+ }
+
+ /**
+ * @brief Load a model from file
+ *
+ * @param file_path
+ */
+ void loadFromFile(const char *file_path);
+ /**
+ * @brief Load a model from a buffer
+ *
+ * @param buffer buffer pointer
+ * @param size buffer size
+ */
+ void loadFromBuffer(uint8_t *buffer, size_t size);
+
+protected:
+ ~BaseLoader() = default;
+ void loadModel();
+
+ // Helper functions
+ ir::Activation convertActivation(ActivationFunctionType type);
+ ir::DataType tensorTypeToDataType(TensorType type);
+ ir::OperandIndex tensorIdxToOperandIdx(int32_t tensorIdx);
+
+ // Create operands form tflite::Tensor
+ ir::OperandIndex loadOperand(const Tensor *tensor, ir::Graph &subg);
+ void loadSparsity(const Tensor *tensor, const ir::Shape &shape, ir::TypeInfo &typeInfo);
+ void loadOperationIO(const Operator *op, ir::OperandIndexSequence &inputs,
+ ir::OperandIndexSequence &outputs);
+ // Create operations from Operator
+ void loadOperation(const Operator *op, ir::Graph &subg);
+ // Load Strides and Paddings from options to param
+ template <typename Param, typename OptionsType>
+ void loadStridesAndPaddings(Param &param, const OptionsType *options);
+ // Load Pool2D param
+ template <typename Param> void loadPool2DOptions(Param &param, const Pool2DOptions *options);
+
+private:
+ virtual std::unique_ptr<ir::Graph> loadSubgraph(const SubGraph *subg) = 0;
+ // Operations
+ template <typename OpIR, typename... Args>
+ const OpIR *loadOperationTo(const Operator *op, ir::Graph &subg, Args &&... args);
+ void loadConv2D(const Operator *op, ir::Graph &subg);
+ void loadDepthwiseConv2D(const Operator *op, ir::Graph &subg);
+ void loadTransposeConv(const Operator *op, ir::Graph &subg);
+ void loadPool2D(const Operator *op, ir::Graph &subg, ir::operation::Pool2D::PoolType op_type);
+ void loadReshape(const Operator *op, ir::Graph &subg);
+ void loadSoftmax(const Operator *op, ir::Graph &subg);
+ void loadConcatenation(const Operator *op, ir::Graph &subg);
+ void loadFC(const Operator *op, ir::Graph &subg);
+ void loadBinaryArithmetic(const Operator *op, ir::Graph &subg,
+ ir::operation::BinaryArithmetic::ArithmeticType op_type);
+ void loadAddV2(const Operator *op, ir::Graph &subg);
+ void loadPack(const Operator *op, ir::Graph &subg);
+ void loadResizeBilinear(const Operator *op, ir::Graph &subg);
+ void loadResizeNearestNeighbor(const Operator *op, ir::Graph &subg);
+ void loadReduce(const Operator *op, ir::Graph &subg,
+ ir::operation::Reduce::ReduceType reduce_type);
+ void loadReduceAll(const Operator *op, ir::Graph &subg);
+ void loadElementwiseActivation(const Operator *op, ir::Graph &subg,
+ ir::operation::ElementwiseActivation::Type op_type,
+ float alpha = 0.f, float beta = 0.f);
+ void loadElementwiseBinary(const Operator *op, ir::Graph &subg,
+ ir::operation::ElementwiseBinary::ElementwiseBinaryType op_type);
+ void loadElementwiseUnary(const Operator *op, ir::Graph &subg,
+ ir::operation::ElementwiseUnary::Type op_type);
+ void loadGather(const Operator *op, ir::Graph &subg);
+ void loadCustom(const Operator *op, ir::Graph &subg);
+ void loadBatchMatMul(const Operator *op, ir::Graph &subg);
+ void loadSqueeze(const Operator *op, ir::Graph &subg);
+ void loadSplit(const Operator *op, ir::Graph &subg);
+ void loadSplitV(const Operator *op, ir::Graph &subg);
+ void loadStridedSlice(const Operator *op, ir::Graph &subg);
+ void loadUnpack(const Operator *op, ir::Graph &subg);
+ void loadComparison(const Operator *op, ir::Graph &subg);
+ void loadEinsum(const Operator *op, ir::Graph &subg);
+ void loadOneHot(const Operator *op, ir::Graph &subg);
+ void loadIf(const Operator *op, ir::Graph &subg);
+ void loadWhile(const Operator *op, ir::Graph &subg);
+ void loadArgMax(const Operator *op, ir::Graph &subg);
+ void loadFusedBatchNorm(const Operator *op, ir::Graph &subg);
+ void loadLogSoftmax(const Operator *op, ir::Graph &subg);
+ void loadSpaceToDepth(const Operator *op, ir::Graph &subg);
+ void loadLeakyRelu(const Operator *op, ir::Graph &subg);
+ void loadUnidirectionalSequenceLSTM(const Operator *op, ir::Graph &subg);
+
+ void verifySubgraphIndex(int subg_index)
+ {
+ const auto num_subgraphs = _model->subgraphs()->size();
+ if (subg_index < 0 || subg_index >= static_cast<int32_t>(num_subgraphs))
+ throw std::runtime_error{std::string{"Invalid subgraph index - "} +
+ std::to_string(subg_index)};
+ }
+
+protected:
+ // Base address for mapped region for loading (if needed)
+ uint8_t *_base;
+ // Memory page size
+ int32_t _pagesize;
+ // loaded file description
+ int _fd;
+ // Reference on loadable subgraphs
+ std::unique_ptr<ir::Subgraphs> &_subgraphs;
+ const Model *_model;
+ // Maps Tensor indices to onert Operands.
+ std::vector<ir::OperandIndex> _tensor_to_operand;
+ std::unordered_map<ir::OperandIndex, std::string> _tensor_names;
+ // Verifier
+ std::unique_ptr<Verifier> _verifier;
+ // Boolean flag to use MMAPED_DATA
+ bool _use_mmaped_data = false;
+};
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::BaseLoader::loadFromFile(const char *file_path)
+{
+ _fd = open(file_path, O_RDONLY);
+ if (_fd < 0)
+ {
+ throw std::runtime_error("Failed to open file " + std::string(file_path));
+ }
+
+ struct stat file_stat;
+ if (fstat(_fd, &file_stat) != 0)
+ {
+ throw std::runtime_error("Fstat failed or file " + std::string(file_path) +
+ " is not a regular file");
+ }
+ int size = file_stat.st_size;
+
+ // Map model file into memory region
+ _base = static_cast<uint8_t *>(mmap(NULL, size, PROT_READ, MAP_PRIVATE, _fd, 0));
+ if (_base == MAP_FAILED)
+ {
+ close(_fd);
+ throw std::runtime_error("mmap failed - " + std::string(strerror(errno)));
+ }
+
+ _verifier = std::make_unique<Verifier>(reinterpret_cast<const std::uint8_t *>(_base), size);
+
+ loadModel();
+ munmap(_base, size);
+
+ close(_fd);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::BaseLoader::loadFromBuffer(uint8_t *buffer, size_t size)
+{
+ _base = buffer;
+ _verifier = std::make_unique<Verifier>(reinterpret_cast<const std::uint8_t *>(_base), size);
+ loadModel();
+}
+
+template <typename LoaderDomain>
+ir::Activation
+BaseLoader<LoaderDomain>::BaseLoader::convertActivation(const ActivationFunctionType type)
+{
+ switch (type)
+ {
+ case ActivationFunctionType::ActivationFunctionType_NONE:
+ return ir::Activation::NONE;
+ case ActivationFunctionType::ActivationFunctionType_RELU:
+ return ir::Activation::RELU;
+ case ActivationFunctionType::ActivationFunctionType_RELU_N1_TO_1:
+ return ir::Activation::RELU1;
+ case ActivationFunctionType::ActivationFunctionType_RELU6:
+ return ir::Activation::RELU6;
+ case ActivationFunctionType::ActivationFunctionType_TANH:
+ return ir::Activation::TANH;
+ default:
+ throw std::runtime_error(std::string("Unsupported or invalid activation type: ") +
+ std::to_string(static_cast<int>(type)));
+ }
+}
+
+template <typename LoaderDomain>
+ir::DataType BaseLoader<LoaderDomain>::BaseLoader::tensorTypeToDataType(const TensorType type)
+{
+ switch (type)
+ {
+ case TensorType::TensorType_FLOAT32:
+ return ir::DataType::FLOAT32;
+ case TensorType::TensorType_INT32:
+ return ir::DataType::INT32;
+ case TensorType::TensorType_BOOL:
+ return ir::DataType::BOOL8;
+ case TensorType::TensorType_UINT8:
+ return ir::DataType::QUANT_UINT8_ASYMM;
+ case TensorType::TensorType_INT8:
+ return ir::DataType::QUANT_INT8_ASYMM;
+ case TensorType::TensorType_INT64:
+ return ir::DataType::INT64;
+ default:
+ throw std::runtime_error(
+ std::string("Unsupported tensor type: ").append(EnumNameTensorType(type)));
+ }
+}
+
+template <typename LoaderDomain>
+ir::OperandIndex BaseLoader<LoaderDomain>::BaseLoader::tensorIdxToOperandIdx(int32_t tensorIdx)
+{
+ return isOptionalInputTensor(tensorIdx) ? ir::OperandIndex() : _tensor_to_operand[tensorIdx];
+}
+
+/* Copy is copied from tensorflow lite */
+template <typename T> bool Copy(const T *data_ptr, std::vector<uint16_t> &arr)
+{
+ if (data_ptr->values() == nullptr)
+ {
+ return false;
+ }
+
+ int size = data_ptr->values()->size();
+ arr.reserve(size);
+ for (int i = 0; i < size; i++)
+ {
+ arr.emplace_back(static_cast<uint16_t>(data_ptr->values()->Get(i)));
+ }
+ return true;
+}
+
+template <typename LoaderDomain>
+ir::OperandIndex BaseLoader<LoaderDomain>::loadOperand(const Tensor *tensor, ir::Graph &subg)
+{
+ ir::Shape shape;
+ // Shape
+ const auto *tensor_shape = tensor->shape();
+ if (tensor_shape != nullptr)
+ {
+ for (const auto &dim : *tensor_shape)
+ {
+ shape.append(dim);
+ }
+ }
+
+ // Note for tensor->shape_signature()
+ // We don't handle shape signature
+ // How we handle:
+ // If shape_signature[k] == -1, we will use tensor->shape()[k] == 1
+ // If app wants to change the input shape, call nnfw_apply_input_tensorinfo() can
+ // be used.
+
+ // Type
+ ir::DataType data_type = tensorTypeToDataType(tensor->type());
+ // Quantization
+ auto q_params = tensor->quantization();
+ float scale = 0.0;
+ long zero_point = 0;
+ if (q_params != nullptr)
+ {
+ if (q_params->scale())
+ {
+ if (q_params->scale()->size() != 1)
+ {
+ throw std::runtime_error("Only 1 scale for a tensor is supported.");
+ }
+ scale = q_params->scale()->Get(0);
+ }
+
+ if (q_params->zero_point())
+ {
+ if (q_params->zero_point()->size() != 1)
+ {
+ throw std::runtime_error("Only 1 zero_point value for a tensor is supported.");
+ }
+ zero_point = q_params->zero_point()->Get(0);
+ // zero_point is long while TypeInfo.zero_point is defined as int32_t.
+ assert(zero_point >= std::numeric_limits<int32_t>::min());
+ assert(zero_point <= std::numeric_limits<int32_t>::max());
+ }
+ auto details = q_params->details_as_CustomQuantization();
+ if (details != nullptr)
+ throw std::runtime_error("Custom Quantization is not supported");
+ }
+ // Create TypeInfo
+ ir::TypeInfo type_info(data_type, scale, zero_point);
+ // Sparsity
+ loadSparsity(tensor, shape, type_info);
+
+ // Create operand
+ const auto operand_index = subg.addOperand(shape, type_info);
+
+ // Constant tensors are indicated by non-empty data.
+ const auto *data = _model->buffers()->Get(tensor->buffer())->data();
+ if (data != nullptr)
+ {
+ using std::ptrdiff_t;
+ std::unique_ptr<ir::Data> data_obj;
+ if (_fd == -1) // Model is from memory
+ {
+ data_obj = std::make_unique<ir::ExternalData>(data->data(), data->size());
+ }
+ else // Model is loaded(mmap'd) from a file
+ {
+ size_t data_size = data->size();
+ ptrdiff_t unaligned_offset_start = data->data() - _base;
+ ptrdiff_t offset_end = unaligned_offset_start + data_size;
+
+ // Calculated aligned offset from base address of mapped region
+ // munmap accepts memory address which is a multiple of the pagesize
+ ptrdiff_t aligned_offset_start = (unaligned_offset_start / _pagesize) * _pagesize;
+ size_t mmap_size = offset_end - aligned_offset_start;
+
+ if (_use_mmaped_data)
+ {
+ data_obj = std::make_unique<ir::MMapedData>(_fd, aligned_offset_start, mmap_size,
+ unaligned_offset_start, data_size);
+ }
+ else
+ {
+ size_t offset = unaligned_offset_start - aligned_offset_start;
+ uint8_t *mmap_base = static_cast<uint8_t *>(
+ mmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, _fd, aligned_offset_start));
+ data_obj = std::make_unique<ir::CachedData>(mmap_base + offset, data_size);
+ munmap(mmap_base, mmap_size);
+ }
+ }
+ subg.setOperandValue(operand_index, std::move(data_obj));
+ }
+
+ _tensor_names.emplace(operand_index, tensor->name()->str());
+
+ // Variable
+ if (tensor->is_variable())
+ {
+ if (data != nullptr)
+ throw std::runtime_error("Variable tensor with buffer is not supported!");
+
+ subg.operands().at(operand_index).info().setAsVariable();
+ }
+
+ return operand_index;
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadSparsity(const Tensor *tensor, const ir::Shape &shape,
+ ir::TypeInfo &typeInfo)
+{
+ auto src_sparsity = tensor->sparsity();
+ if (src_sparsity != nullptr)
+ {
+ std::vector<uint16_t> w1_segments;
+ std::vector<uint16_t> w1_indices;
+ // check traversal_order
+ if (src_sparsity->traversal_order())
+ {
+ const int traversal_order_size = src_sparsity->traversal_order()->size();
+ for (int i = 0; i < traversal_order_size; ++i)
+ {
+ if (i != src_sparsity->traversal_order()->Get(i))
+ throw std::runtime_error("traversal_order [0, 1, ..., n-1] is only supported.");
+ }
+ }
+ // check block_map
+ int block_rank = 0;
+ if (src_sparsity->block_map())
+ {
+ block_rank = src_sparsity->block_map()->size();
+ for (int i = 0; i < block_rank; ++i)
+ {
+ if (i != src_sparsity->block_map()->Get(i))
+ throw std::runtime_error("block_map [0, 1, ..., n-1] is only supported.");
+ }
+ }
+ // load metadata
+ const int dim_metadata_size = src_sparsity->dim_metadata()->size();
+ auto dense_rank = shape.rank();
+ if (dense_rank + block_rank != dim_metadata_size)
+ throw std::runtime_error("sparsity dim_metadata length is wrong.");
+ bool random_sparsity = dim_metadata_size == 2 && block_rank == 0;
+ bool block2D_sparsity = dim_metadata_size == 4 && block_rank == 2;
+ if (dim_metadata_size != !random_sparsity && !block2D_sparsity)
+ throw std::runtime_error(
+ "sparsity is supported only for 2D tensor with random or 16x1 block sparsity.");
+
+ const auto *src_metadata = src_sparsity->dim_metadata()->Get(0);
+ if (src_metadata->format() != DimensionType::DimensionType_DENSE)
+ throw std::runtime_error("sparse tensor dim[0] is not DENSE");
+ src_metadata = src_sparsity->dim_metadata()->Get(1);
+ if (src_metadata->format() != DimensionType::DimensionType_SPARSE_CSR)
+ throw std::runtime_error("sparse tensor dim[0] is not SPARSE_CSR");
+ auto ParseSparseIndexVector = [src_metadata, &w1_segments, &w1_indices]() {
+ if (src_metadata->array_segments() == nullptr || src_metadata->array_indices() == nullptr)
+ return false;
+ bool status = true;
+ switch (src_metadata->array_segments_type())
+ {
+ case SparseIndexVector::SparseIndexVector_Int32Vector:
+ status = Copy(src_metadata->array_segments_as_Int32Vector(), w1_segments);
+ break;
+ case SparseIndexVector::SparseIndexVector_Uint16Vector:
+ status = Copy(src_metadata->array_segments_as_Uint16Vector(), w1_segments);
+ break;
+ case SparseIndexVector::SparseIndexVector_Uint8Vector:
+ status = Copy(src_metadata->array_segments_as_Uint8Vector(), w1_segments);
+ break;
+ default:
+ return false;
+ }
+ if (status != true)
+ return false;
+ switch (src_metadata->array_indices_type())
+ {
+ case SparseIndexVector::SparseIndexVector_Int32Vector:
+ return Copy(src_metadata->array_indices_as_Int32Vector(), w1_indices);
+ case SparseIndexVector::SparseIndexVector_Uint16Vector:
+ return Copy(src_metadata->array_indices_as_Uint16Vector(), w1_indices);
+ case SparseIndexVector::SparseIndexVector_Uint8Vector:
+ return Copy(src_metadata->array_indices_as_Uint8Vector(), w1_indices);
+ default:
+ break;
+ }
+ return false;
+ };
+ if (ParseSparseIndexVector() == false)
+ throw std::runtime_error("Error during parsing sparsity index information");
+ // Get block size
+ std::vector<int32_t> block_size;
+ for (int i = 0; i < block_rank; ++i)
+ {
+ auto block_metadata = src_sparsity->dim_metadata()->Get(dense_rank + i);
+ if (block_metadata->format() != DimensionType::DimensionType_DENSE)
+ throw std::runtime_error("block dimension must be DENSE.");
+ block_size.push_back(block_metadata->dense_size());
+ }
+ typeInfo.sparsity(std::make_shared<ir::Sparsity>(std::move(w1_segments), std::move(w1_indices),
+ std::move(block_size)));
+ }
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadOperationIO(const Operator *op, ir::OperandIndexSequence &inputs,
+ ir::OperandIndexSequence &outputs)
+{
+ for (const std::int32_t idx : *op->inputs())
+ {
+ // Optional tensors are not supported yet except for FULLY_CONNECTED and BCQ_FULLY_CONNECTED
+ auto check_optional_input = [&]() {
+ auto builtin_code = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
+ if (isOptionalInputTensor(idx) && !allowOptionalInputTensor(builtin_code))
+ throw std::runtime_error(
+ std::string("loader doesn't support optional input tensor yet for ")
+ .append(EnumNameBuiltinOperator(builtin_code)));
+ };
+ check_optional_input();
+ inputs.append(tensorIdxToOperandIdx(idx));
+ }
+
+ for (const std::int32_t idx : *op->outputs())
+ {
+ outputs.append(tensorIdxToOperandIdx(idx));
+ }
+}
+
+template <typename LoaderDomain>
+template <typename Param, typename OptionsType>
+void BaseLoader<LoaderDomain>::loadStridesAndPaddings(Param &param, const OptionsType *options)
+{
+ // Strides
+ param.stride.vertical = options->stride_h();
+ param.stride.horizontal = options->stride_w();
+ // Paddings
+ switch (options->padding())
+ {
+ case Padding::Padding_SAME:
+ param.padding.type = ir::PaddingType::SAME;
+ break;
+ case Padding::Padding_VALID:
+ param.padding.type = ir::PaddingType::VALID;
+ break;
+ default:
+ throw std::runtime_error{"Invalid padding type"};
+ }
+ // param paddings indexes unused
+}
+
+template <typename LoaderDomain>
+template <typename Param>
+void BaseLoader<LoaderDomain>::loadPool2DOptions(Param &param, const Pool2DOptions *options)
+{
+ // Strides and Paddings
+ if (options->stride_h() <= 0 || options->stride_w() <= 0)
+ throw std::runtime_error{"Invalid stride vertical or horizontal - both must be bigger than 0"};
+ loadStridesAndPaddings(param, options);
+ // Filter width and height
+ // Strides
+ if (options->filter_width() <= 0 || options->filter_height() <= 0)
+ throw std::runtime_error{"Invalid filter width or height - both must be bigger than 0"};
+ param.kw = options->filter_width();
+ param.kh = options->filter_height();
+ // Activation
+ param.activation = convertActivation(options->fused_activation_function());
+}
+
+template <typename LoaderDomain>
+template <typename OpIR, typename... Args>
+const OpIR *BaseLoader<LoaderDomain>::loadOperationTo(const Operator *op, ir::Graph &subg,
+ Args &&... args)
+{
+ static_assert(sizeof...(args) <= 1, "You can't have more than 1 arguments!");
+ ir::OperandIndexSequence inputs;
+ ir::OperandIndexSequence outputs;
+
+ loadOperationIO(op, inputs, outputs);
+
+ std::unique_ptr<OpIR> new_op(new OpIR(inputs, outputs, std::forward<Args>(args)...));
+ auto ret = new_op.get();
+ subg.addOperation(std::move(new_op));
+
+ return ret;
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadConv2D(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Conv2D::Param param;
+ const auto *options = op->builtin_options_as_Conv2DOptions();
+ param.activation = convertActivation(options->fused_activation_function());
+ loadStridesAndPaddings(param, options);
+ param.dilation.width_factor = options->dilation_w_factor();
+ param.dilation.height_factor = options->dilation_h_factor();
+
+ loadOperationTo<ir::operation::Conv2D>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadDepthwiseConv2D(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::DepthwiseConv2D::Param param;
+ const auto *options = op->builtin_options_as_DepthwiseConv2DOptions();
+ param.activation = convertActivation(options->fused_activation_function());
+ loadStridesAndPaddings(param, options);
+ param.multiplier = options->depth_multiplier();
+ // Dilation h/w factor unused
+ param.dilation.width_factor = options->dilation_w_factor();
+ param.dilation.height_factor = options->dilation_h_factor();
+
+ loadOperationTo<ir::operation::DepthwiseConv2D>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadTransposeConv(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::TransposeConv::Param param;
+ const auto *options = op->builtin_options_as_TransposeConvOptions();
+ loadStridesAndPaddings(param, options);
+
+ loadOperationTo<ir::operation::TransposeConv>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadPool2D(const Operator *op, ir::Graph &subg,
+ ir::operation::Pool2D::PoolType op_type)
+{
+ ir::operation::Pool2D::Param param;
+ param.op_type = op_type;
+ const auto *options = op->builtin_options_as_Pool2DOptions();
+
+ loadPool2DOptions(param, options);
+
+ loadOperationTo<ir::operation::Pool2D>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadReshape(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Reshape::Param param{};
+ const auto *options = op->builtin_options_as_ReshapeOptions();
+ if (options != nullptr)
+ {
+ const auto *new_shape = options->new_shape();
+ if (new_shape)
+ {
+ for (uint i = 0; i < new_shape->size(); ++i)
+ {
+ param.new_shape.push_back(new_shape->Get(i));
+ }
+ }
+ }
+
+ loadOperationTo<ir::operation::Reshape>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadSoftmax(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Softmax::Param param;
+ const auto *options = op->builtin_options_as_SoftmaxOptions();
+ // Beta
+ param.beta = options->beta();
+
+ loadOperationTo<ir::operation::Softmax>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadConcatenation(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Concat::Param param;
+ const auto *options = op->builtin_options_as_ConcatenationOptions();
+ // Axis
+ param.axis = options->axis();
+ // activation unused
+
+ loadOperationTo<ir::operation::Concat>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadFC(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::FullyConnected::Param param;
+ const auto *options = op->builtin_options_as_FullyConnectedOptions();
+
+ param.activation = convertActivation(options->fused_activation_function());
+ param.weights_format = static_cast<ir::FullyConnectedWeightsFormat>(options->weights_format());
+
+ const auto fc = loadOperationTo<ir::operation::FullyConnected>(op, subg, param);
+
+ const auto &input_operand =
+ subg.operands().at(fc->getInputs().at(ir::operation::FullyConnected::INPUT));
+ auto &weights_operand =
+ subg.operands().at(fc->getInputs().at(ir::operation::FullyConnected::WEIGHT));
+ if (input_operand.typeInfo().type() == ir::DataType::FLOAT32 &&
+ ((weights_operand.typeInfo().type() == ir::DataType::QUANT_UINT8_ASYMM) ||
+ weights_operand.typeInfo().type() == ir::DataType::QUANT_INT8_ASYMM))
+ {
+ weights_operand.type(ir::DataType::QUANT_INT8_SYMM);
+ }
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadAddV2(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::BinaryArithmetic::Param param;
+ param.arithmetic_type = ir::operation::BinaryArithmetic::ArithmeticType::ADD;
+
+ if (op->custom_options() == nullptr)
+ {
+ param.activation = ir::Activation::NONE;
+ }
+ else
+ {
+ size_t custom_op_data_size = op->custom_options()->size();
+ auto custom_op_data = op->custom_options()->Data();
+ auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
+ auto attr_map = data_root.AsMap();
+ const auto fused_activation_func = static_cast<typename LoaderDomain::ActivationFunctionType>(
+ attr_map["fused_activation_function"].AsInt8());
+ param.activation = convertActivation(fused_activation_func);
+ }
+
+ loadOperationTo<ir::operation::BinaryArithmetic>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadBinaryArithmetic(
+ const Operator *op, ir::Graph &subg, ir::operation::BinaryArithmetic::ArithmeticType op_type)
+{
+ ir::operation::BinaryArithmetic::Param param;
+ param.arithmetic_type = op_type;
+ switch (op_type)
+ {
+ case ir::operation::BinaryArithmetic::ArithmeticType::ADD:
+ {
+ const auto *add_options = op->builtin_options_as_AddOptions();
+ param.activation = convertActivation(add_options->fused_activation_function());
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::SUB:
+ {
+ const auto *sub_options = op->builtin_options_as_SubOptions();
+ param.activation = convertActivation(sub_options->fused_activation_function());
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::MUL:
+ {
+ const auto *mul_options = op->builtin_options_as_MulOptions();
+ param.activation = convertActivation(mul_options->fused_activation_function());
+ break;
+ }
+ case ir::operation::BinaryArithmetic::ArithmeticType::DIV:
+ {
+ const auto *div_options = op->builtin_options_as_DivOptions();
+ param.activation = convertActivation(div_options->fused_activation_function());
+ break;
+ }
+ default:
+ assert(false &&
+ "The function 'loadBinaryArithmetic' supports only BinaryArithmetic operations");
+ break;
+ }
+
+ loadOperationTo<ir::operation::BinaryArithmetic>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadPack(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Pack::Param param;
+ const auto *options = op->builtin_options_as_PackOptions();
+ param.num = options->values_count();
+ param.axis = options->axis();
+
+ loadOperationTo<ir::operation::Pack>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadElementwiseActivation(
+ const Operator *op, ir::Graph &subg, ir::operation::ElementwiseActivation::Type op_type,
+ float alpha, float beta)
+{
+ ir::operation::ElementwiseActivation::Param param;
+ param.op_type = op_type;
+ param.alpha = alpha;
+ param.beta = beta;
+
+ loadOperationTo<ir::operation::ElementwiseActivation>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadResizeBilinear(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::ResizeBilinear::Param param;
+ param.align_corners = op->builtin_options_as_ResizeBilinearOptions()->align_corners();
+ param.half_pixel_centers = op->builtin_options_as_ResizeBilinearOptions()->half_pixel_centers();
+
+ loadOperationTo<ir::operation::ResizeBilinear>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadResizeNearestNeighbor(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::ResizeNearestNeighbor::Param param;
+ param.align_corners = op->builtin_options_as_ResizeNearestNeighborOptions()->align_corners();
+
+ loadOperationTo<ir::operation::ResizeNearestNeighbor>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadReduce(const Operator *op, ir::Graph &subg,
+ ir::operation::Reduce::ReduceType reduce_type)
+{
+ ir::operation::Reduce::Param param;
+ param.reduce_type = reduce_type;
+ param.keep_dims = op->builtin_options_as_ReducerOptions()->keep_dims();
+
+ loadOperationTo<ir::operation::Reduce>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadReduceAll(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Reduce::Param param;
+ param.reduce_type = ir::operation::Reduce::ReduceType::ALL;
+ if (op->custom_options() == nullptr)
+ {
+ param.keep_dims = false;
+ }
+ else
+ {
+ size_t custom_op_data_size = op->custom_options()->size();
+ auto custom_op_data = op->custom_options()->Data();
+ auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
+ auto attr_map = data_root.AsMap();
+ param.keep_dims = attr_map["keep_dims"].AsBool();
+ }
+
+ loadOperationTo<ir::operation::Reduce>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadElementwiseBinary(
+ const Operator *op, ir::Graph &subg,
+ ir::operation::ElementwiseBinary::ElementwiseBinaryType op_type)
+{
+ ir::operation::ElementwiseBinary::Param param;
+ param.op_type = op_type;
+
+ loadOperationTo<ir::operation::ElementwiseBinary>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadElementwiseUnary(const Operator *op, ir::Graph &subg,
+ ir::operation::ElementwiseUnary::Type op_type)
+{
+ ir::operation::ElementwiseUnary::Param param;
+ param.op_type = op_type;
+
+ const auto eu = loadOperationTo<ir::operation::ElementwiseUnary>(op, subg, param);
+ if (op_type == ir::operation::ElementwiseUnary::Type::CAST)
+ {
+ auto qasymm8ToUint8 = [](ir::Operand &operand) {
+ if (operand.typeInfo().type() == ir::DataType::QUANT_UINT8_ASYMM)
+ {
+ operand.type(ir::DataType::UINT8);
+ }
+ };
+ qasymm8ToUint8(
+ subg.operands().at(eu->getInputs().at(ir::operation::ElementwiseUnary::Input::INPUT)));
+ qasymm8ToUint8(subg.operands().at(eu->getOutputs().at(0)));
+ }
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadGather(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Gather::Param param;
+ param.axis = op->builtin_options_as_GatherOptions()->axis();
+
+ loadOperationTo<ir::operation::Gather>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadBatchMatMul(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::BatchMatMul::Param param;
+
+ const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
+
+ switch (builtin_op)
+ {
+ case BuiltinOperator::BuiltinOperator_BATCH_MATMUL:
+ param.adj_x = op->builtin_options_as_BatchMatMulOptions()->adjoint_lhs();
+ param.adj_y = op->builtin_options_as_BatchMatMulOptions()->adjoint_rhs();
+ break;
+ case BuiltinOperator::BuiltinOperator_CUSTOM:
+ if (op->custom_options() == nullptr)
+ {
+ param.adj_x = false;
+ param.adj_y = false;
+ }
+ else
+ {
+ size_t custom_op_data_size = op->custom_options()->size();
+ auto custom_op_data = op->custom_options()->Data();
+ auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
+ auto attr_map = data_root.AsMap();
+ param.adj_x = attr_map["adj_x"].AsBool();
+ param.adj_y = attr_map["adj_y"].AsBool();
+ }
+ break;
+ default:
+ throw std::runtime_error(
+ std::string("Wrong loaded operation: ").append(EnumNameBuiltinOperator(builtin_op)) +
+ " as " + EnumNameBuiltinOperator(BuiltinOperator::BuiltinOperator_BATCH_MATMUL));
+ }
+
+ loadOperationTo<ir::operation::BatchMatMul>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadSpaceToDepth(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::SpaceToDepth::Param param;
+ const auto *options = op->builtin_options_as_SpaceToDepthOptions();
+ param.block_size = options->block_size();
+
+ loadOperationTo<ir::operation::SpaceToDepth>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadCustom(const Operator *op, ir::Graph &subg)
+{
+ ir::OperandIndexSequence inputs;
+ ir::OperandIndexSequence outputs;
+
+ assert(op->custom_options_format() == CustomOptionsFormat::CustomOptionsFormat_FLEXBUFFERS &&
+ "Unsupported custom operation options format");
+
+ auto *op_code = _model->operator_codes()->Get(op->opcode_index());
+ auto custom_op_name = op_code->custom_code()->str();
+
+ enum class BuiltinOP
+ {
+ AddV2,
+ ReduceAll,
+ MatrixBandPart,
+ BatchMatMul,
+ Einsum,
+ BroadcastTo,
+ FusedBatchNorm,
+ StatelessRandomUniform,
+ Erf
+ };
+
+ // Mapping from custom op name string to BuiltinOP enum
+ std::map<std::string, BuiltinOP> builtin_map = {
+ {"AddV2", BuiltinOP::AddV2},
+ {"All", BuiltinOP::ReduceAll},
+ {"MatrixBandPart", BuiltinOP::MatrixBandPart},
+ {"BatchMatMulV2", BuiltinOP::BatchMatMul},
+ {"Einsum", BuiltinOP::Einsum},
+ {"FusedBatchNormV3", BuiltinOP::FusedBatchNorm},
+ {"BroadcastTo", BuiltinOP::BroadcastTo},
+ {"StatelessRandomUniform", BuiltinOP::StatelessRandomUniform},
+ {"Erf", BuiltinOP::Erf},
+ };
+
+ try
+ {
+ // Throw out_of_range if it is unknown custom op
+ auto custom_op_id = builtin_map.at(custom_op_name);
+ switch (custom_op_id)
+ {
+ case BuiltinOP::AddV2:
+ loadAddV2(op, subg);
+ break;
+ case BuiltinOP::ReduceAll:
+ loadReduceAll(op, subg);
+ break;
+ case BuiltinOP::MatrixBandPart:
+ loadOperationTo<ir::operation::MatrixBandPart>(op, subg);
+ break;
+ case BuiltinOP::BatchMatMul:
+ loadBatchMatMul(op, subg);
+ break;
+ case BuiltinOP::Einsum:
+ loadEinsum(op, subg);
+ break;
+ case BuiltinOP::BroadcastTo:
+ loadOperationTo<ir::operation::BroadcastTo>(op, subg);
+ break;
+ case BuiltinOP::FusedBatchNorm:
+ loadFusedBatchNorm(op, subg);
+ break;
+ case BuiltinOP::StatelessRandomUniform:
+ loadOperationTo<ir::operation::StatelessRandomUniform>(op, subg);
+ break;
+ case BuiltinOP::Erf:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::ERF);
+ break;
+ default:
+ throw std::runtime_error{
+ "Loader: Custom OP map is defined but operation loader function is not defined"};
+ }
+
+ return;
+ }
+ catch (...)
+ {
+ loadOperationIO(op, inputs, outputs);
+
+ auto constraint = ir::OperandConstraint::createExact(inputs.size());
+
+ size_t custom_op_data_size = op->custom_options()->size();
+ auto custom_op_data = new char[custom_op_data_size];
+ std::copy(op->custom_options()->begin(), op->custom_options()->end(), custom_op_data);
+
+ ir::operation::Custom::Userdata userdata{};
+ userdata.data = custom_op_data;
+ userdata.size = custom_op_data_size;
+
+ auto new_op = std::make_unique<ir::operation::Custom>(constraint, inputs, outputs,
+ custom_op_name, userdata);
+
+ subg.addOperation(std::move(new_op));
+ }
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadSqueeze(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Squeeze::Param param;
+ const auto *options = op->builtin_options_as_SqueezeOptions();
+ const auto *dims = options->squeeze_dims();
+ if (dims)
+ {
+ if (dims->size() > sizeof(param.dims) / sizeof(param.dims[0]))
+ throw std::runtime_error("Squeeze: 'param.ndims' is out of range.");
+ param.ndim = dims->size();
+ for (int i = 0; i < param.ndim; ++i)
+ param.dims[i] = dims->Get(i);
+ }
+
+ loadOperationTo<ir::operation::Squeeze>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadSplit(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Split::Param param;
+ const auto *options = op->builtin_options_as_SplitOptions();
+ param.num_splits = options->num_splits();
+
+ loadOperationTo<ir::operation::Split>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadSplitV(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::SplitV::Param param;
+ const auto *options = op->builtin_options_as_SplitVOptions();
+ param.num_splits = options->num_splits();
+
+ loadOperationTo<ir::operation::SplitV>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadStridedSlice(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::StridedSlice::Param param;
+ const auto *options = op->builtin_options_as_StridedSliceOptions();
+ param.begin_mask = options->begin_mask();
+ param.end_mask = options->end_mask();
+ param.shrink_axis_mask = options->shrink_axis_mask();
+
+ loadOperationTo<ir::operation::StridedSlice>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadUnpack(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Unpack::Param param;
+ const auto *options = op->builtin_options_as_UnpackOptions();
+ param.num = options->num();
+ param.axis = options->axis();
+
+ loadOperationTo<ir::operation::Unpack>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadComparison(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Comparison::Param param;
+ const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
+
+ switch (builtin_op)
+ {
+ case BuiltinOperator::BuiltinOperator_EQUAL:
+ param.comparison_type = ir::operation::Comparison::ComparisonType::Equal;
+ break;
+ case BuiltinOperator::BuiltinOperator_NOT_EQUAL:
+ param.comparison_type = ir::operation::Comparison::ComparisonType::NotEqual;
+ break;
+ case BuiltinOperator::BuiltinOperator_GREATER_EQUAL:
+ param.comparison_type = ir::operation::Comparison::ComparisonType::GreaterEqual;
+ break;
+ case BuiltinOperator::BuiltinOperator_GREATER:
+ param.comparison_type = ir::operation::Comparison::ComparisonType::Greater;
+ break;
+ case BuiltinOperator::BuiltinOperator_LESS_EQUAL:
+ param.comparison_type = ir::operation::Comparison::ComparisonType::LessEqual;
+ break;
+ case BuiltinOperator::BuiltinOperator_LESS:
+ param.comparison_type = ir::operation::Comparison::ComparisonType::Less;
+ break;
+ default:
+ throw std::runtime_error(
+ std::string("Unsupported operation: ").append(EnumNameBuiltinOperator(builtin_op)));
+ }
+
+ loadOperationTo<ir::operation::Comparison>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadEinsum(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::Einsum::Param param;
+ if (op->custom_options() == nullptr)
+ {
+ throw std::runtime_error{"Einsum: empty equation"};
+ }
+ else
+ {
+ size_t custom_op_data_size = op->custom_options()->size();
+ auto custom_op_data = op->custom_options()->Data();
+ auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
+ auto attr_map = data_root.AsMap();
+ param.equation = attr_map["equation"].ToString();
+ }
+
+ const auto es = loadOperationTo<ir::operation::Einsum>(op, subg, param);
+ if (es->getInputs().size() != 2)
+ {
+ throw std::runtime_error{"Einsum: NYI input - only support two inputs"};
+ }
+}
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadFusedBatchNorm(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::FusedBatchNorm::Param param;
+ if (op->custom_options() == nullptr)
+ {
+ throw std::runtime_error{"FusedBatchNorm: empty option"};
+ }
+ else
+ {
+ size_t custom_op_data_size = op->custom_options()->size();
+ auto custom_op_data = op->custom_options()->Data();
+ auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
+ auto attr_map = data_root.AsMap();
+ param.is_training = attr_map["is_training"].AsBool();
+ param.epsilon = attr_map["epsilon"].AsFloat();
+ param.data_format = attr_map["data_format"].ToString();
+ }
+
+ const auto fbn = loadOperationTo<ir::operation::FusedBatchNorm>(op, subg, param);
+
+ if (fbn->getInputs().size() != 5)
+ {
+ throw std::runtime_error{"FusedBatchNorm: NYI input - only support five inputs"};
+ }
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadOneHot(const Operator *op, ir::Graph &subg)
+{
+ if (op->inputs()->size() != 4 || op->outputs()->size() != 1)
+ throw std::runtime_error("OneHot Op has wrong number of input or output tensors.");
+
+ // Set parameter
+ ir::operation::OneHot::Param param;
+ param.axis = op->builtin_options_as_OneHotOptions()->axis();
+
+ loadOperationTo<ir::operation::OneHot>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadIf(const Operator *op, ir::Graph &subg)
+{
+ const auto *options = op->builtin_options_as_IfOptions();
+ const int32_t then_index = options->then_subgraph_index();
+ const int32_t else_index = options->else_subgraph_index();
+
+ verifySubgraphIndex(then_index);
+ verifySubgraphIndex(else_index);
+
+ ir::operation::If::Param param;
+ param.then_subg_index = ir::SubgraphIndex{static_cast<uint32_t>(then_index)};
+ param.else_subg_index = ir::SubgraphIndex{static_cast<uint32_t>(else_index)};
+
+ loadOperationTo<ir::operation::If>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadWhile(const Operator *op, ir::Graph &subg)
+{
+ const auto *options = op->builtin_options_as_WhileOptions();
+ const int32_t cond_index = options->cond_subgraph_index();
+ const int32_t body_index = options->body_subgraph_index();
+
+ verifySubgraphIndex(cond_index);
+ verifySubgraphIndex(body_index);
+
+ ir::operation::While::Param param;
+ param.cond_subg_index = ir::SubgraphIndex{static_cast<uint32_t>(cond_index)};
+ param.body_subg_index = ir::SubgraphIndex{static_cast<uint32_t>(body_index)};
+
+ loadOperationTo<ir::operation::While>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadArgMax(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::ArgMax::Param param;
+ const auto output_type = op->builtin_options_as_ArgMaxOptions()->output_type();
+ switch (output_type)
+ {
+ case TensorType::TensorType_INT32:
+ case TensorType::TensorType_INT64:
+ param.output_type = tensorTypeToDataType(output_type);
+ break;
+ default:
+ throw std::runtime_error("ArgMax: `output_type` must be either int32 or int64.");
+ }
+ auto am = loadOperationTo<ir::operation::ArgMax>(op, subg, param);
+
+ auto &axisOperand = subg.operands().at(am->getInputs().at(ir::operation::ArgMax::Input::AXIS));
+ if (!(axisOperand.operandSize() == 4 && (axisOperand.typeInfo().type() == ir::DataType::INT32 ||
+ axisOperand.typeInfo().type() == ir::DataType::INT64)))
+ throw std::runtime_error("ArgMax: `axis` with an int32 or int64 element is only supported.");
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadLogSoftmax(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::LogSoftmax::Param param;
+ // In tflite, beta is fixed to 1.0 and axis is fixed to -1.
+ param.beta = 1.0f;
+ param.axis = -1;
+
+ loadOperationTo<ir::operation::LogSoftmax>(op, subg, param);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadLeakyRelu(const Operator *op, ir::Graph &subg)
+{
+ float alpha = op->builtin_options_as_LeakyReluOptions()->alpha();
+ loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::LEAKY_RELU, alpha,
+ 1.f);
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadUnidirectionalSequenceLSTM(const Operator *op, ir::Graph &subg)
+{
+ ir::operation::LSTM::Param param;
+ const auto *options = op->builtin_options_as_UnidirectionalSequenceLSTMOptions();
+ param.activation = convertActivation(options->fused_activation_function());
+ param.cell_threshold = options->cell_clip();
+ param.projection_threshold = options->proj_clip();
+ param.time_major = options->time_major();
+ // The asymmetric_quantize_inputs option is unused yet
+
+ ir::OperandIndexSequence inputs;
+ for (const std::int32_t idx : *op->inputs())
+ {
+ inputs.append(tensorIdxToOperandIdx(idx));
+ }
+
+ ir::OperandIndexSequence outputs;
+ // loader doesn't support optional output tensor yet
+ if (op->outputs()->size() != 1)
+ {
+ auto builtin_code = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
+ throw std::runtime_error(std::string("loader doesn't support optional output tensor yet for ")
+ .append(EnumNameBuiltinOperator(builtin_code)));
+ }
+ for (size_t i = 0; i < ir::operation::LSTM::Output::OUTPUT; ++i)
+ {
+ // Add optional outputs
+ outputs.append(ir::OperandIndex());
+ }
+ outputs.append(tensorIdxToOperandIdx(op->outputs()->Get(0)));
+
+ std::unique_ptr<ir::operation::LSTM> new_op(new ir::operation::LSTM(inputs, outputs, param));
+ subg.addOperation(std::move(new_op));
+}
+
+template <typename LoaderDomain>
+void BaseLoader<LoaderDomain>::loadOperation(const Operator *op, ir::Graph &subg)
+{
+ const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
+
+ switch (builtin_op)
+ {
+ case BuiltinOperator::BuiltinOperator_ADD_N:
+ loadOperationTo<ir::operation::AddN>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_CONV_2D:
+ loadConv2D(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_AVERAGE_POOL_2D:
+ loadPool2D(op, subg, ir::operation::Pool2D::PoolType::AVG);
+ return;
+ case BuiltinOperator::BuiltinOperator_DEPTHWISE_CONV_2D:
+ loadDepthwiseConv2D(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_TRANSPOSE_CONV:
+ loadTransposeConv(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_RESHAPE:
+ loadReshape(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_SOFTMAX:
+ loadSoftmax(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_MAX_POOL_2D:
+ loadPool2D(op, subg, ir::operation::Pool2D::PoolType::MAX);
+ return;
+ case BuiltinOperator::BuiltinOperator_CONCATENATION:
+ loadConcatenation(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_FLOOR:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::FLOOR);
+ return;
+ case BuiltinOperator::BuiltinOperator_FULLY_CONNECTED:
+ loadFC(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_ADD:
+ loadBinaryArithmetic(op, subg, ir::operation::BinaryArithmetic::ArithmeticType::ADD);
+ return;
+ case BuiltinOperator::BuiltinOperator_SUB:
+ loadBinaryArithmetic(op, subg, ir::operation::BinaryArithmetic::ArithmeticType::SUB);
+ return;
+ case BuiltinOperator::BuiltinOperator_MUL:
+ loadBinaryArithmetic(op, subg, ir::operation::BinaryArithmetic::ArithmeticType::MUL);
+ return;
+ case BuiltinOperator::BuiltinOperator_DIV:
+ loadBinaryArithmetic(op, subg, ir::operation::BinaryArithmetic::ArithmeticType::DIV);
+ return;
+ case BuiltinOperator::BuiltinOperator_PACK:
+ loadPack(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_RELU:
+ loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::RELU,
+ ir::operation::ElementwiseActivation::infinity, 0.f);
+ return;
+ case BuiltinOperator::BuiltinOperator_RELU_N1_TO_1:
+ loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::RELU, 1.f,
+ -1.f);
+ return;
+ case BuiltinOperator::BuiltinOperator_RELU6:
+ loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::RELU, 6.f,
+ 0.f);
+ return;
+ case BuiltinOperator::BuiltinOperator_RESIZE_BILINEAR:
+ loadResizeBilinear(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR:
+ loadResizeNearestNeighbor(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_RSQRT:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::RSQRT);
+ return;
+ case BuiltinOperator::BuiltinOperator_SELECT:
+ case BuiltinOperator::BuiltinOperator_SELECT_V2:
+ loadOperationTo<ir::operation::Select>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_SQRT:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::SQRT);
+ return;
+ case BuiltinOperator::BuiltinOperator_SQUARED_DIFFERENCE:
+ loadOperationTo<ir::operation::SquaredDifference>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_TANH:
+ loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::TANH, 1.f,
+ 1.f);
+ return;
+ case BuiltinOperator::BuiltinOperator_TRANSPOSE:
+ loadOperationTo<ir::operation::Transpose>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_MEAN:
+ loadReduce(op, subg, ir::operation::Reduce::ReduceType::MEAN);
+ return;
+ case BuiltinOperator::BuiltinOperator_REDUCE_ANY:
+ loadReduce(op, subg, ir::operation::Reduce::ReduceType::ANY);
+ return;
+ case BuiltinOperator::BuiltinOperator_REDUCE_MAX:
+ loadReduce(op, subg, ir::operation::Reduce::ReduceType::MAX);
+ return;
+ case BuiltinOperator::BuiltinOperator_REVERSE_V2:
+ loadOperationTo<ir::operation::Reverse>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_PAD:
+ case BuiltinOperator::BuiltinOperator_PADV2:
+ loadOperationTo<ir::operation::Pad>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_LOGISTIC:
+ loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::LOGISTIC);
+ return;
+ case BuiltinOperator::BuiltinOperator_EXP:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::EXP);
+ return;
+ case BuiltinOperator::BuiltinOperator_EXPAND_DIMS:
+ loadOperationTo<ir::operation::ExpandDims>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_GATHER:
+ loadGather(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_SPACE_TO_BATCH_ND:
+ loadOperationTo<ir::operation::SpaceToBatchND>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_BATCH_TO_SPACE_ND:
+ loadOperationTo<ir::operation::BatchToSpaceND>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_SUM:
+ loadReduce(op, subg, ir::operation::Reduce::ReduceType::SUM);
+ return;
+ case BuiltinOperator::BuiltinOperator_CUSTOM:
+ loadCustom(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_SQUEEZE:
+ loadSqueeze(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_PRELU:
+ loadOperationTo<ir::operation::PReLU>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_SPLIT:
+ loadSplit(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_SPLIT_V:
+ loadSplitV(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_SLICE:
+ loadOperationTo<ir::operation::Slice>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_STRIDED_SLICE:
+ loadStridedSlice(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_UNPACK:
+ loadUnpack(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_MINIMUM:
+ loadElementwiseBinary(op, subg, ir::operation::ElementwiseBinary::ElementwiseBinaryType::MIN);
+ return;
+ case BuiltinOperator::BuiltinOperator_MAXIMUM:
+ loadElementwiseBinary(op, subg, ir::operation::ElementwiseBinary::ElementwiseBinaryType::MAX);
+ return;
+ case BuiltinOperator::BuiltinOperator_CAST:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::CAST);
+ return;
+ case BuiltinOperator::BuiltinOperator_EQUAL:
+ case BuiltinOperator::BuiltinOperator_NOT_EQUAL:
+ case BuiltinOperator::BuiltinOperator_GREATER_EQUAL:
+ case BuiltinOperator::BuiltinOperator_GREATER:
+ case BuiltinOperator::BuiltinOperator_LESS_EQUAL:
+ case BuiltinOperator::BuiltinOperator_LESS:
+ loadComparison(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_ONE_HOT:
+ loadOneHot(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_ABS:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::ABS);
+ return;
+ case BuiltinOperator::BuiltinOperator_COS:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::COS);
+ return;
+ case BuiltinOperator::BuiltinOperator_SIN:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::SIN);
+ return;
+ case BuiltinOperator::BuiltinOperator_SHAPE:
+ loadOperationTo<ir::operation::Shape>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_REDUCE_PROD:
+ loadReduce(op, subg, ir::operation::Reduce::ReduceType::PROD);
+ return;
+ case BuiltinOperator::BuiltinOperator_IF:
+ loadIf(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_WHILE:
+ loadWhile(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_NEG:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::NEG);
+ return;
+ case BuiltinOperator::BuiltinOperator_ARG_MAX:
+ loadArgMax(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_LOG:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::LOG);
+ return;
+ case BuiltinOperator::BuiltinOperator_ROUND:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::ROUND);
+ return;
+ case BuiltinOperator::BuiltinOperator_POW:
+ loadOperationTo<ir::operation::Pow>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_LOGICAL_NOT:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::LOGICAL_NOT);
+ return;
+ case BuiltinOperator::BuiltinOperator_LOGICAL_OR:
+ loadElementwiseBinary(op, subg,
+ ir::operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR);
+ return;
+ case BuiltinOperator::BuiltinOperator_FILL:
+ loadOperationTo<ir::operation::Fill>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_ZEROS_LIKE:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::ZEROS_LIKE);
+ return;
+ case BuiltinOperator::BuiltinOperator_TILE:
+ loadOperationTo<ir::operation::Tile>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_RANGE:
+ loadOperationTo<ir::operation::Range>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_BATCH_MATMUL:
+ loadBatchMatMul(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_LOG_SOFTMAX:
+ loadLogSoftmax(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_QUANTIZE:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::QUANTIZE);
+ return;
+ case BuiltinOperator::BuiltinOperator_DEQUANTIZE:
+ loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::DEQUANTIZE);
+ return;
+ case BuiltinOperator::BuiltinOperator_SPACE_TO_DEPTH:
+ loadSpaceToDepth(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_L2_NORMALIZATION:
+ loadOperationTo<ir::operation::L2Normalization>(op, subg);
+ break;
+ case BuiltinOperator::BuiltinOperator_LEAKY_RELU:
+ loadLeakyRelu(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_RANK:
+ loadOperationTo<ir::operation::Rank>(op, subg);
+ return;
+ case BuiltinOperator::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM:
+ loadUnidirectionalSequenceLSTM(op, subg);
+ return;
+ default:
+ throw std::runtime_error(
+ std::string("Unsupported operation: ").append(EnumNameBuiltinOperator(builtin_op)));
+ }
+}
+
+template <typename LoaderDomain> void BaseLoader<LoaderDomain>::loadModel()
+{
+ LoaderDomain::VerifyModelBuffer(*_verifier.get());
+ _model = LoaderDomain::GetModel(_base);
+ // Version unused
+ // const auto version = _model->version();
+ // Description unused
+ // const auto *description = _model->description();
+ // Metabuffer unsued
+ // const auto *metadata_buffer = _model->metadata_buffer();
+ // Load subgraphs and map operations on subgraph
+ const auto domain_subgraphs = _model->subgraphs();
+ auto subgraphs = std::make_unique<ir::Subgraphs>();
+ for (uint32_t subgraph_index = 0; subgraph_index < domain_subgraphs->size(); ++subgraph_index)
+ {
+ auto subg = loadSubgraph((*_model->subgraphs())[subgraph_index]);
+ subgraphs->push(ir::SubgraphIndex{subgraph_index}, std::move(subg));
+ }
+ _subgraphs = std::move(subgraphs);
+}
+
+} // namespace base_loader
+} // namespace onert
+
+#endif //__BASE_LOADER_BASE_LOADER_H__
diff --git a/runtime/onert/frontend/circle/CMakeLists.txt b/runtime/onert/frontend/circle/CMakeLists.txt
new file mode 100644
index 000000000..e89e86142
--- /dev/null
+++ b/runtime/onert/frontend/circle/CMakeLists.txt
@@ -0,0 +1,20 @@
+if (NOT BUILD_CIRCLE_LOADER)
+ return()
+endif ()
+
+set(CIRCLE_LOADER_SOURCES src/circle_loader.cc)
+
+add_library(circle_loader SHARED ${CIRCLE_LOADER_SOURCES})
+
+target_include_directories(circle_loader PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+target_link_libraries(circle_loader PRIVATE onert_core)
+target_link_libraries(circle_loader PRIVATE base_loader nnfw_common nnfw_coverage)
+target_link_libraries(circle_loader PRIVATE circle_schema)
+
+if(CMAKE_BUILD_TYPE_LC STREQUAL "release")
+ add_custom_command(TARGET circle_loader POST_BUILD
+ COMMAND ${CMAKE_STRIP} "--strip-unneeded" $<TARGET_FILE_NAME:circle_loader>)
+endif()
+
+install(TARGETS circle_loader DESTINATION lib)
diff --git a/runtime/onert/frontend/circle/include/circle_loader.h b/runtime/onert/frontend/circle/include/circle_loader.h
new file mode 100644
index 000000000..675a5b3e7
--- /dev/null
+++ b/runtime/onert/frontend/circle/include/circle_loader.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CIRCLE_CIRCLE_LOADER_H__
+#define __CIRCLE_CIRCLE_LOADER_H__
+
+#include "ir/Graph.h"
+
+#include <memory>
+
+namespace onert
+{
+namespace circle_loader
+{
+std::unique_ptr<ir::Subgraphs> loadModel(const char *filename);
+std::unique_ptr<ir::Subgraphs> loadModel(uint8_t *buffer, size_t size);
+} // namespace circle_loader
+} // namespace onert
+
+#endif // __CIRCLE_CIRCLE_LOADER_H__
diff --git a/runtime/onert/frontend/circle/src/circle_loader.cc b/runtime/onert/frontend/circle/src/circle_loader.cc
new file mode 100644
index 000000000..33e1709a8
--- /dev/null
+++ b/runtime/onert/frontend/circle/src/circle_loader.cc
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "circle_loader.h"
+#include "base_loader.h"
+#include "circle_schema_generated.h"
+
+namespace onert
+{
+namespace circle_loader
+{
+
+namespace
+{
+
+ir::Layout convertDataFormat(circle::DataFormat data_format)
+{
+ switch (data_format)
+ {
+ case circle::DataFormat::DataFormat_CHANNELS_FIRST:
+ return ir::Layout::NCHW;
+ case circle::DataFormat::DataFormat_CHANNELS_LAST:
+ return ir::Layout::NHWC;
+ default:
+ throw std::runtime_error("Unsupported DataFormat");
+ }
+}
+
+struct LoaderDomain
+{
+ using Verifier = flatbuffers::Verifier;
+ using ActivationFunctionType = circle::ActivationFunctionType;
+ using Buffer = circle::Buffer;
+ using BuiltinOperator = circle::BuiltinOperator;
+ using CustomOptionsFormat = circle::CustomOptionsFormat;
+ using Model = circle::Model;
+ using Operator = circle::Operator;
+ using Padding = circle::Padding;
+ using Pool2DOptions = circle::Pool2DOptions;
+ using Tensor = circle::Tensor;
+ using TensorType = circle::TensorType;
+ using SubGraph = circle::SubGraph;
+ using DimensionType = circle::DimensionType;
+ using SparseIndexVector = circle::SparseIndexVector;
+
+ static const char *EnumNameBuiltinOperator(BuiltinOperator e)
+ {
+ return circle::EnumNameBuiltinOperator(e);
+ }
+ static const char *EnumNameActivationFunctionType(ActivationFunctionType e)
+ {
+ return circle::EnumNameActivationFunctionType(e);
+ }
+ static const char *EnumNameTensorType(TensorType e) { return circle::EnumNameTensorType(e); }
+ static const Model *GetModel(const void *buf) { return circle::GetModel(buf); }
+ static bool VerifyModelBuffer(Verifier &verifier) { return circle::VerifyModelBuffer(verifier); }
+};
+
+class CircleLoader final : public base_loader::BaseLoader<LoaderDomain>
+{
+protected:
+ void loadInstanceNorm(const Operator *op, ir::Graph &subg);
+ void loadBCQFullyConnected(const Operator *op, ir::Graph &subg);
+ void loadBCQGather(const Operator *op, ir::Graph &subg);
+
+public:
+ using BaseLoader::BaseLoader;
+
+ bool allowOptionalInputTensor(BuiltinOperator op) override
+ {
+ switch (op)
+ {
+ case BuiltinOperator::BuiltinOperator_FULLY_CONNECTED:
+ case BuiltinOperator::BuiltinOperator_BCQ_FULLY_CONNECTED:
+ case BuiltinOperator::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+private:
+ std::unique_ptr<ir::Graph> loadSubgraph(const circle::SubGraph *circle_subg) override
+ {
+ auto subg = std::make_unique<ir::Graph>();
+ // Load tensors
+ _tensor_to_operand.resize(circle_subg->tensors()->size());
+ for (flatbuffers::uoffset_t i = 0; i < circle_subg->tensors()->size(); ++i)
+ {
+ _tensor_to_operand[i] = loadOperand(circle_subg->tensors()->Get(i), *subg);
+ }
+ // Set inputs
+ for (const std::int32_t input_ind : *circle_subg->inputs())
+ {
+ subg->addInput(tensorIdxToOperandIdx(input_ind),
+ _tensor_names.at(_tensor_to_operand[input_ind]));
+ }
+ // Set outputs
+ for (const std::int32_t output_ind : *circle_subg->outputs())
+ {
+ subg->addOutput(tensorIdxToOperandIdx(output_ind),
+ _tensor_names.at(_tensor_to_operand[output_ind]));
+ }
+ // Create operations
+ for (const auto *op : *circle_subg->operators())
+ {
+ CircleLoader::loadOperation(op, *subg);
+ }
+
+ subg->setLayout(convertDataFormat(circle_subg->data_format()));
+
+ subg->finishBuilding();
+
+ return subg;
+ }
+
+ void loadOperation(const circle::Operator *op, ir::Graph &subg)
+ {
+ const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
+
+ switch (builtin_op)
+ {
+ case circle::BuiltinOperator::BuiltinOperator_INSTANCE_NORM:
+ loadInstanceNorm(op, subg);
+ return;
+ case circle::BuiltinOperator::BuiltinOperator_BCQ_FULLY_CONNECTED:
+ loadBCQFullyConnected(op, subg);
+ return;
+ case circle::BuiltinOperator::BuiltinOperator_BCQ_GATHER:
+ loadBCQGather(op, subg);
+ return;
+ default:
+ BaseLoader::loadOperation(op, subg);
+ return;
+ }
+ }
+};
+
+void CircleLoader::loadInstanceNorm(const Operator *op, ir::Graph &subg)
+{
+ ir::OperandIndexSequence inputs;
+ ir::OperandIndexSequence outputs;
+
+ loadOperationIO(op, inputs, outputs);
+
+ ir::operation::InstanceNorm::Param param;
+ const auto *options = op->builtin_options_as_InstanceNormOptions();
+
+ param.activation = convertActivation(options->fused_activation_function());
+ // Use default value 1e-5 if value of epsilon is zero
+ param.epsilon = options->epsilon() == 0.f ? 1e-5 : options->epsilon();
+
+ std::unique_ptr<ir::Operation> new_op(new ir::operation::InstanceNorm(inputs, outputs, param));
+ subg.addOperation(std::move(new_op));
+}
+
+void CircleLoader::loadBCQGather(const Operator *op, ir::Graph &subg)
+{
+ ir::OperandIndexSequence inputs;
+ ir::OperandIndexSequence outputs;
+
+ loadOperationIO(op, inputs, outputs);
+
+ ir::operation::BCQGather::Param param;
+ const auto *options = op->builtin_options_as_BCQGatherOptions();
+ param.input_hidden_size = options->input_hidden_size();
+ param.axis = options->axis();
+
+ std::unique_ptr<ir::Operation> new_op(new ir::operation::BCQGather(inputs, outputs, param));
+ subg.addOperation(std::move(new_op));
+}
+
+void CircleLoader::loadBCQFullyConnected(const Operator *op, ir::Graph &subg)
+{
+ ir::OperandIndexSequence inputs;
+ ir::OperandIndexSequence outputs;
+
+ loadOperationIO(op, inputs, outputs);
+
+ ir::operation::BCQFullyConnected::Param param;
+ const auto *options = op->builtin_options_as_BCQFullyConnectedOptions();
+ param.weights_hidden_size = options->weights_hidden_size();
+ param.activation = convertActivation(options->fused_activation_function());
+
+ std::unique_ptr<ir::Operation> new_op(
+ new ir::operation::BCQFullyConnected(inputs, outputs, param));
+ subg.addOperation(std::move(new_op));
+}
+
+} // namespace
+
+std::unique_ptr<ir::Subgraphs> loadModel(const char *filename)
+{
+ auto subgraphs = std::make_unique<ir::Subgraphs>();
+ CircleLoader loader(subgraphs);
+ loader.loadFromFile(filename);
+ return subgraphs;
+}
+
+std::unique_ptr<ir::Subgraphs> loadModel(uint8_t *buffer, size_t size)
+{
+ auto subgraphs = std::make_unique<ir::Subgraphs>();
+ CircleLoader loader(subgraphs);
+ loader.loadFromBuffer(buffer, size);
+ return subgraphs;
+}
+
+} // namespace circle_loader
+} // namespace onert
diff --git a/runtime/onert/frontend/circle_schema/CMakeLists.txt b/runtime/onert/frontend/circle_schema/CMakeLists.txt
new file mode 100644
index 000000000..208103f1c
--- /dev/null
+++ b/runtime/onert/frontend/circle_schema/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_library(circle_schema INTERFACE)
+
+nnfw_find_package(FlatBuffers REQUIRED)
+
+target_link_libraries(circle_schema INTERFACE flatbuffers::flatbuffers)
+
+target_include_directories(circle_schema INTERFACE include)
diff --git a/runtime/onert/frontend/circle_schema/include/circle_schema_generated.h b/runtime/onert/frontend/circle_schema/include/circle_schema_generated.h
new file mode 100644
index 000000000..0ff1f72a2
--- /dev/null
+++ b/runtime/onert/frontend/circle_schema/include/circle_schema_generated.h
@@ -0,0 +1,10709 @@
+/*
+ * Copyright (c) 2019-2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2018 The TensorFlow Authors. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// automatically generated by the FlatBuffers compiler, do not modify
+
+#ifndef FLATBUFFERS_GENERATED_CIRCLESCHEMA_CIRCLE_H_
+#define FLATBUFFERS_GENERATED_CIRCLESCHEMA_CIRCLE_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace circle
+{
+
+struct CustomQuantization;
+struct CustomQuantizationBuilder;
+
+struct QuantizationParameters;
+struct QuantizationParametersBuilder;
+
+struct Int32Vector;
+struct Int32VectorBuilder;
+
+struct Uint16Vector;
+struct Uint16VectorBuilder;
+
+struct Uint8Vector;
+struct Uint8VectorBuilder;
+
+struct DimensionMetadata;
+struct DimensionMetadataBuilder;
+
+struct SparsityParameters;
+struct SparsityParametersBuilder;
+
+struct Tensor;
+struct TensorBuilder;
+
+struct Conv2DOptions;
+struct Conv2DOptionsBuilder;
+
+struct Pool2DOptions;
+struct Pool2DOptionsBuilder;
+
+struct DepthwiseConv2DOptions;
+struct DepthwiseConv2DOptionsBuilder;
+
+struct ConcatEmbeddingsOptions;
+struct ConcatEmbeddingsOptionsBuilder;
+
+struct LSHProjectionOptions;
+struct LSHProjectionOptionsBuilder;
+
+struct SVDFOptions;
+struct SVDFOptionsBuilder;
+
+struct RNNOptions;
+struct RNNOptionsBuilder;
+
+struct SequenceRNNOptions;
+struct SequenceRNNOptionsBuilder;
+
+struct BidirectionalSequenceRNNOptions;
+struct BidirectionalSequenceRNNOptionsBuilder;
+
+struct FullyConnectedOptions;
+struct FullyConnectedOptionsBuilder;
+
+struct SoftmaxOptions;
+struct SoftmaxOptionsBuilder;
+
+struct ConcatenationOptions;
+struct ConcatenationOptionsBuilder;
+
+struct AddOptions;
+struct AddOptionsBuilder;
+
+struct MulOptions;
+struct MulOptionsBuilder;
+
+struct L2NormOptions;
+struct L2NormOptionsBuilder;
+
+struct LocalResponseNormalizationOptions;
+struct LocalResponseNormalizationOptionsBuilder;
+
+struct LSTMOptions;
+struct LSTMOptionsBuilder;
+
+struct UnidirectionalSequenceLSTMOptions;
+struct UnidirectionalSequenceLSTMOptionsBuilder;
+
+struct BidirectionalSequenceLSTMOptions;
+struct BidirectionalSequenceLSTMOptionsBuilder;
+
+struct ResizeBilinearOptions;
+struct ResizeBilinearOptionsBuilder;
+
+struct ResizeNearestNeighborOptions;
+struct ResizeNearestNeighborOptionsBuilder;
+
+struct CallOptions;
+struct CallOptionsBuilder;
+
+struct PadOptions;
+struct PadOptionsBuilder;
+
+struct PadV2Options;
+struct PadV2OptionsBuilder;
+
+struct ReshapeOptions;
+struct ReshapeOptionsBuilder;
+
+struct SpaceToBatchNDOptions;
+struct SpaceToBatchNDOptionsBuilder;
+
+struct BatchToSpaceNDOptions;
+struct BatchToSpaceNDOptionsBuilder;
+
+struct SkipGramOptions;
+struct SkipGramOptionsBuilder;
+
+struct SpaceToDepthOptions;
+struct SpaceToDepthOptionsBuilder;
+
+struct DepthToSpaceOptions;
+struct DepthToSpaceOptionsBuilder;
+
+struct SubOptions;
+struct SubOptionsBuilder;
+
+struct DivOptions;
+struct DivOptionsBuilder;
+
+struct TopKV2Options;
+struct TopKV2OptionsBuilder;
+
+struct EmbeddingLookupSparseOptions;
+struct EmbeddingLookupSparseOptionsBuilder;
+
+struct GatherOptions;
+struct GatherOptionsBuilder;
+
+struct TransposeOptions;
+struct TransposeOptionsBuilder;
+
+struct ExpOptions;
+struct ExpOptionsBuilder;
+
+struct CosOptions;
+struct CosOptionsBuilder;
+
+struct ReducerOptions;
+struct ReducerOptionsBuilder;
+
+struct SqueezeOptions;
+struct SqueezeOptionsBuilder;
+
+struct SplitOptions;
+struct SplitOptionsBuilder;
+
+struct SplitVOptions;
+struct SplitVOptionsBuilder;
+
+struct StridedSliceOptions;
+struct StridedSliceOptionsBuilder;
+
+struct LogSoftmaxOptions;
+struct LogSoftmaxOptionsBuilder;
+
+struct CastOptions;
+struct CastOptionsBuilder;
+
+struct DequantizeOptions;
+struct DequantizeOptionsBuilder;
+
+struct MaximumMinimumOptions;
+struct MaximumMinimumOptionsBuilder;
+
+struct TileOptions;
+struct TileOptionsBuilder;
+
+struct ArgMaxOptions;
+struct ArgMaxOptionsBuilder;
+
+struct ArgMinOptions;
+struct ArgMinOptionsBuilder;
+
+struct GreaterOptions;
+struct GreaterOptionsBuilder;
+
+struct GreaterEqualOptions;
+struct GreaterEqualOptionsBuilder;
+
+struct LessOptions;
+struct LessOptionsBuilder;
+
+struct LessEqualOptions;
+struct LessEqualOptionsBuilder;
+
+struct NegOptions;
+struct NegOptionsBuilder;
+
+struct SelectOptions;
+struct SelectOptionsBuilder;
+
+struct SliceOptions;
+struct SliceOptionsBuilder;
+
+struct TransposeConvOptions;
+struct TransposeConvOptionsBuilder;
+
+struct ExpandDimsOptions;
+struct ExpandDimsOptionsBuilder;
+
+struct SparseToDenseOptions;
+struct SparseToDenseOptionsBuilder;
+
+struct EqualOptions;
+struct EqualOptionsBuilder;
+
+struct NotEqualOptions;
+struct NotEqualOptionsBuilder;
+
+struct ShapeOptions;
+struct ShapeOptionsBuilder;
+
+struct RankOptions;
+struct RankOptionsBuilder;
+
+struct PowOptions;
+struct PowOptionsBuilder;
+
+struct FakeQuantOptions;
+struct FakeQuantOptionsBuilder;
+
+struct PackOptions;
+struct PackOptionsBuilder;
+
+struct LogicalOrOptions;
+struct LogicalOrOptionsBuilder;
+
+struct OneHotOptions;
+struct OneHotOptionsBuilder;
+
+struct AbsOptions;
+struct AbsOptionsBuilder;
+
+struct HardSwishOptions;
+struct HardSwishOptionsBuilder;
+
+struct LogicalAndOptions;
+struct LogicalAndOptionsBuilder;
+
+struct LogicalNotOptions;
+struct LogicalNotOptionsBuilder;
+
+struct UnpackOptions;
+struct UnpackOptionsBuilder;
+
+struct FloorDivOptions;
+struct FloorDivOptionsBuilder;
+
+struct SquareOptions;
+struct SquareOptionsBuilder;
+
+struct ZerosLikeOptions;
+struct ZerosLikeOptionsBuilder;
+
+struct FillOptions;
+struct FillOptionsBuilder;
+
+struct FloorModOptions;
+struct FloorModOptionsBuilder;
+
+struct RangeOptions;
+struct RangeOptionsBuilder;
+
+struct LeakyReluOptions;
+struct LeakyReluOptionsBuilder;
+
+struct SquaredDifferenceOptions;
+struct SquaredDifferenceOptionsBuilder;
+
+struct MirrorPadOptions;
+struct MirrorPadOptionsBuilder;
+
+struct UniqueOptions;
+struct UniqueOptionsBuilder;
+
+struct ReverseV2Options;
+struct ReverseV2OptionsBuilder;
+
+struct AddNOptions;
+struct AddNOptionsBuilder;
+
+struct GatherNdOptions;
+struct GatherNdOptionsBuilder;
+
+struct WhereOptions;
+struct WhereOptionsBuilder;
+
+struct ReverseSequenceOptions;
+struct ReverseSequenceOptionsBuilder;
+
+struct MatrixDiagOptions;
+struct MatrixDiagOptionsBuilder;
+
+struct QuantizeOptions;
+struct QuantizeOptionsBuilder;
+
+struct MatrixSetDiagOptions;
+struct MatrixSetDiagOptionsBuilder;
+
+struct IfOptions;
+struct IfOptionsBuilder;
+
+struct WhileOptions;
+struct WhileOptionsBuilder;
+
+struct NonMaxSuppressionV4Options;
+struct NonMaxSuppressionV4OptionsBuilder;
+
+struct NonMaxSuppressionV5Options;
+struct NonMaxSuppressionV5OptionsBuilder;
+
+struct ScatterNdOptions;
+struct ScatterNdOptionsBuilder;
+
+struct SelectV2Options;
+struct SelectV2OptionsBuilder;
+
+struct DensifyOptions;
+struct DensifyOptionsBuilder;
+
+struct SegmentSumOptions;
+struct SegmentSumOptionsBuilder;
+
+struct BatchMatMulOptions;
+struct BatchMatMulOptionsBuilder;
+
+struct BCQGatherOptions;
+struct BCQGatherOptionsBuilder;
+
+struct BCQFullyConnectedOptions;
+struct BCQFullyConnectedOptionsBuilder;
+
+struct InstanceNormOptions;
+struct InstanceNormOptionsBuilder;
+
+struct OperatorCode;
+struct OperatorCodeBuilder;
+
+struct Operator;
+struct OperatorBuilder;
+
+struct SubGraph;
+struct SubGraphBuilder;
+
+struct Buffer;
+struct BufferBuilder;
+
+struct Metadata;
+struct MetadataBuilder;
+
+struct Model;
+struct ModelBuilder;
+
+enum TensorType
+{
+ TensorType_FLOAT32 = 0,
+ TensorType_FLOAT16 = 1,
+ TensorType_INT32 = 2,
+ TensorType_UINT8 = 3,
+ TensorType_INT64 = 4,
+ TensorType_STRING = 5,
+ TensorType_BOOL = 6,
+ TensorType_INT16 = 7,
+ TensorType_COMPLEX64 = 8,
+ TensorType_INT8 = 9,
+ TensorType_FLOAT64 = 10,
+ TensorType_MIN = TensorType_FLOAT32,
+ TensorType_MAX = TensorType_FLOAT64
+};
+
+inline const TensorType (&EnumValuesTensorType())[11]
+{
+ static const TensorType values[] = {TensorType_FLOAT32, TensorType_FLOAT16, TensorType_INT32,
+ TensorType_UINT8, TensorType_INT64, TensorType_STRING,
+ TensorType_BOOL, TensorType_INT16, TensorType_COMPLEX64,
+ TensorType_INT8, TensorType_FLOAT64};
+ return values;
+}
+
+inline const char *const *EnumNamesTensorType()
+{
+ static const char *const names[12] = {"FLOAT32", "FLOAT16", "INT32", "UINT8",
+ "INT64", "STRING", "BOOL", "INT16",
+ "COMPLEX64", "INT8", "FLOAT64", nullptr};
+ return names;
+}
+
+inline const char *EnumNameTensorType(TensorType e)
+{
+ if (flatbuffers::IsOutRange(e, TensorType_FLOAT32, TensorType_FLOAT64))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesTensorType()[index];
+}
+
+enum QuantizationDetails
+{
+ QuantizationDetails_NONE = 0,
+ QuantizationDetails_CustomQuantization = 1,
+ QuantizationDetails_MIN = QuantizationDetails_NONE,
+ QuantizationDetails_MAX = QuantizationDetails_CustomQuantization
+};
+
+inline const QuantizationDetails (&EnumValuesQuantizationDetails())[2]
+{
+ static const QuantizationDetails values[] = {QuantizationDetails_NONE,
+ QuantizationDetails_CustomQuantization};
+ return values;
+}
+
+inline const char *const *EnumNamesQuantizationDetails()
+{
+ static const char *const names[3] = {"NONE", "CustomQuantization", nullptr};
+ return names;
+}
+
+inline const char *EnumNameQuantizationDetails(QuantizationDetails e)
+{
+ if (flatbuffers::IsOutRange(e, QuantizationDetails_NONE, QuantizationDetails_CustomQuantization))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesQuantizationDetails()[index];
+}
+
+template <typename T> struct QuantizationDetailsTraits
+{
+ static const QuantizationDetails enum_value = QuantizationDetails_NONE;
+};
+
+template <> struct QuantizationDetailsTraits<circle::CustomQuantization>
+{
+ static const QuantizationDetails enum_value = QuantizationDetails_CustomQuantization;
+};
+
+bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj,
+ QuantizationDetails type);
+bool VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types);
+
+enum DimensionType
+{
+ DimensionType_DENSE = 0,
+ DimensionType_SPARSE_CSR = 1,
+ DimensionType_MIN = DimensionType_DENSE,
+ DimensionType_MAX = DimensionType_SPARSE_CSR
+};
+
+inline const DimensionType (&EnumValuesDimensionType())[2]
+{
+ static const DimensionType values[] = {DimensionType_DENSE, DimensionType_SPARSE_CSR};
+ return values;
+}
+
+inline const char *const *EnumNamesDimensionType()
+{
+ static const char *const names[3] = {"DENSE", "SPARSE_CSR", nullptr};
+ return names;
+}
+
+inline const char *EnumNameDimensionType(DimensionType e)
+{
+ if (flatbuffers::IsOutRange(e, DimensionType_DENSE, DimensionType_SPARSE_CSR))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesDimensionType()[index];
+}
+
+enum SparseIndexVector
+{
+ SparseIndexVector_NONE = 0,
+ SparseIndexVector_Int32Vector = 1,
+ SparseIndexVector_Uint16Vector = 2,
+ SparseIndexVector_Uint8Vector = 3,
+ SparseIndexVector_MIN = SparseIndexVector_NONE,
+ SparseIndexVector_MAX = SparseIndexVector_Uint8Vector
+};
+
+inline const SparseIndexVector (&EnumValuesSparseIndexVector())[4]
+{
+ static const SparseIndexVector values[] = {SparseIndexVector_NONE, SparseIndexVector_Int32Vector,
+ SparseIndexVector_Uint16Vector,
+ SparseIndexVector_Uint8Vector};
+ return values;
+}
+
+inline const char *const *EnumNamesSparseIndexVector()
+{
+ static const char *const names[5] = {"NONE", "Int32Vector", "Uint16Vector", "Uint8Vector",
+ nullptr};
+ return names;
+}
+
+inline const char *EnumNameSparseIndexVector(SparseIndexVector e)
+{
+ if (flatbuffers::IsOutRange(e, SparseIndexVector_NONE, SparseIndexVector_Uint8Vector))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesSparseIndexVector()[index];
+}
+
+template <typename T> struct SparseIndexVectorTraits
+{
+ static const SparseIndexVector enum_value = SparseIndexVector_NONE;
+};
+
+template <> struct SparseIndexVectorTraits<circle::Int32Vector>
+{
+ static const SparseIndexVector enum_value = SparseIndexVector_Int32Vector;
+};
+
+template <> struct SparseIndexVectorTraits<circle::Uint16Vector>
+{
+ static const SparseIndexVector enum_value = SparseIndexVector_Uint16Vector;
+};
+
+template <> struct SparseIndexVectorTraits<circle::Uint8Vector>
+{
+ static const SparseIndexVector enum_value = SparseIndexVector_Uint8Vector;
+};
+
+bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj,
+ SparseIndexVector type);
+bool VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types);
+
+enum BuiltinOperator
+{
+ BuiltinOperator_ADD = 0,
+ BuiltinOperator_AVERAGE_POOL_2D = 1,
+ BuiltinOperator_CONCATENATION = 2,
+ BuiltinOperator_CONV_2D = 3,
+ BuiltinOperator_DEPTHWISE_CONV_2D = 4,
+ BuiltinOperator_DEPTH_TO_SPACE = 5,
+ BuiltinOperator_DEQUANTIZE = 6,
+ BuiltinOperator_EMBEDDING_LOOKUP = 7,
+ BuiltinOperator_FLOOR = 8,
+ BuiltinOperator_FULLY_CONNECTED = 9,
+ BuiltinOperator_HASHTABLE_LOOKUP = 10,
+ BuiltinOperator_L2_NORMALIZATION = 11,
+ BuiltinOperator_L2_POOL_2D = 12,
+ BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION = 13,
+ BuiltinOperator_LOGISTIC = 14,
+ BuiltinOperator_LSH_PROJECTION = 15,
+ BuiltinOperator_LSTM = 16,
+ BuiltinOperator_MAX_POOL_2D = 17,
+ BuiltinOperator_MUL = 18,
+ BuiltinOperator_RELU = 19,
+ BuiltinOperator_RELU_N1_TO_1 = 20,
+ BuiltinOperator_RELU6 = 21,
+ BuiltinOperator_RESHAPE = 22,
+ BuiltinOperator_RESIZE_BILINEAR = 23,
+ BuiltinOperator_RNN = 24,
+ BuiltinOperator_SOFTMAX = 25,
+ BuiltinOperator_SPACE_TO_DEPTH = 26,
+ BuiltinOperator_SVDF = 27,
+ BuiltinOperator_TANH = 28,
+ BuiltinOperator_CONCAT_EMBEDDINGS = 29,
+ BuiltinOperator_SKIP_GRAM = 30,
+ BuiltinOperator_CALL = 31,
+ BuiltinOperator_CUSTOM = 32,
+ BuiltinOperator_EMBEDDING_LOOKUP_SPARSE = 33,
+ BuiltinOperator_PAD = 34,
+ BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN = 35,
+ BuiltinOperator_GATHER = 36,
+ BuiltinOperator_BATCH_TO_SPACE_ND = 37,
+ BuiltinOperator_SPACE_TO_BATCH_ND = 38,
+ BuiltinOperator_TRANSPOSE = 39,
+ BuiltinOperator_MEAN = 40,
+ BuiltinOperator_SUB = 41,
+ BuiltinOperator_DIV = 42,
+ BuiltinOperator_SQUEEZE = 43,
+ BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44,
+ BuiltinOperator_STRIDED_SLICE = 45,
+ BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN = 46,
+ BuiltinOperator_EXP = 47,
+ BuiltinOperator_TOPK_V2 = 48,
+ BuiltinOperator_SPLIT = 49,
+ BuiltinOperator_LOG_SOFTMAX = 50,
+ BuiltinOperator_DELEGATE = 51,
+ BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM = 52,
+ BuiltinOperator_CAST = 53,
+ BuiltinOperator_PRELU = 54,
+ BuiltinOperator_MAXIMUM = 55,
+ BuiltinOperator_ARG_MAX = 56,
+ BuiltinOperator_MINIMUM = 57,
+ BuiltinOperator_LESS = 58,
+ BuiltinOperator_NEG = 59,
+ BuiltinOperator_PADV2 = 60,
+ BuiltinOperator_GREATER = 61,
+ BuiltinOperator_GREATER_EQUAL = 62,
+ BuiltinOperator_LESS_EQUAL = 63,
+ BuiltinOperator_SELECT = 64,
+ BuiltinOperator_SLICE = 65,
+ BuiltinOperator_SIN = 66,
+ BuiltinOperator_TRANSPOSE_CONV = 67,
+ BuiltinOperator_SPARSE_TO_DENSE = 68,
+ BuiltinOperator_TILE = 69,
+ BuiltinOperator_EXPAND_DIMS = 70,
+ BuiltinOperator_EQUAL = 71,
+ BuiltinOperator_NOT_EQUAL = 72,
+ BuiltinOperator_LOG = 73,
+ BuiltinOperator_SUM = 74,
+ BuiltinOperator_SQRT = 75,
+ BuiltinOperator_RSQRT = 76,
+ BuiltinOperator_SHAPE = 77,
+ BuiltinOperator_POW = 78,
+ BuiltinOperator_ARG_MIN = 79,
+ BuiltinOperator_FAKE_QUANT = 80,
+ BuiltinOperator_REDUCE_PROD = 81,
+ BuiltinOperator_REDUCE_MAX = 82,
+ BuiltinOperator_PACK = 83,
+ BuiltinOperator_LOGICAL_OR = 84,
+ BuiltinOperator_ONE_HOT = 85,
+ BuiltinOperator_LOGICAL_AND = 86,
+ BuiltinOperator_LOGICAL_NOT = 87,
+ BuiltinOperator_UNPACK = 88,
+ BuiltinOperator_REDUCE_MIN = 89,
+ BuiltinOperator_FLOOR_DIV = 90,
+ BuiltinOperator_REDUCE_ANY = 91,
+ BuiltinOperator_SQUARE = 92,
+ BuiltinOperator_ZEROS_LIKE = 93,
+ BuiltinOperator_FILL = 94,
+ BuiltinOperator_FLOOR_MOD = 95,
+ BuiltinOperator_RANGE = 96,
+ BuiltinOperator_RESIZE_NEAREST_NEIGHBOR = 97,
+ BuiltinOperator_LEAKY_RELU = 98,
+ BuiltinOperator_SQUARED_DIFFERENCE = 99,
+ BuiltinOperator_MIRROR_PAD = 100,
+ BuiltinOperator_ABS = 101,
+ BuiltinOperator_SPLIT_V = 102,
+ BuiltinOperator_UNIQUE = 103,
+ BuiltinOperator_CEIL = 104,
+ BuiltinOperator_REVERSE_V2 = 105,
+ BuiltinOperator_ADD_N = 106,
+ BuiltinOperator_GATHER_ND = 107,
+ BuiltinOperator_COS = 108,
+ BuiltinOperator_WHERE = 109,
+ BuiltinOperator_RANK = 110,
+ BuiltinOperator_ELU = 111,
+ BuiltinOperator_REVERSE_SEQUENCE = 112,
+ BuiltinOperator_MATRIX_DIAG = 113,
+ BuiltinOperator_QUANTIZE = 114,
+ BuiltinOperator_MATRIX_SET_DIAG = 115,
+ BuiltinOperator_ROUND = 116,
+ BuiltinOperator_HARD_SWISH = 117,
+ BuiltinOperator_IF = 118,
+ BuiltinOperator_WHILE = 119,
+ BuiltinOperator_NON_MAX_SUPPRESSION_V4 = 120,
+ BuiltinOperator_NON_MAX_SUPPRESSION_V5 = 121,
+ BuiltinOperator_SCATTER_ND = 122,
+ BuiltinOperator_SELECT_V2 = 123,
+ BuiltinOperator_DENSIFY = 124,
+ BuiltinOperator_SEGMENT_SUM = 125,
+ BuiltinOperator_BATCH_MATMUL = 126,
+ BuiltinOperator_BCQ_GATHER = 252,
+ BuiltinOperator_BCQ_FULLY_CONNECTED = 253,
+ BuiltinOperator_INSTANCE_NORM = 254,
+ BuiltinOperator_MIN = BuiltinOperator_ADD,
+ BuiltinOperator_MAX = BuiltinOperator_INSTANCE_NORM
+};
+
+inline const BuiltinOperator (&EnumValuesBuiltinOperator())[130]
+{
+ static const BuiltinOperator values[] = {BuiltinOperator_ADD,
+ BuiltinOperator_AVERAGE_POOL_2D,
+ BuiltinOperator_CONCATENATION,
+ BuiltinOperator_CONV_2D,
+ BuiltinOperator_DEPTHWISE_CONV_2D,
+ BuiltinOperator_DEPTH_TO_SPACE,
+ BuiltinOperator_DEQUANTIZE,
+ BuiltinOperator_EMBEDDING_LOOKUP,
+ BuiltinOperator_FLOOR,
+ BuiltinOperator_FULLY_CONNECTED,
+ BuiltinOperator_HASHTABLE_LOOKUP,
+ BuiltinOperator_L2_NORMALIZATION,
+ BuiltinOperator_L2_POOL_2D,
+ BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION,
+ BuiltinOperator_LOGISTIC,
+ BuiltinOperator_LSH_PROJECTION,
+ BuiltinOperator_LSTM,
+ BuiltinOperator_MAX_POOL_2D,
+ BuiltinOperator_MUL,
+ BuiltinOperator_RELU,
+ BuiltinOperator_RELU_N1_TO_1,
+ BuiltinOperator_RELU6,
+ BuiltinOperator_RESHAPE,
+ BuiltinOperator_RESIZE_BILINEAR,
+ BuiltinOperator_RNN,
+ BuiltinOperator_SOFTMAX,
+ BuiltinOperator_SPACE_TO_DEPTH,
+ BuiltinOperator_SVDF,
+ BuiltinOperator_TANH,
+ BuiltinOperator_CONCAT_EMBEDDINGS,
+ BuiltinOperator_SKIP_GRAM,
+ BuiltinOperator_CALL,
+ BuiltinOperator_CUSTOM,
+ BuiltinOperator_EMBEDDING_LOOKUP_SPARSE,
+ BuiltinOperator_PAD,
+ BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN,
+ BuiltinOperator_GATHER,
+ BuiltinOperator_BATCH_TO_SPACE_ND,
+ BuiltinOperator_SPACE_TO_BATCH_ND,
+ BuiltinOperator_TRANSPOSE,
+ BuiltinOperator_MEAN,
+ BuiltinOperator_SUB,
+ BuiltinOperator_DIV,
+ BuiltinOperator_SQUEEZE,
+ BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM,
+ BuiltinOperator_STRIDED_SLICE,
+ BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN,
+ BuiltinOperator_EXP,
+ BuiltinOperator_TOPK_V2,
+ BuiltinOperator_SPLIT,
+ BuiltinOperator_LOG_SOFTMAX,
+ BuiltinOperator_DELEGATE,
+ BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM,
+ BuiltinOperator_CAST,
+ BuiltinOperator_PRELU,
+ BuiltinOperator_MAXIMUM,
+ BuiltinOperator_ARG_MAX,
+ BuiltinOperator_MINIMUM,
+ BuiltinOperator_LESS,
+ BuiltinOperator_NEG,
+ BuiltinOperator_PADV2,
+ BuiltinOperator_GREATER,
+ BuiltinOperator_GREATER_EQUAL,
+ BuiltinOperator_LESS_EQUAL,
+ BuiltinOperator_SELECT,
+ BuiltinOperator_SLICE,
+ BuiltinOperator_SIN,
+ BuiltinOperator_TRANSPOSE_CONV,
+ BuiltinOperator_SPARSE_TO_DENSE,
+ BuiltinOperator_TILE,
+ BuiltinOperator_EXPAND_DIMS,
+ BuiltinOperator_EQUAL,
+ BuiltinOperator_NOT_EQUAL,
+ BuiltinOperator_LOG,
+ BuiltinOperator_SUM,
+ BuiltinOperator_SQRT,
+ BuiltinOperator_RSQRT,
+ BuiltinOperator_SHAPE,
+ BuiltinOperator_POW,
+ BuiltinOperator_ARG_MIN,
+ BuiltinOperator_FAKE_QUANT,
+ BuiltinOperator_REDUCE_PROD,
+ BuiltinOperator_REDUCE_MAX,
+ BuiltinOperator_PACK,
+ BuiltinOperator_LOGICAL_OR,
+ BuiltinOperator_ONE_HOT,
+ BuiltinOperator_LOGICAL_AND,
+ BuiltinOperator_LOGICAL_NOT,
+ BuiltinOperator_UNPACK,
+ BuiltinOperator_REDUCE_MIN,
+ BuiltinOperator_FLOOR_DIV,
+ BuiltinOperator_REDUCE_ANY,
+ BuiltinOperator_SQUARE,
+ BuiltinOperator_ZEROS_LIKE,
+ BuiltinOperator_FILL,
+ BuiltinOperator_FLOOR_MOD,
+ BuiltinOperator_RANGE,
+ BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
+ BuiltinOperator_LEAKY_RELU,
+ BuiltinOperator_SQUARED_DIFFERENCE,
+ BuiltinOperator_MIRROR_PAD,
+ BuiltinOperator_ABS,
+ BuiltinOperator_SPLIT_V,
+ BuiltinOperator_UNIQUE,
+ BuiltinOperator_CEIL,
+ BuiltinOperator_REVERSE_V2,
+ BuiltinOperator_ADD_N,
+ BuiltinOperator_GATHER_ND,
+ BuiltinOperator_COS,
+ BuiltinOperator_WHERE,
+ BuiltinOperator_RANK,
+ BuiltinOperator_ELU,
+ BuiltinOperator_REVERSE_SEQUENCE,
+ BuiltinOperator_MATRIX_DIAG,
+ BuiltinOperator_QUANTIZE,
+ BuiltinOperator_MATRIX_SET_DIAG,
+ BuiltinOperator_ROUND,
+ BuiltinOperator_HARD_SWISH,
+ BuiltinOperator_IF,
+ BuiltinOperator_WHILE,
+ BuiltinOperator_NON_MAX_SUPPRESSION_V4,
+ BuiltinOperator_NON_MAX_SUPPRESSION_V5,
+ BuiltinOperator_SCATTER_ND,
+ BuiltinOperator_SELECT_V2,
+ BuiltinOperator_DENSIFY,
+ BuiltinOperator_SEGMENT_SUM,
+ BuiltinOperator_BATCH_MATMUL,
+ BuiltinOperator_BCQ_GATHER,
+ BuiltinOperator_BCQ_FULLY_CONNECTED,
+ BuiltinOperator_INSTANCE_NORM};
+ return values;
+}
+
+inline const char *const *EnumNamesBuiltinOperator()
+{
+ static const char *const names[256] = {"ADD",
+ "AVERAGE_POOL_2D",
+ "CONCATENATION",
+ "CONV_2D",
+ "DEPTHWISE_CONV_2D",
+ "DEPTH_TO_SPACE",
+ "DEQUANTIZE",
+ "EMBEDDING_LOOKUP",
+ "FLOOR",
+ "FULLY_CONNECTED",
+ "HASHTABLE_LOOKUP",
+ "L2_NORMALIZATION",
+ "L2_POOL_2D",
+ "LOCAL_RESPONSE_NORMALIZATION",
+ "LOGISTIC",
+ "LSH_PROJECTION",
+ "LSTM",
+ "MAX_POOL_2D",
+ "MUL",
+ "RELU",
+ "RELU_N1_TO_1",
+ "RELU6",
+ "RESHAPE",
+ "RESIZE_BILINEAR",
+ "RNN",
+ "SOFTMAX",
+ "SPACE_TO_DEPTH",
+ "SVDF",
+ "TANH",
+ "CONCAT_EMBEDDINGS",
+ "SKIP_GRAM",
+ "CALL",
+ "CUSTOM",
+ "EMBEDDING_LOOKUP_SPARSE",
+ "PAD",
+ "UNIDIRECTIONAL_SEQUENCE_RNN",
+ "GATHER",
+ "BATCH_TO_SPACE_ND",
+ "SPACE_TO_BATCH_ND",
+ "TRANSPOSE",
+ "MEAN",
+ "SUB",
+ "DIV",
+ "SQUEEZE",
+ "UNIDIRECTIONAL_SEQUENCE_LSTM",
+ "STRIDED_SLICE",
+ "BIDIRECTIONAL_SEQUENCE_RNN",
+ "EXP",
+ "TOPK_V2",
+ "SPLIT",
+ "LOG_SOFTMAX",
+ "DELEGATE",
+ "BIDIRECTIONAL_SEQUENCE_LSTM",
+ "CAST",
+ "PRELU",
+ "MAXIMUM",
+ "ARG_MAX",
+ "MINIMUM",
+ "LESS",
+ "NEG",
+ "PADV2",
+ "GREATER",
+ "GREATER_EQUAL",
+ "LESS_EQUAL",
+ "SELECT",
+ "SLICE",
+ "SIN",
+ "TRANSPOSE_CONV",
+ "SPARSE_TO_DENSE",
+ "TILE",
+ "EXPAND_DIMS",
+ "EQUAL",
+ "NOT_EQUAL",
+ "LOG",
+ "SUM",
+ "SQRT",
+ "RSQRT",
+ "SHAPE",
+ "POW",
+ "ARG_MIN",
+ "FAKE_QUANT",
+ "REDUCE_PROD",
+ "REDUCE_MAX",
+ "PACK",
+ "LOGICAL_OR",
+ "ONE_HOT",
+ "LOGICAL_AND",
+ "LOGICAL_NOT",
+ "UNPACK",
+ "REDUCE_MIN",
+ "FLOOR_DIV",
+ "REDUCE_ANY",
+ "SQUARE",
+ "ZEROS_LIKE",
+ "FILL",
+ "FLOOR_MOD",
+ "RANGE",
+ "RESIZE_NEAREST_NEIGHBOR",
+ "LEAKY_RELU",
+ "SQUARED_DIFFERENCE",
+ "MIRROR_PAD",
+ "ABS",
+ "SPLIT_V",
+ "UNIQUE",
+ "CEIL",
+ "REVERSE_V2",
+ "ADD_N",
+ "GATHER_ND",
+ "COS",
+ "WHERE",
+ "RANK",
+ "ELU",
+ "REVERSE_SEQUENCE",
+ "MATRIX_DIAG",
+ "QUANTIZE",
+ "MATRIX_SET_DIAG",
+ "ROUND",
+ "HARD_SWISH",
+ "IF",
+ "WHILE",
+ "NON_MAX_SUPPRESSION_V4",
+ "NON_MAX_SUPPRESSION_V5",
+ "SCATTER_ND",
+ "SELECT_V2",
+ "DENSIFY",
+ "SEGMENT_SUM",
+ "BATCH_MATMUL",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "BCQ_GATHER",
+ "BCQ_FULLY_CONNECTED",
+ "INSTANCE_NORM",
+ nullptr};
+ return names;
+}
+
+inline const char *EnumNameBuiltinOperator(BuiltinOperator e)
+{
+ if (flatbuffers::IsOutRange(e, BuiltinOperator_ADD, BuiltinOperator_INSTANCE_NORM))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesBuiltinOperator()[index];
+}
+
+enum BuiltinOptions
+{
+ BuiltinOptions_NONE = 0,
+ BuiltinOptions_Conv2DOptions = 1,
+ BuiltinOptions_DepthwiseConv2DOptions = 2,
+ BuiltinOptions_ConcatEmbeddingsOptions = 3,
+ BuiltinOptions_LSHProjectionOptions = 4,
+ BuiltinOptions_Pool2DOptions = 5,
+ BuiltinOptions_SVDFOptions = 6,
+ BuiltinOptions_RNNOptions = 7,
+ BuiltinOptions_FullyConnectedOptions = 8,
+ BuiltinOptions_SoftmaxOptions = 9,
+ BuiltinOptions_ConcatenationOptions = 10,
+ BuiltinOptions_AddOptions = 11,
+ BuiltinOptions_L2NormOptions = 12,
+ BuiltinOptions_LocalResponseNormalizationOptions = 13,
+ BuiltinOptions_LSTMOptions = 14,
+ BuiltinOptions_ResizeBilinearOptions = 15,
+ BuiltinOptions_CallOptions = 16,
+ BuiltinOptions_ReshapeOptions = 17,
+ BuiltinOptions_SkipGramOptions = 18,
+ BuiltinOptions_SpaceToDepthOptions = 19,
+ BuiltinOptions_EmbeddingLookupSparseOptions = 20,
+ BuiltinOptions_MulOptions = 21,
+ BuiltinOptions_PadOptions = 22,
+ BuiltinOptions_GatherOptions = 23,
+ BuiltinOptions_BatchToSpaceNDOptions = 24,
+ BuiltinOptions_SpaceToBatchNDOptions = 25,
+ BuiltinOptions_TransposeOptions = 26,
+ BuiltinOptions_ReducerOptions = 27,
+ BuiltinOptions_SubOptions = 28,
+ BuiltinOptions_DivOptions = 29,
+ BuiltinOptions_SqueezeOptions = 30,
+ BuiltinOptions_SequenceRNNOptions = 31,
+ BuiltinOptions_StridedSliceOptions = 32,
+ BuiltinOptions_ExpOptions = 33,
+ BuiltinOptions_TopKV2Options = 34,
+ BuiltinOptions_SplitOptions = 35,
+ BuiltinOptions_LogSoftmaxOptions = 36,
+ BuiltinOptions_CastOptions = 37,
+ BuiltinOptions_DequantizeOptions = 38,
+ BuiltinOptions_MaximumMinimumOptions = 39,
+ BuiltinOptions_ArgMaxOptions = 40,
+ BuiltinOptions_LessOptions = 41,
+ BuiltinOptions_NegOptions = 42,
+ BuiltinOptions_PadV2Options = 43,
+ BuiltinOptions_GreaterOptions = 44,
+ BuiltinOptions_GreaterEqualOptions = 45,
+ BuiltinOptions_LessEqualOptions = 46,
+ BuiltinOptions_SelectOptions = 47,
+ BuiltinOptions_SliceOptions = 48,
+ BuiltinOptions_TransposeConvOptions = 49,
+ BuiltinOptions_SparseToDenseOptions = 50,
+ BuiltinOptions_TileOptions = 51,
+ BuiltinOptions_ExpandDimsOptions = 52,
+ BuiltinOptions_EqualOptions = 53,
+ BuiltinOptions_NotEqualOptions = 54,
+ BuiltinOptions_ShapeOptions = 55,
+ BuiltinOptions_PowOptions = 56,
+ BuiltinOptions_ArgMinOptions = 57,
+ BuiltinOptions_FakeQuantOptions = 58,
+ BuiltinOptions_PackOptions = 59,
+ BuiltinOptions_LogicalOrOptions = 60,
+ BuiltinOptions_OneHotOptions = 61,
+ BuiltinOptions_LogicalAndOptions = 62,
+ BuiltinOptions_LogicalNotOptions = 63,
+ BuiltinOptions_UnpackOptions = 64,
+ BuiltinOptions_FloorDivOptions = 65,
+ BuiltinOptions_SquareOptions = 66,
+ BuiltinOptions_ZerosLikeOptions = 67,
+ BuiltinOptions_FillOptions = 68,
+ BuiltinOptions_BidirectionalSequenceLSTMOptions = 69,
+ BuiltinOptions_BidirectionalSequenceRNNOptions = 70,
+ BuiltinOptions_UnidirectionalSequenceLSTMOptions = 71,
+ BuiltinOptions_FloorModOptions = 72,
+ BuiltinOptions_RangeOptions = 73,
+ BuiltinOptions_ResizeNearestNeighborOptions = 74,
+ BuiltinOptions_LeakyReluOptions = 75,
+ BuiltinOptions_SquaredDifferenceOptions = 76,
+ BuiltinOptions_MirrorPadOptions = 77,
+ BuiltinOptions_AbsOptions = 78,
+ BuiltinOptions_SplitVOptions = 79,
+ BuiltinOptions_UniqueOptions = 80,
+ BuiltinOptions_ReverseV2Options = 81,
+ BuiltinOptions_AddNOptions = 82,
+ BuiltinOptions_GatherNdOptions = 83,
+ BuiltinOptions_CosOptions = 84,
+ BuiltinOptions_WhereOptions = 85,
+ BuiltinOptions_RankOptions = 86,
+ BuiltinOptions_ReverseSequenceOptions = 87,
+ BuiltinOptions_MatrixDiagOptions = 88,
+ BuiltinOptions_QuantizeOptions = 89,
+ BuiltinOptions_MatrixSetDiagOptions = 90,
+ BuiltinOptions_HardSwishOptions = 91,
+ BuiltinOptions_IfOptions = 92,
+ BuiltinOptions_WhileOptions = 93,
+ BuiltinOptions_DepthToSpaceOptions = 94,
+ BuiltinOptions_NonMaxSuppressionV4Options = 95,
+ BuiltinOptions_NonMaxSuppressionV5Options = 96,
+ BuiltinOptions_ScatterNdOptions = 97,
+ BuiltinOptions_SelectV2Options = 98,
+ BuiltinOptions_DensifyOptions = 99,
+ BuiltinOptions_SegmentSumOptions = 100,
+ BuiltinOptions_BatchMatMulOptions = 101,
+ BuiltinOptions_BCQGatherOptions = 252,
+ BuiltinOptions_BCQFullyConnectedOptions = 253,
+ BuiltinOptions_InstanceNormOptions = 254,
+ BuiltinOptions_MIN = BuiltinOptions_NONE,
+ BuiltinOptions_MAX = BuiltinOptions_InstanceNormOptions
+};
+
+inline const BuiltinOptions (&EnumValuesBuiltinOptions())[105]
+{
+ static const BuiltinOptions values[] = {BuiltinOptions_NONE,
+ BuiltinOptions_Conv2DOptions,
+ BuiltinOptions_DepthwiseConv2DOptions,
+ BuiltinOptions_ConcatEmbeddingsOptions,
+ BuiltinOptions_LSHProjectionOptions,
+ BuiltinOptions_Pool2DOptions,
+ BuiltinOptions_SVDFOptions,
+ BuiltinOptions_RNNOptions,
+ BuiltinOptions_FullyConnectedOptions,
+ BuiltinOptions_SoftmaxOptions,
+ BuiltinOptions_ConcatenationOptions,
+ BuiltinOptions_AddOptions,
+ BuiltinOptions_L2NormOptions,
+ BuiltinOptions_LocalResponseNormalizationOptions,
+ BuiltinOptions_LSTMOptions,
+ BuiltinOptions_ResizeBilinearOptions,
+ BuiltinOptions_CallOptions,
+ BuiltinOptions_ReshapeOptions,
+ BuiltinOptions_SkipGramOptions,
+ BuiltinOptions_SpaceToDepthOptions,
+ BuiltinOptions_EmbeddingLookupSparseOptions,
+ BuiltinOptions_MulOptions,
+ BuiltinOptions_PadOptions,
+ BuiltinOptions_GatherOptions,
+ BuiltinOptions_BatchToSpaceNDOptions,
+ BuiltinOptions_SpaceToBatchNDOptions,
+ BuiltinOptions_TransposeOptions,
+ BuiltinOptions_ReducerOptions,
+ BuiltinOptions_SubOptions,
+ BuiltinOptions_DivOptions,
+ BuiltinOptions_SqueezeOptions,
+ BuiltinOptions_SequenceRNNOptions,
+ BuiltinOptions_StridedSliceOptions,
+ BuiltinOptions_ExpOptions,
+ BuiltinOptions_TopKV2Options,
+ BuiltinOptions_SplitOptions,
+ BuiltinOptions_LogSoftmaxOptions,
+ BuiltinOptions_CastOptions,
+ BuiltinOptions_DequantizeOptions,
+ BuiltinOptions_MaximumMinimumOptions,
+ BuiltinOptions_ArgMaxOptions,
+ BuiltinOptions_LessOptions,
+ BuiltinOptions_NegOptions,
+ BuiltinOptions_PadV2Options,
+ BuiltinOptions_GreaterOptions,
+ BuiltinOptions_GreaterEqualOptions,
+ BuiltinOptions_LessEqualOptions,
+ BuiltinOptions_SelectOptions,
+ BuiltinOptions_SliceOptions,
+ BuiltinOptions_TransposeConvOptions,
+ BuiltinOptions_SparseToDenseOptions,
+ BuiltinOptions_TileOptions,
+ BuiltinOptions_ExpandDimsOptions,
+ BuiltinOptions_EqualOptions,
+ BuiltinOptions_NotEqualOptions,
+ BuiltinOptions_ShapeOptions,
+ BuiltinOptions_PowOptions,
+ BuiltinOptions_ArgMinOptions,
+ BuiltinOptions_FakeQuantOptions,
+ BuiltinOptions_PackOptions,
+ BuiltinOptions_LogicalOrOptions,
+ BuiltinOptions_OneHotOptions,
+ BuiltinOptions_LogicalAndOptions,
+ BuiltinOptions_LogicalNotOptions,
+ BuiltinOptions_UnpackOptions,
+ BuiltinOptions_FloorDivOptions,
+ BuiltinOptions_SquareOptions,
+ BuiltinOptions_ZerosLikeOptions,
+ BuiltinOptions_FillOptions,
+ BuiltinOptions_BidirectionalSequenceLSTMOptions,
+ BuiltinOptions_BidirectionalSequenceRNNOptions,
+ BuiltinOptions_UnidirectionalSequenceLSTMOptions,
+ BuiltinOptions_FloorModOptions,
+ BuiltinOptions_RangeOptions,
+ BuiltinOptions_ResizeNearestNeighborOptions,
+ BuiltinOptions_LeakyReluOptions,
+ BuiltinOptions_SquaredDifferenceOptions,
+ BuiltinOptions_MirrorPadOptions,
+ BuiltinOptions_AbsOptions,
+ BuiltinOptions_SplitVOptions,
+ BuiltinOptions_UniqueOptions,
+ BuiltinOptions_ReverseV2Options,
+ BuiltinOptions_AddNOptions,
+ BuiltinOptions_GatherNdOptions,
+ BuiltinOptions_CosOptions,
+ BuiltinOptions_WhereOptions,
+ BuiltinOptions_RankOptions,
+ BuiltinOptions_ReverseSequenceOptions,
+ BuiltinOptions_MatrixDiagOptions,
+ BuiltinOptions_QuantizeOptions,
+ BuiltinOptions_MatrixSetDiagOptions,
+ BuiltinOptions_HardSwishOptions,
+ BuiltinOptions_IfOptions,
+ BuiltinOptions_WhileOptions,
+ BuiltinOptions_DepthToSpaceOptions,
+ BuiltinOptions_NonMaxSuppressionV4Options,
+ BuiltinOptions_NonMaxSuppressionV5Options,
+ BuiltinOptions_ScatterNdOptions,
+ BuiltinOptions_SelectV2Options,
+ BuiltinOptions_DensifyOptions,
+ BuiltinOptions_SegmentSumOptions,
+ BuiltinOptions_BatchMatMulOptions,
+ BuiltinOptions_BCQGatherOptions,
+ BuiltinOptions_BCQFullyConnectedOptions,
+ BuiltinOptions_InstanceNormOptions};
+ return values;
+}
+
+inline const char *const *EnumNamesBuiltinOptions()
+{
+ static const char *const names[256] = {"NONE",
+ "Conv2DOptions",
+ "DepthwiseConv2DOptions",
+ "ConcatEmbeddingsOptions",
+ "LSHProjectionOptions",
+ "Pool2DOptions",
+ "SVDFOptions",
+ "RNNOptions",
+ "FullyConnectedOptions",
+ "SoftmaxOptions",
+ "ConcatenationOptions",
+ "AddOptions",
+ "L2NormOptions",
+ "LocalResponseNormalizationOptions",
+ "LSTMOptions",
+ "ResizeBilinearOptions",
+ "CallOptions",
+ "ReshapeOptions",
+ "SkipGramOptions",
+ "SpaceToDepthOptions",
+ "EmbeddingLookupSparseOptions",
+ "MulOptions",
+ "PadOptions",
+ "GatherOptions",
+ "BatchToSpaceNDOptions",
+ "SpaceToBatchNDOptions",
+ "TransposeOptions",
+ "ReducerOptions",
+ "SubOptions",
+ "DivOptions",
+ "SqueezeOptions",
+ "SequenceRNNOptions",
+ "StridedSliceOptions",
+ "ExpOptions",
+ "TopKV2Options",
+ "SplitOptions",
+ "LogSoftmaxOptions",
+ "CastOptions",
+ "DequantizeOptions",
+ "MaximumMinimumOptions",
+ "ArgMaxOptions",
+ "LessOptions",
+ "NegOptions",
+ "PadV2Options",
+ "GreaterOptions",
+ "GreaterEqualOptions",
+ "LessEqualOptions",
+ "SelectOptions",
+ "SliceOptions",
+ "TransposeConvOptions",
+ "SparseToDenseOptions",
+ "TileOptions",
+ "ExpandDimsOptions",
+ "EqualOptions",
+ "NotEqualOptions",
+ "ShapeOptions",
+ "PowOptions",
+ "ArgMinOptions",
+ "FakeQuantOptions",
+ "PackOptions",
+ "LogicalOrOptions",
+ "OneHotOptions",
+ "LogicalAndOptions",
+ "LogicalNotOptions",
+ "UnpackOptions",
+ "FloorDivOptions",
+ "SquareOptions",
+ "ZerosLikeOptions",
+ "FillOptions",
+ "BidirectionalSequenceLSTMOptions",
+ "BidirectionalSequenceRNNOptions",
+ "UnidirectionalSequenceLSTMOptions",
+ "FloorModOptions",
+ "RangeOptions",
+ "ResizeNearestNeighborOptions",
+ "LeakyReluOptions",
+ "SquaredDifferenceOptions",
+ "MirrorPadOptions",
+ "AbsOptions",
+ "SplitVOptions",
+ "UniqueOptions",
+ "ReverseV2Options",
+ "AddNOptions",
+ "GatherNdOptions",
+ "CosOptions",
+ "WhereOptions",
+ "RankOptions",
+ "ReverseSequenceOptions",
+ "MatrixDiagOptions",
+ "QuantizeOptions",
+ "MatrixSetDiagOptions",
+ "HardSwishOptions",
+ "IfOptions",
+ "WhileOptions",
+ "DepthToSpaceOptions",
+ "NonMaxSuppressionV4Options",
+ "NonMaxSuppressionV5Options",
+ "ScatterNdOptions",
+ "SelectV2Options",
+ "DensifyOptions",
+ "SegmentSumOptions",
+ "BatchMatMulOptions",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "BCQGatherOptions",
+ "BCQFullyConnectedOptions",
+ "InstanceNormOptions",
+ nullptr};
+ return names;
+}
+
+inline const char *EnumNameBuiltinOptions(BuiltinOptions e)
+{
+ if (flatbuffers::IsOutRange(e, BuiltinOptions_NONE, BuiltinOptions_InstanceNormOptions))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesBuiltinOptions()[index];
+}
+
+template <typename T> struct BuiltinOptionsTraits
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NONE;
+};
+
+template <> struct BuiltinOptionsTraits<circle::Conv2DOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_Conv2DOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::DepthwiseConv2DOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DepthwiseConv2DOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ConcatEmbeddingsOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ConcatEmbeddingsOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LSHProjectionOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LSHProjectionOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::Pool2DOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_Pool2DOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SVDFOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SVDFOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::RNNOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_RNNOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::FullyConnectedOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FullyConnectedOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SoftmaxOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SoftmaxOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ConcatenationOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ConcatenationOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::AddOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_AddOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::L2NormOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_L2NormOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LocalResponseNormalizationOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LocalResponseNormalizationOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LSTMOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LSTMOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ResizeBilinearOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ResizeBilinearOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::CallOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_CallOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ReshapeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ReshapeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SkipGramOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SkipGramOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SpaceToDepthOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SpaceToDepthOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::EmbeddingLookupSparseOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_EmbeddingLookupSparseOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::MulOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MulOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::PadOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_PadOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::GatherOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_GatherOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::BatchToSpaceNDOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BatchToSpaceNDOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SpaceToBatchNDOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SpaceToBatchNDOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::TransposeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_TransposeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ReducerOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ReducerOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SubOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SubOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::DivOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DivOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SqueezeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SqueezeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SequenceRNNOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SequenceRNNOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::StridedSliceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_StridedSliceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ExpOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ExpOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::TopKV2Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_TopKV2Options;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SplitOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SplitOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LogSoftmaxOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LogSoftmaxOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::CastOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_CastOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::DequantizeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DequantizeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::MaximumMinimumOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MaximumMinimumOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ArgMaxOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ArgMaxOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LessOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LessOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::NegOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NegOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::PadV2Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_PadV2Options;
+};
+
+template <> struct BuiltinOptionsTraits<circle::GreaterOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_GreaterOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::GreaterEqualOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_GreaterEqualOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LessEqualOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LessEqualOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SelectOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SelectOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SliceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SliceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::TransposeConvOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_TransposeConvOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SparseToDenseOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SparseToDenseOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::TileOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_TileOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ExpandDimsOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ExpandDimsOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::EqualOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_EqualOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::NotEqualOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NotEqualOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ShapeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ShapeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::PowOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_PowOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ArgMinOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ArgMinOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::FakeQuantOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FakeQuantOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::PackOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_PackOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LogicalOrOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LogicalOrOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::OneHotOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_OneHotOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LogicalAndOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LogicalAndOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LogicalNotOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LogicalNotOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::UnpackOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_UnpackOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::FloorDivOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FloorDivOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SquareOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SquareOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ZerosLikeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ZerosLikeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::FillOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FillOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::BidirectionalSequenceLSTMOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceLSTMOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::BidirectionalSequenceRNNOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceRNNOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::UnidirectionalSequenceLSTMOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_UnidirectionalSequenceLSTMOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::FloorModOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FloorModOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::RangeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_RangeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ResizeNearestNeighborOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ResizeNearestNeighborOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::LeakyReluOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LeakyReluOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SquaredDifferenceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SquaredDifferenceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::MirrorPadOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MirrorPadOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::AbsOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_AbsOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SplitVOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SplitVOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::UniqueOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_UniqueOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ReverseV2Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ReverseV2Options;
+};
+
+template <> struct BuiltinOptionsTraits<circle::AddNOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_AddNOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::GatherNdOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_GatherNdOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::CosOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_CosOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::WhereOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_WhereOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::RankOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_RankOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ReverseSequenceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ReverseSequenceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::MatrixDiagOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MatrixDiagOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::QuantizeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_QuantizeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::MatrixSetDiagOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MatrixSetDiagOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::HardSwishOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_HardSwishOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::IfOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_IfOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::WhileOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_WhileOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::DepthToSpaceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DepthToSpaceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::NonMaxSuppressionV4Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV4Options;
+};
+
+template <> struct BuiltinOptionsTraits<circle::NonMaxSuppressionV5Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV5Options;
+};
+
+template <> struct BuiltinOptionsTraits<circle::ScatterNdOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ScatterNdOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SelectV2Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SelectV2Options;
+};
+
+template <> struct BuiltinOptionsTraits<circle::DensifyOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DensifyOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::SegmentSumOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SegmentSumOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::BatchMatMulOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BatchMatMulOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::BCQGatherOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BCQGatherOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::BCQFullyConnectedOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BCQFullyConnectedOptions;
+};
+
+template <> struct BuiltinOptionsTraits<circle::InstanceNormOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_InstanceNormOptions;
+};
+
+bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type);
+bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types);
+
+enum Padding
+{
+ Padding_SAME = 0,
+ Padding_VALID = 1,
+ Padding_MIN = Padding_SAME,
+ Padding_MAX = Padding_VALID
+};
+
+inline const Padding (&EnumValuesPadding())[2]
+{
+ static const Padding values[] = {Padding_SAME, Padding_VALID};
+ return values;
+}
+
+inline const char *const *EnumNamesPadding()
+{
+ static const char *const names[3] = {"SAME", "VALID", nullptr};
+ return names;
+}
+
+inline const char *EnumNamePadding(Padding e)
+{
+ if (flatbuffers::IsOutRange(e, Padding_SAME, Padding_VALID))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesPadding()[index];
+}
+
+enum ActivationFunctionType
+{
+ ActivationFunctionType_NONE = 0,
+ ActivationFunctionType_RELU = 1,
+ ActivationFunctionType_RELU_N1_TO_1 = 2,
+ ActivationFunctionType_RELU6 = 3,
+ ActivationFunctionType_TANH = 4,
+ ActivationFunctionType_SIGN_BIT = 5,
+ ActivationFunctionType_MIN = ActivationFunctionType_NONE,
+ ActivationFunctionType_MAX = ActivationFunctionType_SIGN_BIT
+};
+
+inline const ActivationFunctionType (&EnumValuesActivationFunctionType())[6]
+{
+ static const ActivationFunctionType values[] = {
+ ActivationFunctionType_NONE, ActivationFunctionType_RELU,
+ ActivationFunctionType_RELU_N1_TO_1, ActivationFunctionType_RELU6,
+ ActivationFunctionType_TANH, ActivationFunctionType_SIGN_BIT};
+ return values;
+}
+
+inline const char *const *EnumNamesActivationFunctionType()
+{
+ static const char *const names[7] = {"NONE", "RELU", "RELU_N1_TO_1", "RELU6",
+ "TANH", "SIGN_BIT", nullptr};
+ return names;
+}
+
+inline const char *EnumNameActivationFunctionType(ActivationFunctionType e)
+{
+ if (flatbuffers::IsOutRange(e, ActivationFunctionType_NONE, ActivationFunctionType_SIGN_BIT))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesActivationFunctionType()[index];
+}
+
+enum LSHProjectionType
+{
+ LSHProjectionType_UNKNOWN = 0,
+ LSHProjectionType_SPARSE = 1,
+ LSHProjectionType_DENSE = 2,
+ LSHProjectionType_MIN = LSHProjectionType_UNKNOWN,
+ LSHProjectionType_MAX = LSHProjectionType_DENSE
+};
+
+inline const LSHProjectionType (&EnumValuesLSHProjectionType())[3]
+{
+ static const LSHProjectionType values[] = {LSHProjectionType_UNKNOWN, LSHProjectionType_SPARSE,
+ LSHProjectionType_DENSE};
+ return values;
+}
+
+inline const char *const *EnumNamesLSHProjectionType()
+{
+ static const char *const names[4] = {"UNKNOWN", "SPARSE", "DENSE", nullptr};
+ return names;
+}
+
+inline const char *EnumNameLSHProjectionType(LSHProjectionType e)
+{
+ if (flatbuffers::IsOutRange(e, LSHProjectionType_UNKNOWN, LSHProjectionType_DENSE))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesLSHProjectionType()[index];
+}
+
+enum FullyConnectedOptionsWeightsFormat
+{
+ FullyConnectedOptionsWeightsFormat_DEFAULT = 0,
+ FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 = 1,
+ FullyConnectedOptionsWeightsFormat_SHUFFLED16x1FLOAT32 = 127,
+ FullyConnectedOptionsWeightsFormat_MIN = FullyConnectedOptionsWeightsFormat_DEFAULT,
+ FullyConnectedOptionsWeightsFormat_MAX = FullyConnectedOptionsWeightsFormat_SHUFFLED16x1FLOAT32
+};
+
+inline const FullyConnectedOptionsWeightsFormat (&EnumValuesFullyConnectedOptionsWeightsFormat())[3]
+{
+ static const FullyConnectedOptionsWeightsFormat values[] = {
+ FullyConnectedOptionsWeightsFormat_DEFAULT,
+ FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8,
+ FullyConnectedOptionsWeightsFormat_SHUFFLED16x1FLOAT32};
+ return values;
+}
+
+inline const char *EnumNameFullyConnectedOptionsWeightsFormat(FullyConnectedOptionsWeightsFormat e)
+{
+ switch (e)
+ {
+ case FullyConnectedOptionsWeightsFormat_DEFAULT:
+ return "DEFAULT";
+ case FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8:
+ return "SHUFFLED4x16INT8";
+ case FullyConnectedOptionsWeightsFormat_SHUFFLED16x1FLOAT32:
+ return "SHUFFLED16x1FLOAT32";
+ default:
+ return "";
+ }
+}
+
+enum LSTMKernelType
+{
+ LSTMKernelType_FULL = 0,
+ LSTMKernelType_BASIC = 1,
+ LSTMKernelType_MIN = LSTMKernelType_FULL,
+ LSTMKernelType_MAX = LSTMKernelType_BASIC
+};
+
+inline const LSTMKernelType (&EnumValuesLSTMKernelType())[2]
+{
+ static const LSTMKernelType values[] = {LSTMKernelType_FULL, LSTMKernelType_BASIC};
+ return values;
+}
+
+inline const char *const *EnumNamesLSTMKernelType()
+{
+ static const char *const names[3] = {"FULL", "BASIC", nullptr};
+ return names;
+}
+
+inline const char *EnumNameLSTMKernelType(LSTMKernelType e)
+{
+ if (flatbuffers::IsOutRange(e, LSTMKernelType_FULL, LSTMKernelType_BASIC))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesLSTMKernelType()[index];
+}
+
+enum CombinerType
+{
+ CombinerType_SUM = 0,
+ CombinerType_MEAN = 1,
+ CombinerType_SQRTN = 2,
+ CombinerType_MIN = CombinerType_SUM,
+ CombinerType_MAX = CombinerType_SQRTN
+};
+
+inline const CombinerType (&EnumValuesCombinerType())[3]
+{
+ static const CombinerType values[] = {CombinerType_SUM, CombinerType_MEAN, CombinerType_SQRTN};
+ return values;
+}
+
+inline const char *const *EnumNamesCombinerType()
+{
+ static const char *const names[4] = {"SUM", "MEAN", "SQRTN", nullptr};
+ return names;
+}
+
+inline const char *EnumNameCombinerType(CombinerType e)
+{
+ if (flatbuffers::IsOutRange(e, CombinerType_SUM, CombinerType_SQRTN))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesCombinerType()[index];
+}
+
+enum MirrorPadMode
+{
+ MirrorPadMode_REFLECT = 0,
+ MirrorPadMode_SYMMETRIC = 1,
+ MirrorPadMode_MIN = MirrorPadMode_REFLECT,
+ MirrorPadMode_MAX = MirrorPadMode_SYMMETRIC
+};
+
+inline const MirrorPadMode (&EnumValuesMirrorPadMode())[2]
+{
+ static const MirrorPadMode values[] = {MirrorPadMode_REFLECT, MirrorPadMode_SYMMETRIC};
+ return values;
+}
+
+inline const char *const *EnumNamesMirrorPadMode()
+{
+ static const char *const names[3] = {"REFLECT", "SYMMETRIC", nullptr};
+ return names;
+}
+
+inline const char *EnumNameMirrorPadMode(MirrorPadMode e)
+{
+ if (flatbuffers::IsOutRange(e, MirrorPadMode_REFLECT, MirrorPadMode_SYMMETRIC))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesMirrorPadMode()[index];
+}
+
+enum CustomOptionsFormat
+{
+ CustomOptionsFormat_FLEXBUFFERS = 0,
+ CustomOptionsFormat_MIN = CustomOptionsFormat_FLEXBUFFERS,
+ CustomOptionsFormat_MAX = CustomOptionsFormat_FLEXBUFFERS
+};
+
+inline const CustomOptionsFormat (&EnumValuesCustomOptionsFormat())[1]
+{
+ static const CustomOptionsFormat values[] = {CustomOptionsFormat_FLEXBUFFERS};
+ return values;
+}
+
+inline const char *const *EnumNamesCustomOptionsFormat()
+{
+ static const char *const names[2] = {"FLEXBUFFERS", nullptr};
+ return names;
+}
+
+inline const char *EnumNameCustomOptionsFormat(CustomOptionsFormat e)
+{
+ if (flatbuffers::IsOutRange(e, CustomOptionsFormat_FLEXBUFFERS, CustomOptionsFormat_FLEXBUFFERS))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesCustomOptionsFormat()[index];
+}
+
+enum DataFormat
+{
+ DataFormat_CHANNELS_LAST = 0,
+ DataFormat_CHANNELS_FIRST = 1,
+ DataFormat_MIN = DataFormat_CHANNELS_LAST,
+ DataFormat_MAX = DataFormat_CHANNELS_FIRST
+};
+
+inline const DataFormat (&EnumValuesDataFormat())[2]
+{
+ static const DataFormat values[] = {DataFormat_CHANNELS_LAST, DataFormat_CHANNELS_FIRST};
+ return values;
+}
+
+inline const char *const *EnumNamesDataFormat()
+{
+ static const char *const names[3] = {"CHANNELS_LAST", "CHANNELS_FIRST", nullptr};
+ return names;
+}
+
+inline const char *EnumNameDataFormat(DataFormat e)
+{
+ if (flatbuffers::IsOutRange(e, DataFormat_CHANNELS_LAST, DataFormat_CHANNELS_FIRST))
+ return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesDataFormat()[index];
+}
+
+struct CustomQuantization FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef CustomQuantizationBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_CUSTOM = 4
+ };
+ const flatbuffers::Vector<uint8_t> *custom() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_CUSTOM);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_CUSTOM) &&
+ verifier.VerifyVector(custom()) && verifier.EndTable();
+ }
+};
+
+struct CustomQuantizationBuilder
+{
+ typedef CustomQuantization Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_custom(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> custom)
+ {
+ fbb_.AddOffset(CustomQuantization::VT_CUSTOM, custom);
+ }
+ explicit CustomQuantizationBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ CustomQuantizationBuilder &operator=(const CustomQuantizationBuilder &);
+ flatbuffers::Offset<CustomQuantization> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CustomQuantization>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CustomQuantization>
+CreateCustomQuantization(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> custom = 0)
+{
+ CustomQuantizationBuilder builder_(_fbb);
+ builder_.add_custom(custom);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<CustomQuantization>
+CreateCustomQuantizationDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<uint8_t> *custom = nullptr)
+{
+ if (custom)
+ {
+ _fbb.ForceVectorAlignment(custom->size(), sizeof(uint8_t), 16);
+ }
+ auto custom__ = custom ? _fbb.CreateVector<uint8_t>(*custom) : 0;
+ return circle::CreateCustomQuantization(_fbb, custom__);
+}
+
+struct QuantizationParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef QuantizationParametersBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_MIN = 4,
+ VT_MAX = 6,
+ VT_SCALE = 8,
+ VT_ZERO_POINT = 10,
+ VT_DETAILS_TYPE = 12,
+ VT_DETAILS = 14,
+ VT_QUANTIZED_DIMENSION = 16
+ };
+ const flatbuffers::Vector<float> *min() const
+ {
+ return GetPointer<const flatbuffers::Vector<float> *>(VT_MIN);
+ }
+ const flatbuffers::Vector<float> *max() const
+ {
+ return GetPointer<const flatbuffers::Vector<float> *>(VT_MAX);
+ }
+ const flatbuffers::Vector<float> *scale() const
+ {
+ return GetPointer<const flatbuffers::Vector<float> *>(VT_SCALE);
+ }
+ const flatbuffers::Vector<int64_t> *zero_point() const
+ {
+ return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_ZERO_POINT);
+ }
+ circle::QuantizationDetails details_type() const
+ {
+ return static_cast<circle::QuantizationDetails>(GetField<uint8_t>(VT_DETAILS_TYPE, 0));
+ }
+ const void *details() const { return GetPointer<const void *>(VT_DETAILS); }
+ template <typename T> const T *details_as() const;
+ const circle::CustomQuantization *details_as_CustomQuantization() const
+ {
+ return details_type() == circle::QuantizationDetails_CustomQuantization
+ ? static_cast<const circle::CustomQuantization *>(details())
+ : nullptr;
+ }
+ int32_t quantized_dimension() const { return GetField<int32_t>(VT_QUANTIZED_DIMENSION, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_MIN) &&
+ verifier.VerifyVector(min()) && VerifyOffset(verifier, VT_MAX) &&
+ verifier.VerifyVector(max()) && VerifyOffset(verifier, VT_SCALE) &&
+ verifier.VerifyVector(scale()) && VerifyOffset(verifier, VT_ZERO_POINT) &&
+ verifier.VerifyVector(zero_point()) && VerifyField<uint8_t>(verifier, VT_DETAILS_TYPE) &&
+ VerifyOffset(verifier, VT_DETAILS) &&
+ VerifyQuantizationDetails(verifier, details(), details_type()) &&
+ VerifyField<int32_t>(verifier, VT_QUANTIZED_DIMENSION) && verifier.EndTable();
+ }
+};
+
+template <>
+inline const circle::CustomQuantization *
+QuantizationParameters::details_as<circle::CustomQuantization>() const
+{
+ return details_as_CustomQuantization();
+}
+
+struct QuantizationParametersBuilder
+{
+ typedef QuantizationParameters Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_min(flatbuffers::Offset<flatbuffers::Vector<float>> min)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_MIN, min);
+ }
+ void add_max(flatbuffers::Offset<flatbuffers::Vector<float>> max)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_MAX, max);
+ }
+ void add_scale(flatbuffers::Offset<flatbuffers::Vector<float>> scale)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_SCALE, scale);
+ }
+ void add_zero_point(flatbuffers::Offset<flatbuffers::Vector<int64_t>> zero_point)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_ZERO_POINT, zero_point);
+ }
+ void add_details_type(circle::QuantizationDetails details_type)
+ {
+ fbb_.AddElement<uint8_t>(QuantizationParameters::VT_DETAILS_TYPE,
+ static_cast<uint8_t>(details_type), 0);
+ }
+ void add_details(flatbuffers::Offset<void> details)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_DETAILS, details);
+ }
+ void add_quantized_dimension(int32_t quantized_dimension)
+ {
+ fbb_.AddElement<int32_t>(QuantizationParameters::VT_QUANTIZED_DIMENSION, quantized_dimension,
+ 0);
+ }
+ explicit QuantizationParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ QuantizationParametersBuilder &operator=(const QuantizationParametersBuilder &);
+ flatbuffers::Offset<QuantizationParameters> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<QuantizationParameters>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<QuantizationParameters> CreateQuantizationParameters(
+ flatbuffers::FlatBufferBuilder &_fbb, flatbuffers::Offset<flatbuffers::Vector<float>> min = 0,
+ flatbuffers::Offset<flatbuffers::Vector<float>> max = 0,
+ flatbuffers::Offset<flatbuffers::Vector<float>> scale = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int64_t>> zero_point = 0,
+ circle::QuantizationDetails details_type = circle::QuantizationDetails_NONE,
+ flatbuffers::Offset<void> details = 0, int32_t quantized_dimension = 0)
+{
+ QuantizationParametersBuilder builder_(_fbb);
+ builder_.add_quantized_dimension(quantized_dimension);
+ builder_.add_details(details);
+ builder_.add_zero_point(zero_point);
+ builder_.add_scale(scale);
+ builder_.add_max(max);
+ builder_.add_min(min);
+ builder_.add_details_type(details_type);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<QuantizationParameters> CreateQuantizationParametersDirect(
+ flatbuffers::FlatBufferBuilder &_fbb, const std::vector<float> *min = nullptr,
+ const std::vector<float> *max = nullptr, const std::vector<float> *scale = nullptr,
+ const std::vector<int64_t> *zero_point = nullptr,
+ circle::QuantizationDetails details_type = circle::QuantizationDetails_NONE,
+ flatbuffers::Offset<void> details = 0, int32_t quantized_dimension = 0)
+{
+ auto min__ = min ? _fbb.CreateVector<float>(*min) : 0;
+ auto max__ = max ? _fbb.CreateVector<float>(*max) : 0;
+ auto scale__ = scale ? _fbb.CreateVector<float>(*scale) : 0;
+ auto zero_point__ = zero_point ? _fbb.CreateVector<int64_t>(*zero_point) : 0;
+ return circle::CreateQuantizationParameters(_fbb, min__, max__, scale__, zero_point__,
+ details_type, details, quantized_dimension);
+}
+
+struct Int32Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef Int32VectorBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_VALUES = 4
+ };
+ const flatbuffers::Vector<int32_t> *values() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_VALUES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) &&
+ verifier.VerifyVector(values()) && verifier.EndTable();
+ }
+};
+
+struct Int32VectorBuilder
+{
+ typedef Int32Vector Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_values(flatbuffers::Offset<flatbuffers::Vector<int32_t>> values)
+ {
+ fbb_.AddOffset(Int32Vector::VT_VALUES, values);
+ }
+ explicit Int32VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Int32VectorBuilder &operator=(const Int32VectorBuilder &);
+ flatbuffers::Offset<Int32Vector> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Int32Vector>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Int32Vector>
+CreateInt32Vector(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> values = 0)
+{
+ Int32VectorBuilder builder_(_fbb);
+ builder_.add_values(values);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Int32Vector>
+CreateInt32VectorDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<int32_t> *values = nullptr)
+{
+ auto values__ = values ? _fbb.CreateVector<int32_t>(*values) : 0;
+ return circle::CreateInt32Vector(_fbb, values__);
+}
+
+struct Uint16Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef Uint16VectorBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_VALUES = 4
+ };
+ const flatbuffers::Vector<uint16_t> *values() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint16_t> *>(VT_VALUES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) &&
+ verifier.VerifyVector(values()) && verifier.EndTable();
+ }
+};
+
+struct Uint16VectorBuilder
+{
+ typedef Uint16Vector Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_values(flatbuffers::Offset<flatbuffers::Vector<uint16_t>> values)
+ {
+ fbb_.AddOffset(Uint16Vector::VT_VALUES, values);
+ }
+ explicit Uint16VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Uint16VectorBuilder &operator=(const Uint16VectorBuilder &);
+ flatbuffers::Offset<Uint16Vector> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Uint16Vector>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Uint16Vector>
+CreateUint16Vector(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<uint16_t>> values = 0)
+{
+ Uint16VectorBuilder builder_(_fbb);
+ builder_.add_values(values);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Uint16Vector>
+CreateUint16VectorDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<uint16_t> *values = nullptr)
+{
+ if (values)
+ {
+ _fbb.ForceVectorAlignment(values->size(), sizeof(uint16_t), 4);
+ }
+ auto values__ = values ? _fbb.CreateVector<uint16_t>(*values) : 0;
+ return circle::CreateUint16Vector(_fbb, values__);
+}
+
+struct Uint8Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef Uint8VectorBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_VALUES = 4
+ };
+ const flatbuffers::Vector<uint8_t> *values() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_VALUES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) &&
+ verifier.VerifyVector(values()) && verifier.EndTable();
+ }
+};
+
+struct Uint8VectorBuilder
+{
+ typedef Uint8Vector Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_values(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> values)
+ {
+ fbb_.AddOffset(Uint8Vector::VT_VALUES, values);
+ }
+ explicit Uint8VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Uint8VectorBuilder &operator=(const Uint8VectorBuilder &);
+ flatbuffers::Offset<Uint8Vector> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Uint8Vector>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Uint8Vector>
+CreateUint8Vector(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> values = 0)
+{
+ Uint8VectorBuilder builder_(_fbb);
+ builder_.add_values(values);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Uint8Vector>
+CreateUint8VectorDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<uint8_t> *values = nullptr)
+{
+ if (values)
+ {
+ _fbb.ForceVectorAlignment(values->size(), sizeof(uint8_t), 4);
+ }
+ auto values__ = values ? _fbb.CreateVector<uint8_t>(*values) : 0;
+ return circle::CreateUint8Vector(_fbb, values__);
+}
+
+struct DimensionMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef DimensionMetadataBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FORMAT = 4,
+ VT_DENSE_SIZE = 6,
+ VT_ARRAY_SEGMENTS_TYPE = 8,
+ VT_ARRAY_SEGMENTS = 10,
+ VT_ARRAY_INDICES_TYPE = 12,
+ VT_ARRAY_INDICES = 14
+ };
+ circle::DimensionType format() const
+ {
+ return static_cast<circle::DimensionType>(GetField<int8_t>(VT_FORMAT, 0));
+ }
+ int32_t dense_size() const { return GetField<int32_t>(VT_DENSE_SIZE, 0); }
+ circle::SparseIndexVector array_segments_type() const
+ {
+ return static_cast<circle::SparseIndexVector>(GetField<uint8_t>(VT_ARRAY_SEGMENTS_TYPE, 0));
+ }
+ const void *array_segments() const { return GetPointer<const void *>(VT_ARRAY_SEGMENTS); }
+ template <typename T> const T *array_segments_as() const;
+ const circle::Int32Vector *array_segments_as_Int32Vector() const
+ {
+ return array_segments_type() == circle::SparseIndexVector_Int32Vector
+ ? static_cast<const circle::Int32Vector *>(array_segments())
+ : nullptr;
+ }
+ const circle::Uint16Vector *array_segments_as_Uint16Vector() const
+ {
+ return array_segments_type() == circle::SparseIndexVector_Uint16Vector
+ ? static_cast<const circle::Uint16Vector *>(array_segments())
+ : nullptr;
+ }
+ const circle::Uint8Vector *array_segments_as_Uint8Vector() const
+ {
+ return array_segments_type() == circle::SparseIndexVector_Uint8Vector
+ ? static_cast<const circle::Uint8Vector *>(array_segments())
+ : nullptr;
+ }
+ circle::SparseIndexVector array_indices_type() const
+ {
+ return static_cast<circle::SparseIndexVector>(GetField<uint8_t>(VT_ARRAY_INDICES_TYPE, 0));
+ }
+ const void *array_indices() const { return GetPointer<const void *>(VT_ARRAY_INDICES); }
+ template <typename T> const T *array_indices_as() const;
+ const circle::Int32Vector *array_indices_as_Int32Vector() const
+ {
+ return array_indices_type() == circle::SparseIndexVector_Int32Vector
+ ? static_cast<const circle::Int32Vector *>(array_indices())
+ : nullptr;
+ }
+ const circle::Uint16Vector *array_indices_as_Uint16Vector() const
+ {
+ return array_indices_type() == circle::SparseIndexVector_Uint16Vector
+ ? static_cast<const circle::Uint16Vector *>(array_indices())
+ : nullptr;
+ }
+ const circle::Uint8Vector *array_indices_as_Uint8Vector() const
+ {
+ return array_indices_type() == circle::SparseIndexVector_Uint8Vector
+ ? static_cast<const circle::Uint8Vector *>(array_indices())
+ : nullptr;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_FORMAT) &&
+ VerifyField<int32_t>(verifier, VT_DENSE_SIZE) &&
+ VerifyField<uint8_t>(verifier, VT_ARRAY_SEGMENTS_TYPE) &&
+ VerifyOffset(verifier, VT_ARRAY_SEGMENTS) &&
+ VerifySparseIndexVector(verifier, array_segments(), array_segments_type()) &&
+ VerifyField<uint8_t>(verifier, VT_ARRAY_INDICES_TYPE) &&
+ VerifyOffset(verifier, VT_ARRAY_INDICES) &&
+ VerifySparseIndexVector(verifier, array_indices(), array_indices_type()) &&
+ verifier.EndTable();
+ }
+};
+
+template <>
+inline const circle::Int32Vector *DimensionMetadata::array_segments_as<circle::Int32Vector>() const
+{
+ return array_segments_as_Int32Vector();
+}
+
+template <>
+inline const circle::Uint16Vector *
+DimensionMetadata::array_segments_as<circle::Uint16Vector>() const
+{
+ return array_segments_as_Uint16Vector();
+}
+
+template <>
+inline const circle::Uint8Vector *DimensionMetadata::array_segments_as<circle::Uint8Vector>() const
+{
+ return array_segments_as_Uint8Vector();
+}
+
+template <>
+inline const circle::Int32Vector *DimensionMetadata::array_indices_as<circle::Int32Vector>() const
+{
+ return array_indices_as_Int32Vector();
+}
+
+template <>
+inline const circle::Uint16Vector *DimensionMetadata::array_indices_as<circle::Uint16Vector>() const
+{
+ return array_indices_as_Uint16Vector();
+}
+
+template <>
+inline const circle::Uint8Vector *DimensionMetadata::array_indices_as<circle::Uint8Vector>() const
+{
+ return array_indices_as_Uint8Vector();
+}
+
+struct DimensionMetadataBuilder
+{
+ typedef DimensionMetadata Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_format(circle::DimensionType format)
+ {
+ fbb_.AddElement<int8_t>(DimensionMetadata::VT_FORMAT, static_cast<int8_t>(format), 0);
+ }
+ void add_dense_size(int32_t dense_size)
+ {
+ fbb_.AddElement<int32_t>(DimensionMetadata::VT_DENSE_SIZE, dense_size, 0);
+ }
+ void add_array_segments_type(circle::SparseIndexVector array_segments_type)
+ {
+ fbb_.AddElement<uint8_t>(DimensionMetadata::VT_ARRAY_SEGMENTS_TYPE,
+ static_cast<uint8_t>(array_segments_type), 0);
+ }
+ void add_array_segments(flatbuffers::Offset<void> array_segments)
+ {
+ fbb_.AddOffset(DimensionMetadata::VT_ARRAY_SEGMENTS, array_segments);
+ }
+ void add_array_indices_type(circle::SparseIndexVector array_indices_type)
+ {
+ fbb_.AddElement<uint8_t>(DimensionMetadata::VT_ARRAY_INDICES_TYPE,
+ static_cast<uint8_t>(array_indices_type), 0);
+ }
+ void add_array_indices(flatbuffers::Offset<void> array_indices)
+ {
+ fbb_.AddOffset(DimensionMetadata::VT_ARRAY_INDICES, array_indices);
+ }
+ explicit DimensionMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DimensionMetadataBuilder &operator=(const DimensionMetadataBuilder &);
+ flatbuffers::Offset<DimensionMetadata> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DimensionMetadata>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DimensionMetadata> CreateDimensionMetadata(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::DimensionType format = circle::DimensionType_DENSE, int32_t dense_size = 0,
+ circle::SparseIndexVector array_segments_type = circle::SparseIndexVector_NONE,
+ flatbuffers::Offset<void> array_segments = 0,
+ circle::SparseIndexVector array_indices_type = circle::SparseIndexVector_NONE,
+ flatbuffers::Offset<void> array_indices = 0)
+{
+ DimensionMetadataBuilder builder_(_fbb);
+ builder_.add_array_indices(array_indices);
+ builder_.add_array_segments(array_segments);
+ builder_.add_dense_size(dense_size);
+ builder_.add_array_indices_type(array_indices_type);
+ builder_.add_array_segments_type(array_segments_type);
+ builder_.add_format(format);
+ return builder_.Finish();
+}
+
+struct SparsityParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SparsityParametersBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_TRAVERSAL_ORDER = 4,
+ VT_BLOCK_MAP = 6,
+ VT_DIM_METADATA = 8
+ };
+ const flatbuffers::Vector<int32_t> *traversal_order() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_TRAVERSAL_ORDER);
+ }
+ const flatbuffers::Vector<int32_t> *block_map() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_BLOCK_MAP);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<circle::DimensionMetadata>> *dim_metadata() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<circle::DimensionMetadata>> *>(
+ VT_DIM_METADATA);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TRAVERSAL_ORDER) &&
+ verifier.VerifyVector(traversal_order()) && VerifyOffset(verifier, VT_BLOCK_MAP) &&
+ verifier.VerifyVector(block_map()) && VerifyOffset(verifier, VT_DIM_METADATA) &&
+ verifier.VerifyVector(dim_metadata()) && verifier.VerifyVectorOfTables(dim_metadata()) &&
+ verifier.EndTable();
+ }
+};
+
+struct SparsityParametersBuilder
+{
+ typedef SparsityParameters Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_traversal_order(flatbuffers::Offset<flatbuffers::Vector<int32_t>> traversal_order)
+ {
+ fbb_.AddOffset(SparsityParameters::VT_TRAVERSAL_ORDER, traversal_order);
+ }
+ void add_block_map(flatbuffers::Offset<flatbuffers::Vector<int32_t>> block_map)
+ {
+ fbb_.AddOffset(SparsityParameters::VT_BLOCK_MAP, block_map);
+ }
+ void add_dim_metadata(
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::DimensionMetadata>>>
+ dim_metadata)
+ {
+ fbb_.AddOffset(SparsityParameters::VT_DIM_METADATA, dim_metadata);
+ }
+ explicit SparsityParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SparsityParametersBuilder &operator=(const SparsityParametersBuilder &);
+ flatbuffers::Offset<SparsityParameters> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SparsityParameters>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SparsityParameters> CreateSparsityParameters(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> traversal_order = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> block_map = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::DimensionMetadata>>>
+ dim_metadata = 0)
+{
+ SparsityParametersBuilder builder_(_fbb);
+ builder_.add_dim_metadata(dim_metadata);
+ builder_.add_block_map(block_map);
+ builder_.add_traversal_order(traversal_order);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<SparsityParameters> CreateSparsityParametersDirect(
+ flatbuffers::FlatBufferBuilder &_fbb, const std::vector<int32_t> *traversal_order = nullptr,
+ const std::vector<int32_t> *block_map = nullptr,
+ const std::vector<flatbuffers::Offset<circle::DimensionMetadata>> *dim_metadata = nullptr)
+{
+ auto traversal_order__ = traversal_order ? _fbb.CreateVector<int32_t>(*traversal_order) : 0;
+ auto block_map__ = block_map ? _fbb.CreateVector<int32_t>(*block_map) : 0;
+ auto dim_metadata__ =
+ dim_metadata
+ ? _fbb.CreateVector<flatbuffers::Offset<circle::DimensionMetadata>>(*dim_metadata)
+ : 0;
+ return circle::CreateSparsityParameters(_fbb, traversal_order__, block_map__, dim_metadata__);
+}
+
+struct Tensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef TensorBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_SHAPE = 4,
+ VT_TYPE = 6,
+ VT_BUFFER = 8,
+ VT_NAME = 10,
+ VT_QUANTIZATION = 12,
+ VT_IS_VARIABLE = 14,
+ VT_SPARSITY = 16,
+ VT_SHAPE_SIGNATURE = 18
+ };
+ const flatbuffers::Vector<int32_t> *shape() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_SHAPE);
+ }
+ circle::TensorType type() const
+ {
+ return static_cast<circle::TensorType>(GetField<int8_t>(VT_TYPE, 0));
+ }
+ uint32_t buffer() const { return GetField<uint32_t>(VT_BUFFER, 0); }
+ const flatbuffers::String *name() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ const circle::QuantizationParameters *quantization() const
+ {
+ return GetPointer<const circle::QuantizationParameters *>(VT_QUANTIZATION);
+ }
+ bool is_variable() const { return GetField<uint8_t>(VT_IS_VARIABLE, 0) != 0; }
+ const circle::SparsityParameters *sparsity() const
+ {
+ return GetPointer<const circle::SparsityParameters *>(VT_SPARSITY);
+ }
+ const flatbuffers::Vector<int32_t> *shape_signature() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_SHAPE_SIGNATURE);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SHAPE) &&
+ verifier.VerifyVector(shape()) && VerifyField<int8_t>(verifier, VT_TYPE) &&
+ VerifyField<uint32_t>(verifier, VT_BUFFER) && VerifyOffset(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) && VerifyOffset(verifier, VT_QUANTIZATION) &&
+ verifier.VerifyTable(quantization()) && VerifyField<uint8_t>(verifier, VT_IS_VARIABLE) &&
+ VerifyOffset(verifier, VT_SPARSITY) && verifier.VerifyTable(sparsity()) &&
+ VerifyOffset(verifier, VT_SHAPE_SIGNATURE) && verifier.VerifyVector(shape_signature()) &&
+ verifier.EndTable();
+ }
+};
+
+struct TensorBuilder
+{
+ typedef Tensor Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_shape(flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape)
+ {
+ fbb_.AddOffset(Tensor::VT_SHAPE, shape);
+ }
+ void add_type(circle::TensorType type)
+ {
+ fbb_.AddElement<int8_t>(Tensor::VT_TYPE, static_cast<int8_t>(type), 0);
+ }
+ void add_buffer(uint32_t buffer) { fbb_.AddElement<uint32_t>(Tensor::VT_BUFFER, buffer, 0); }
+ void add_name(flatbuffers::Offset<flatbuffers::String> name)
+ {
+ fbb_.AddOffset(Tensor::VT_NAME, name);
+ }
+ void add_quantization(flatbuffers::Offset<circle::QuantizationParameters> quantization)
+ {
+ fbb_.AddOffset(Tensor::VT_QUANTIZATION, quantization);
+ }
+ void add_is_variable(bool is_variable)
+ {
+ fbb_.AddElement<uint8_t>(Tensor::VT_IS_VARIABLE, static_cast<uint8_t>(is_variable), 0);
+ }
+ void add_sparsity(flatbuffers::Offset<circle::SparsityParameters> sparsity)
+ {
+ fbb_.AddOffset(Tensor::VT_SPARSITY, sparsity);
+ }
+ void add_shape_signature(flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape_signature)
+ {
+ fbb_.AddOffset(Tensor::VT_SHAPE_SIGNATURE, shape_signature);
+ }
+ explicit TensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TensorBuilder &operator=(const TensorBuilder &);
+ flatbuffers::Offset<Tensor> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Tensor>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Tensor>
+CreateTensor(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape = 0,
+ circle::TensorType type = circle::TensorType_FLOAT32, uint32_t buffer = 0,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<circle::QuantizationParameters> quantization = 0,
+ bool is_variable = false, flatbuffers::Offset<circle::SparsityParameters> sparsity = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape_signature = 0)
+{
+ TensorBuilder builder_(_fbb);
+ builder_.add_shape_signature(shape_signature);
+ builder_.add_sparsity(sparsity);
+ builder_.add_quantization(quantization);
+ builder_.add_name(name);
+ builder_.add_buffer(buffer);
+ builder_.add_shape(shape);
+ builder_.add_is_variable(is_variable);
+ builder_.add_type(type);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Tensor> CreateTensorDirect(
+ flatbuffers::FlatBufferBuilder &_fbb, const std::vector<int32_t> *shape = nullptr,
+ circle::TensorType type = circle::TensorType_FLOAT32, uint32_t buffer = 0,
+ const char *name = nullptr,
+ flatbuffers::Offset<circle::QuantizationParameters> quantization = 0, bool is_variable = false,
+ flatbuffers::Offset<circle::SparsityParameters> sparsity = 0,
+ const std::vector<int32_t> *shape_signature = nullptr)
+{
+ auto shape__ = shape ? _fbb.CreateVector<int32_t>(*shape) : 0;
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto shape_signature__ = shape_signature ? _fbb.CreateVector<int32_t>(*shape_signature) : 0;
+ return circle::CreateTensor(_fbb, shape__, type, buffer, name__, quantization, is_variable,
+ sparsity, shape_signature__);
+}
+
+struct Conv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef Conv2DOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_PADDING = 4,
+ VT_STRIDE_W = 6,
+ VT_STRIDE_H = 8,
+ VT_FUSED_ACTIVATION_FUNCTION = 10,
+ VT_DILATION_W_FACTOR = 12,
+ VT_DILATION_H_FACTOR = 14
+ };
+ circle::Padding padding() const
+ {
+ return static_cast<circle::Padding>(GetField<int8_t>(VT_PADDING, 0));
+ }
+ int32_t stride_w() const { return GetField<int32_t>(VT_STRIDE_W, 0); }
+ int32_t stride_h() const { return GetField<int32_t>(VT_STRIDE_H, 0); }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ int32_t dilation_w_factor() const { return GetField<int32_t>(VT_DILATION_W_FACTOR, 1); }
+ int32_t dilation_h_factor() const { return GetField<int32_t>(VT_DILATION_H_FACTOR, 1); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_PADDING) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_W) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_H) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<int32_t>(verifier, VT_DILATION_W_FACTOR) &&
+ VerifyField<int32_t>(verifier, VT_DILATION_H_FACTOR) && verifier.EndTable();
+ }
+};
+
+struct Conv2DOptionsBuilder
+{
+ typedef Conv2DOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_padding(circle::Padding padding)
+ {
+ fbb_.AddElement<int8_t>(Conv2DOptions::VT_PADDING, static_cast<int8_t>(padding), 0);
+ }
+ void add_stride_w(int32_t stride_w)
+ {
+ fbb_.AddElement<int32_t>(Conv2DOptions::VT_STRIDE_W, stride_w, 0);
+ }
+ void add_stride_h(int32_t stride_h)
+ {
+ fbb_.AddElement<int32_t>(Conv2DOptions::VT_STRIDE_H, stride_h, 0);
+ }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(Conv2DOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_dilation_w_factor(int32_t dilation_w_factor)
+ {
+ fbb_.AddElement<int32_t>(Conv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1);
+ }
+ void add_dilation_h_factor(int32_t dilation_h_factor)
+ {
+ fbb_.AddElement<int32_t>(Conv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1);
+ }
+ explicit Conv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Conv2DOptionsBuilder &operator=(const Conv2DOptionsBuilder &);
+ flatbuffers::Offset<Conv2DOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Conv2DOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Conv2DOptions> CreateConv2DOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, circle::Padding padding = circle::Padding_SAME,
+ int32_t stride_w = 0, int32_t stride_h = 0,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ int32_t dilation_w_factor = 1, int32_t dilation_h_factor = 1)
+{
+ Conv2DOptionsBuilder builder_(_fbb);
+ builder_.add_dilation_h_factor(dilation_h_factor);
+ builder_.add_dilation_w_factor(dilation_w_factor);
+ builder_.add_stride_h(stride_h);
+ builder_.add_stride_w(stride_w);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_padding(padding);
+ return builder_.Finish();
+}
+
+struct Pool2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef Pool2DOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_PADDING = 4,
+ VT_STRIDE_W = 6,
+ VT_STRIDE_H = 8,
+ VT_FILTER_WIDTH = 10,
+ VT_FILTER_HEIGHT = 12,
+ VT_FUSED_ACTIVATION_FUNCTION = 14
+ };
+ circle::Padding padding() const
+ {
+ return static_cast<circle::Padding>(GetField<int8_t>(VT_PADDING, 0));
+ }
+ int32_t stride_w() const { return GetField<int32_t>(VT_STRIDE_W, 0); }
+ int32_t stride_h() const { return GetField<int32_t>(VT_STRIDE_H, 0); }
+ int32_t filter_width() const { return GetField<int32_t>(VT_FILTER_WIDTH, 0); }
+ int32_t filter_height() const { return GetField<int32_t>(VT_FILTER_HEIGHT, 0); }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_PADDING) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_W) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_H) &&
+ VerifyField<int32_t>(verifier, VT_FILTER_WIDTH) &&
+ VerifyField<int32_t>(verifier, VT_FILTER_HEIGHT) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct Pool2DOptionsBuilder
+{
+ typedef Pool2DOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_padding(circle::Padding padding)
+ {
+ fbb_.AddElement<int8_t>(Pool2DOptions::VT_PADDING, static_cast<int8_t>(padding), 0);
+ }
+ void add_stride_w(int32_t stride_w)
+ {
+ fbb_.AddElement<int32_t>(Pool2DOptions::VT_STRIDE_W, stride_w, 0);
+ }
+ void add_stride_h(int32_t stride_h)
+ {
+ fbb_.AddElement<int32_t>(Pool2DOptions::VT_STRIDE_H, stride_h, 0);
+ }
+ void add_filter_width(int32_t filter_width)
+ {
+ fbb_.AddElement<int32_t>(Pool2DOptions::VT_FILTER_WIDTH, filter_width, 0);
+ }
+ void add_filter_height(int32_t filter_height)
+ {
+ fbb_.AddElement<int32_t>(Pool2DOptions::VT_FILTER_HEIGHT, filter_height, 0);
+ }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(Pool2DOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit Pool2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Pool2DOptionsBuilder &operator=(const Pool2DOptionsBuilder &);
+ flatbuffers::Offset<Pool2DOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Pool2DOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Pool2DOptions> CreatePool2DOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, circle::Padding padding = circle::Padding_SAME,
+ int32_t stride_w = 0, int32_t stride_h = 0, int32_t filter_width = 0, int32_t filter_height = 0,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ Pool2DOptionsBuilder builder_(_fbb);
+ builder_.add_filter_height(filter_height);
+ builder_.add_filter_width(filter_width);
+ builder_.add_stride_h(stride_h);
+ builder_.add_stride_w(stride_w);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_padding(padding);
+ return builder_.Finish();
+}
+
+struct DepthwiseConv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef DepthwiseConv2DOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_PADDING = 4,
+ VT_STRIDE_W = 6,
+ VT_STRIDE_H = 8,
+ VT_DEPTH_MULTIPLIER = 10,
+ VT_FUSED_ACTIVATION_FUNCTION = 12,
+ VT_DILATION_W_FACTOR = 14,
+ VT_DILATION_H_FACTOR = 16
+ };
+ circle::Padding padding() const
+ {
+ return static_cast<circle::Padding>(GetField<int8_t>(VT_PADDING, 0));
+ }
+ int32_t stride_w() const { return GetField<int32_t>(VT_STRIDE_W, 0); }
+ int32_t stride_h() const { return GetField<int32_t>(VT_STRIDE_H, 0); }
+ int32_t depth_multiplier() const { return GetField<int32_t>(VT_DEPTH_MULTIPLIER, 0); }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ int32_t dilation_w_factor() const { return GetField<int32_t>(VT_DILATION_W_FACTOR, 1); }
+ int32_t dilation_h_factor() const { return GetField<int32_t>(VT_DILATION_H_FACTOR, 1); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_PADDING) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_W) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_H) &&
+ VerifyField<int32_t>(verifier, VT_DEPTH_MULTIPLIER) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<int32_t>(verifier, VT_DILATION_W_FACTOR) &&
+ VerifyField<int32_t>(verifier, VT_DILATION_H_FACTOR) && verifier.EndTable();
+ }
+};
+
+struct DepthwiseConv2DOptionsBuilder
+{
+ typedef DepthwiseConv2DOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_padding(circle::Padding padding)
+ {
+ fbb_.AddElement<int8_t>(DepthwiseConv2DOptions::VT_PADDING, static_cast<int8_t>(padding), 0);
+ }
+ void add_stride_w(int32_t stride_w)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_STRIDE_W, stride_w, 0);
+ }
+ void add_stride_h(int32_t stride_h)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_STRIDE_H, stride_h, 0);
+ }
+ void add_depth_multiplier(int32_t depth_multiplier)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_DEPTH_MULTIPLIER, depth_multiplier, 0);
+ }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(DepthwiseConv2DOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_dilation_w_factor(int32_t dilation_w_factor)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1);
+ }
+ void add_dilation_h_factor(int32_t dilation_h_factor)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1);
+ }
+ explicit DepthwiseConv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DepthwiseConv2DOptionsBuilder &operator=(const DepthwiseConv2DOptionsBuilder &);
+ flatbuffers::Offset<DepthwiseConv2DOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DepthwiseConv2DOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DepthwiseConv2DOptions> CreateDepthwiseConv2DOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, circle::Padding padding = circle::Padding_SAME,
+ int32_t stride_w = 0, int32_t stride_h = 0, int32_t depth_multiplier = 0,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ int32_t dilation_w_factor = 1, int32_t dilation_h_factor = 1)
+{
+ DepthwiseConv2DOptionsBuilder builder_(_fbb);
+ builder_.add_dilation_h_factor(dilation_h_factor);
+ builder_.add_dilation_w_factor(dilation_w_factor);
+ builder_.add_depth_multiplier(depth_multiplier);
+ builder_.add_stride_h(stride_h);
+ builder_.add_stride_w(stride_w);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_padding(padding);
+ return builder_.Finish();
+}
+
+struct ConcatEmbeddingsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ConcatEmbeddingsOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_NUM_CHANNELS = 4,
+ VT_NUM_COLUMNS_PER_CHANNEL = 6,
+ VT_EMBEDDING_DIM_PER_CHANNEL = 8
+ };
+ int32_t num_channels() const { return GetField<int32_t>(VT_NUM_CHANNELS, 0); }
+ const flatbuffers::Vector<int32_t> *num_columns_per_channel() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_NUM_COLUMNS_PER_CHANNEL);
+ }
+ const flatbuffers::Vector<int32_t> *embedding_dim_per_channel() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_EMBEDDING_DIM_PER_CHANNEL);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NUM_CHANNELS) &&
+ VerifyOffset(verifier, VT_NUM_COLUMNS_PER_CHANNEL) &&
+ verifier.VerifyVector(num_columns_per_channel()) &&
+ VerifyOffset(verifier, VT_EMBEDDING_DIM_PER_CHANNEL) &&
+ verifier.VerifyVector(embedding_dim_per_channel()) && verifier.EndTable();
+ }
+};
+
+struct ConcatEmbeddingsOptionsBuilder
+{
+ typedef ConcatEmbeddingsOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_num_channels(int32_t num_channels)
+ {
+ fbb_.AddElement<int32_t>(ConcatEmbeddingsOptions::VT_NUM_CHANNELS, num_channels, 0);
+ }
+ void add_num_columns_per_channel(
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> num_columns_per_channel)
+ {
+ fbb_.AddOffset(ConcatEmbeddingsOptions::VT_NUM_COLUMNS_PER_CHANNEL, num_columns_per_channel);
+ }
+ void add_embedding_dim_per_channel(
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> embedding_dim_per_channel)
+ {
+ fbb_.AddOffset(ConcatEmbeddingsOptions::VT_EMBEDDING_DIM_PER_CHANNEL,
+ embedding_dim_per_channel);
+ }
+ explicit ConcatEmbeddingsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ConcatEmbeddingsOptionsBuilder &operator=(const ConcatEmbeddingsOptionsBuilder &);
+ flatbuffers::Offset<ConcatEmbeddingsOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ConcatEmbeddingsOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ConcatEmbeddingsOptions> CreateConcatEmbeddingsOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, int32_t num_channels = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> num_columns_per_channel = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> embedding_dim_per_channel = 0)
+{
+ ConcatEmbeddingsOptionsBuilder builder_(_fbb);
+ builder_.add_embedding_dim_per_channel(embedding_dim_per_channel);
+ builder_.add_num_columns_per_channel(num_columns_per_channel);
+ builder_.add_num_channels(num_channels);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<ConcatEmbeddingsOptions>
+CreateConcatEmbeddingsOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb, int32_t num_channels = 0,
+ const std::vector<int32_t> *num_columns_per_channel = nullptr,
+ const std::vector<int32_t> *embedding_dim_per_channel = nullptr)
+{
+ auto num_columns_per_channel__ =
+ num_columns_per_channel ? _fbb.CreateVector<int32_t>(*num_columns_per_channel) : 0;
+ auto embedding_dim_per_channel__ =
+ embedding_dim_per_channel ? _fbb.CreateVector<int32_t>(*embedding_dim_per_channel) : 0;
+ return circle::CreateConcatEmbeddingsOptions(_fbb, num_channels, num_columns_per_channel__,
+ embedding_dim_per_channel__);
+}
+
+struct LSHProjectionOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LSHProjectionOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_TYPE = 4
+ };
+ circle::LSHProjectionType type() const
+ {
+ return static_cast<circle::LSHProjectionType>(GetField<int8_t>(VT_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct LSHProjectionOptionsBuilder
+{
+ typedef LSHProjectionOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_type(circle::LSHProjectionType type)
+ {
+ fbb_.AddElement<int8_t>(LSHProjectionOptions::VT_TYPE, static_cast<int8_t>(type), 0);
+ }
+ explicit LSHProjectionOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LSHProjectionOptionsBuilder &operator=(const LSHProjectionOptionsBuilder &);
+ flatbuffers::Offset<LSHProjectionOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LSHProjectionOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LSHProjectionOptions>
+CreateLSHProjectionOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::LSHProjectionType type = circle::LSHProjectionType_UNKNOWN)
+{
+ LSHProjectionOptionsBuilder builder_(_fbb);
+ builder_.add_type(type);
+ return builder_.Finish();
+}
+
+struct SVDFOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SVDFOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_RANK = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 8
+ };
+ int32_t rank() const { return GetField<int32_t>(VT_RANK, 0); }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_RANK) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct SVDFOptionsBuilder
+{
+ typedef SVDFOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_rank(int32_t rank) { fbb_.AddElement<int32_t>(SVDFOptions::VT_RANK, rank, 0); }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(SVDFOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(SVDFOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit SVDFOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SVDFOptionsBuilder &operator=(const SVDFOptionsBuilder &);
+ flatbuffers::Offset<SVDFOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SVDFOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SVDFOptions> CreateSVDFOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, int32_t rank = 0,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ bool asymmetric_quantize_inputs = false)
+{
+ SVDFOptionsBuilder builder_(_fbb);
+ builder_.add_rank(rank);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct RNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef RNNOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 6
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct RNNOptionsBuilder
+{
+ typedef RNNOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(RNNOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(RNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit RNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ RNNOptionsBuilder &operator=(const RNNOptionsBuilder &);
+ flatbuffers::Offset<RNNOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<RNNOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<RNNOptions> CreateRNNOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ bool asymmetric_quantize_inputs = false)
+{
+ RNNOptionsBuilder builder_(_fbb);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct SequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SequenceRNNOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_TIME_MAJOR = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 8
+ };
+ bool time_major() const { return GetField<uint8_t>(VT_TIME_MAJOR, 0) != 0; }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_TIME_MAJOR) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct SequenceRNNOptionsBuilder
+{
+ typedef SequenceRNNOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_time_major(bool time_major)
+ {
+ fbb_.AddElement<uint8_t>(SequenceRNNOptions::VT_TIME_MAJOR, static_cast<uint8_t>(time_major),
+ 0);
+ }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(SequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(SequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit SequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SequenceRNNOptionsBuilder &operator=(const SequenceRNNOptionsBuilder &);
+ flatbuffers::Offset<SequenceRNNOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SequenceRNNOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SequenceRNNOptions> CreateSequenceRNNOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, bool time_major = false,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ bool asymmetric_quantize_inputs = false)
+{
+ SequenceRNNOptionsBuilder builder_(_fbb);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_time_major(time_major);
+ return builder_.Finish();
+}
+
+struct BidirectionalSequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef BidirectionalSequenceRNNOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_TIME_MAJOR = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6,
+ VT_MERGE_OUTPUTS = 8,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 10
+ };
+ bool time_major() const { return GetField<uint8_t>(VT_TIME_MAJOR, 0) != 0; }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool merge_outputs() const { return GetField<uint8_t>(VT_MERGE_OUTPUTS, 0) != 0; }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_TIME_MAJOR) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<uint8_t>(verifier, VT_MERGE_OUTPUTS) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct BidirectionalSequenceRNNOptionsBuilder
+{
+ typedef BidirectionalSequenceRNNOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_time_major(bool time_major)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceRNNOptions::VT_TIME_MAJOR,
+ static_cast<uint8_t>(time_major), 0);
+ }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(BidirectionalSequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_merge_outputs(bool merge_outputs)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceRNNOptions::VT_MERGE_OUTPUTS,
+ static_cast<uint8_t>(merge_outputs), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit BidirectionalSequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BidirectionalSequenceRNNOptionsBuilder &operator=(const BidirectionalSequenceRNNOptionsBuilder &);
+ flatbuffers::Offset<BidirectionalSequenceRNNOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BidirectionalSequenceRNNOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BidirectionalSequenceRNNOptions> CreateBidirectionalSequenceRNNOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, bool time_major = false,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ bool merge_outputs = false, bool asymmetric_quantize_inputs = false)
+{
+ BidirectionalSequenceRNNOptionsBuilder builder_(_fbb);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_merge_outputs(merge_outputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_time_major(time_major);
+ return builder_.Finish();
+}
+
+struct FullyConnectedOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef FullyConnectedOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_WEIGHTS_FORMAT = 6,
+ VT_KEEP_NUM_DIMS = 8,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 10
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ circle::FullyConnectedOptionsWeightsFormat weights_format() const
+ {
+ return static_cast<circle::FullyConnectedOptionsWeightsFormat>(
+ GetField<int8_t>(VT_WEIGHTS_FORMAT, 0));
+ }
+ bool keep_num_dims() const { return GetField<uint8_t>(VT_KEEP_NUM_DIMS, 0) != 0; }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<int8_t>(verifier, VT_WEIGHTS_FORMAT) &&
+ VerifyField<uint8_t>(verifier, VT_KEEP_NUM_DIMS) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct FullyConnectedOptionsBuilder
+{
+ typedef FullyConnectedOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(FullyConnectedOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_weights_format(circle::FullyConnectedOptionsWeightsFormat weights_format)
+ {
+ fbb_.AddElement<int8_t>(FullyConnectedOptions::VT_WEIGHTS_FORMAT,
+ static_cast<int8_t>(weights_format), 0);
+ }
+ void add_keep_num_dims(bool keep_num_dims)
+ {
+ fbb_.AddElement<uint8_t>(FullyConnectedOptions::VT_KEEP_NUM_DIMS,
+ static_cast<uint8_t>(keep_num_dims), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(FullyConnectedOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit FullyConnectedOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FullyConnectedOptionsBuilder &operator=(const FullyConnectedOptionsBuilder &);
+ flatbuffers::Offset<FullyConnectedOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FullyConnectedOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FullyConnectedOptions> CreateFullyConnectedOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ circle::FullyConnectedOptionsWeightsFormat weights_format =
+ circle::FullyConnectedOptionsWeightsFormat_DEFAULT,
+ bool keep_num_dims = false, bool asymmetric_quantize_inputs = false)
+{
+ FullyConnectedOptionsBuilder builder_(_fbb);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_keep_num_dims(keep_num_dims);
+ builder_.add_weights_format(weights_format);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct SoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SoftmaxOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_BETA = 4
+ };
+ float beta() const { return GetField<float>(VT_BETA, 0.0f); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<float>(verifier, VT_BETA) &&
+ verifier.EndTable();
+ }
+};
+
+struct SoftmaxOptionsBuilder
+{
+ typedef SoftmaxOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_beta(float beta) { fbb_.AddElement<float>(SoftmaxOptions::VT_BETA, beta, 0.0f); }
+ explicit SoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SoftmaxOptionsBuilder &operator=(const SoftmaxOptionsBuilder &);
+ flatbuffers::Offset<SoftmaxOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SoftmaxOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SoftmaxOptions>
+CreateSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb, float beta = 0.0f)
+{
+ SoftmaxOptionsBuilder builder_(_fbb);
+ builder_.add_beta(beta);
+ return builder_.Finish();
+}
+
+struct ConcatenationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ConcatenationOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_AXIS = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6
+ };
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_AXIS) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct ConcatenationOptionsBuilder
+{
+ typedef ConcatenationOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(ConcatenationOptions::VT_AXIS, axis, 0); }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(ConcatenationOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit ConcatenationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ConcatenationOptionsBuilder &operator=(const ConcatenationOptionsBuilder &);
+ flatbuffers::Offset<ConcatenationOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ConcatenationOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ConcatenationOptions> CreateConcatenationOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, int32_t axis = 0,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ ConcatenationOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct AddOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef AddOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct AddOptionsBuilder
+{
+ typedef AddOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(AddOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit AddOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ AddOptionsBuilder &operator=(const AddOptionsBuilder &);
+ flatbuffers::Offset<AddOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<AddOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<AddOptions> CreateAddOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ AddOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct MulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef MulOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct MulOptionsBuilder
+{
+ typedef MulOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(MulOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit MulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MulOptionsBuilder &operator=(const MulOptionsBuilder &);
+ flatbuffers::Offset<MulOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MulOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MulOptions> CreateMulOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ MulOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct L2NormOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef L2NormOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct L2NormOptionsBuilder
+{
+ typedef L2NormOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(L2NormOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit L2NormOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ L2NormOptionsBuilder &operator=(const L2NormOptionsBuilder &);
+ flatbuffers::Offset<L2NormOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<L2NormOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<L2NormOptions> CreateL2NormOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ L2NormOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct LocalResponseNormalizationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LocalResponseNormalizationOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_RADIUS = 4,
+ VT_BIAS = 6,
+ VT_ALPHA = 8,
+ VT_BETA = 10
+ };
+ int32_t radius() const { return GetField<int32_t>(VT_RADIUS, 0); }
+ float bias() const { return GetField<float>(VT_BIAS, 0.0f); }
+ float alpha() const { return GetField<float>(VT_ALPHA, 0.0f); }
+ float beta() const { return GetField<float>(VT_BETA, 0.0f); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_RADIUS) &&
+ VerifyField<float>(verifier, VT_BIAS) && VerifyField<float>(verifier, VT_ALPHA) &&
+ VerifyField<float>(verifier, VT_BETA) && verifier.EndTable();
+ }
+};
+
+struct LocalResponseNormalizationOptionsBuilder
+{
+ typedef LocalResponseNormalizationOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_radius(int32_t radius)
+ {
+ fbb_.AddElement<int32_t>(LocalResponseNormalizationOptions::VT_RADIUS, radius, 0);
+ }
+ void add_bias(float bias)
+ {
+ fbb_.AddElement<float>(LocalResponseNormalizationOptions::VT_BIAS, bias, 0.0f);
+ }
+ void add_alpha(float alpha)
+ {
+ fbb_.AddElement<float>(LocalResponseNormalizationOptions::VT_ALPHA, alpha, 0.0f);
+ }
+ void add_beta(float beta)
+ {
+ fbb_.AddElement<float>(LocalResponseNormalizationOptions::VT_BETA, beta, 0.0f);
+ }
+ explicit LocalResponseNormalizationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LocalResponseNormalizationOptionsBuilder &
+ operator=(const LocalResponseNormalizationOptionsBuilder &);
+ flatbuffers::Offset<LocalResponseNormalizationOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LocalResponseNormalizationOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LocalResponseNormalizationOptions>
+CreateLocalResponseNormalizationOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t radius = 0,
+ float bias = 0.0f, float alpha = 0.0f, float beta = 0.0f)
+{
+ LocalResponseNormalizationOptionsBuilder builder_(_fbb);
+ builder_.add_beta(beta);
+ builder_.add_alpha(alpha);
+ builder_.add_bias(bias);
+ builder_.add_radius(radius);
+ return builder_.Finish();
+}
+
+struct LSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LSTMOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_CELL_CLIP = 6,
+ VT_PROJ_CLIP = 8,
+ VT_KERNEL_TYPE = 10,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 12
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ float cell_clip() const { return GetField<float>(VT_CELL_CLIP, 0.0f); }
+ float proj_clip() const { return GetField<float>(VT_PROJ_CLIP, 0.0f); }
+ circle::LSTMKernelType kernel_type() const
+ {
+ return static_cast<circle::LSTMKernelType>(GetField<int8_t>(VT_KERNEL_TYPE, 0));
+ }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<float>(verifier, VT_CELL_CLIP) &&
+ VerifyField<float>(verifier, VT_PROJ_CLIP) &&
+ VerifyField<int8_t>(verifier, VT_KERNEL_TYPE) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct LSTMOptionsBuilder
+{
+ typedef LSTMOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(LSTMOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_cell_clip(float cell_clip)
+ {
+ fbb_.AddElement<float>(LSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f);
+ }
+ void add_proj_clip(float proj_clip)
+ {
+ fbb_.AddElement<float>(LSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f);
+ }
+ void add_kernel_type(circle::LSTMKernelType kernel_type)
+ {
+ fbb_.AddElement<int8_t>(LSTMOptions::VT_KERNEL_TYPE, static_cast<int8_t>(kernel_type), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(LSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit LSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LSTMOptionsBuilder &operator=(const LSTMOptionsBuilder &);
+ flatbuffers::Offset<LSTMOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LSTMOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LSTMOptions> CreateLSTMOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ float cell_clip = 0.0f, float proj_clip = 0.0f,
+ circle::LSTMKernelType kernel_type = circle::LSTMKernelType_FULL,
+ bool asymmetric_quantize_inputs = false)
+{
+ LSTMOptionsBuilder builder_(_fbb);
+ builder_.add_proj_clip(proj_clip);
+ builder_.add_cell_clip(cell_clip);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_kernel_type(kernel_type);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct UnidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef UnidirectionalSequenceLSTMOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_CELL_CLIP = 6,
+ VT_PROJ_CLIP = 8,
+ VT_TIME_MAJOR = 10,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 12
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ float cell_clip() const { return GetField<float>(VT_CELL_CLIP, 0.0f); }
+ float proj_clip() const { return GetField<float>(VT_PROJ_CLIP, 0.0f); }
+ bool time_major() const { return GetField<uint8_t>(VT_TIME_MAJOR, 0) != 0; }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<float>(verifier, VT_CELL_CLIP) &&
+ VerifyField<float>(verifier, VT_PROJ_CLIP) &&
+ VerifyField<uint8_t>(verifier, VT_TIME_MAJOR) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct UnidirectionalSequenceLSTMOptionsBuilder
+{
+ typedef UnidirectionalSequenceLSTMOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(UnidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_cell_clip(float cell_clip)
+ {
+ fbb_.AddElement<float>(UnidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f);
+ }
+ void add_proj_clip(float proj_clip)
+ {
+ fbb_.AddElement<float>(UnidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f);
+ }
+ void add_time_major(bool time_major)
+ {
+ fbb_.AddElement<uint8_t>(UnidirectionalSequenceLSTMOptions::VT_TIME_MAJOR,
+ static_cast<uint8_t>(time_major), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(UnidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit UnidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ UnidirectionalSequenceLSTMOptionsBuilder &
+ operator=(const UnidirectionalSequenceLSTMOptionsBuilder &);
+ flatbuffers::Offset<UnidirectionalSequenceLSTMOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<UnidirectionalSequenceLSTMOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<UnidirectionalSequenceLSTMOptions>
+CreateUnidirectionalSequenceLSTMOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ float cell_clip = 0.0f, float proj_clip = 0.0f, bool time_major = false,
+ bool asymmetric_quantize_inputs = false)
+{
+ UnidirectionalSequenceLSTMOptionsBuilder builder_(_fbb);
+ builder_.add_proj_clip(proj_clip);
+ builder_.add_cell_clip(cell_clip);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_time_major(time_major);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct BidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef BidirectionalSequenceLSTMOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_CELL_CLIP = 6,
+ VT_PROJ_CLIP = 8,
+ VT_MERGE_OUTPUTS = 10,
+ VT_TIME_MAJOR = 12,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 14
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ float cell_clip() const { return GetField<float>(VT_CELL_CLIP, 0.0f); }
+ float proj_clip() const { return GetField<float>(VT_PROJ_CLIP, 0.0f); }
+ bool merge_outputs() const { return GetField<uint8_t>(VT_MERGE_OUTPUTS, 0) != 0; }
+ bool time_major() const { return GetField<uint8_t>(VT_TIME_MAJOR, 1) != 0; }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<float>(verifier, VT_CELL_CLIP) &&
+ VerifyField<float>(verifier, VT_PROJ_CLIP) &&
+ VerifyField<uint8_t>(verifier, VT_MERGE_OUTPUTS) &&
+ VerifyField<uint8_t>(verifier, VT_TIME_MAJOR) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct BidirectionalSequenceLSTMOptionsBuilder
+{
+ typedef BidirectionalSequenceLSTMOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(BidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_cell_clip(float cell_clip)
+ {
+ fbb_.AddElement<float>(BidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f);
+ }
+ void add_proj_clip(float proj_clip)
+ {
+ fbb_.AddElement<float>(BidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f);
+ }
+ void add_merge_outputs(bool merge_outputs)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceLSTMOptions::VT_MERGE_OUTPUTS,
+ static_cast<uint8_t>(merge_outputs), 0);
+ }
+ void add_time_major(bool time_major)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceLSTMOptions::VT_TIME_MAJOR,
+ static_cast<uint8_t>(time_major), 1);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit BidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BidirectionalSequenceLSTMOptionsBuilder &
+ operator=(const BidirectionalSequenceLSTMOptionsBuilder &);
+ flatbuffers::Offset<BidirectionalSequenceLSTMOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BidirectionalSequenceLSTMOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BidirectionalSequenceLSTMOptions> CreateBidirectionalSequenceLSTMOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE,
+ float cell_clip = 0.0f, float proj_clip = 0.0f, bool merge_outputs = false,
+ bool time_major = true, bool asymmetric_quantize_inputs = false)
+{
+ BidirectionalSequenceLSTMOptionsBuilder builder_(_fbb);
+ builder_.add_proj_clip(proj_clip);
+ builder_.add_cell_clip(cell_clip);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_time_major(time_major);
+ builder_.add_merge_outputs(merge_outputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct ResizeBilinearOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ResizeBilinearOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_ALIGN_CORNERS = 8,
+ VT_HALF_PIXEL_CENTERS = 10
+ };
+ bool align_corners() const { return GetField<uint8_t>(VT_ALIGN_CORNERS, 0) != 0; }
+ bool half_pixel_centers() const { return GetField<uint8_t>(VT_HALF_PIXEL_CENTERS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_ALIGN_CORNERS) &&
+ VerifyField<uint8_t>(verifier, VT_HALF_PIXEL_CENTERS) && verifier.EndTable();
+ }
+};
+
+struct ResizeBilinearOptionsBuilder
+{
+ typedef ResizeBilinearOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_align_corners(bool align_corners)
+ {
+ fbb_.AddElement<uint8_t>(ResizeBilinearOptions::VT_ALIGN_CORNERS,
+ static_cast<uint8_t>(align_corners), 0);
+ }
+ void add_half_pixel_centers(bool half_pixel_centers)
+ {
+ fbb_.AddElement<uint8_t>(ResizeBilinearOptions::VT_HALF_PIXEL_CENTERS,
+ static_cast<uint8_t>(half_pixel_centers), 0);
+ }
+ explicit ResizeBilinearOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ResizeBilinearOptionsBuilder &operator=(const ResizeBilinearOptionsBuilder &);
+ flatbuffers::Offset<ResizeBilinearOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ResizeBilinearOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ResizeBilinearOptions>
+CreateResizeBilinearOptions(flatbuffers::FlatBufferBuilder &_fbb, bool align_corners = false,
+ bool half_pixel_centers = false)
+{
+ ResizeBilinearOptionsBuilder builder_(_fbb);
+ builder_.add_half_pixel_centers(half_pixel_centers);
+ builder_.add_align_corners(align_corners);
+ return builder_.Finish();
+}
+
+struct ResizeNearestNeighborOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ResizeNearestNeighborOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_ALIGN_CORNERS = 4
+ };
+ bool align_corners() const { return GetField<uint8_t>(VT_ALIGN_CORNERS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_ALIGN_CORNERS) &&
+ verifier.EndTable();
+ }
+};
+
+struct ResizeNearestNeighborOptionsBuilder
+{
+ typedef ResizeNearestNeighborOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_align_corners(bool align_corners)
+ {
+ fbb_.AddElement<uint8_t>(ResizeNearestNeighborOptions::VT_ALIGN_CORNERS,
+ static_cast<uint8_t>(align_corners), 0);
+ }
+ explicit ResizeNearestNeighborOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ResizeNearestNeighborOptionsBuilder &operator=(const ResizeNearestNeighborOptionsBuilder &);
+ flatbuffers::Offset<ResizeNearestNeighborOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ResizeNearestNeighborOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ResizeNearestNeighborOptions>
+CreateResizeNearestNeighborOptions(flatbuffers::FlatBufferBuilder &_fbb, bool align_corners = false)
+{
+ ResizeNearestNeighborOptionsBuilder builder_(_fbb);
+ builder_.add_align_corners(align_corners);
+ return builder_.Finish();
+}
+
+struct CallOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef CallOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_SUBGRAPH = 4
+ };
+ uint32_t subgraph() const { return GetField<uint32_t>(VT_SUBGRAPH, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint32_t>(verifier, VT_SUBGRAPH) &&
+ verifier.EndTable();
+ }
+};
+
+struct CallOptionsBuilder
+{
+ typedef CallOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_subgraph(uint32_t subgraph)
+ {
+ fbb_.AddElement<uint32_t>(CallOptions::VT_SUBGRAPH, subgraph, 0);
+ }
+ explicit CallOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ CallOptionsBuilder &operator=(const CallOptionsBuilder &);
+ flatbuffers::Offset<CallOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CallOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CallOptions> CreateCallOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t subgraph = 0)
+{
+ CallOptionsBuilder builder_(_fbb);
+ builder_.add_subgraph(subgraph);
+ return builder_.Finish();
+}
+
+struct PadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef PadOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct PadOptionsBuilder
+{
+ typedef PadOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ PadOptionsBuilder &operator=(const PadOptionsBuilder &);
+ flatbuffers::Offset<PadOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PadOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PadOptions> CreatePadOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ PadOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct PadV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef PadV2OptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct PadV2OptionsBuilder
+{
+ typedef PadV2Options Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PadV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ PadV2OptionsBuilder &operator=(const PadV2OptionsBuilder &);
+ flatbuffers::Offset<PadV2Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PadV2Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PadV2Options> CreatePadV2Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ PadV2OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ReshapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ReshapeOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_NEW_SHAPE = 4
+ };
+ const flatbuffers::Vector<int32_t> *new_shape() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_NEW_SHAPE);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NEW_SHAPE) &&
+ verifier.VerifyVector(new_shape()) && verifier.EndTable();
+ }
+};
+
+struct ReshapeOptionsBuilder
+{
+ typedef ReshapeOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_new_shape(flatbuffers::Offset<flatbuffers::Vector<int32_t>> new_shape)
+ {
+ fbb_.AddOffset(ReshapeOptions::VT_NEW_SHAPE, new_shape);
+ }
+ explicit ReshapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ReshapeOptionsBuilder &operator=(const ReshapeOptionsBuilder &);
+ flatbuffers::Offset<ReshapeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ReshapeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ReshapeOptions>
+CreateReshapeOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> new_shape = 0)
+{
+ ReshapeOptionsBuilder builder_(_fbb);
+ builder_.add_new_shape(new_shape);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<ReshapeOptions>
+CreateReshapeOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<int32_t> *new_shape = nullptr)
+{
+ auto new_shape__ = new_shape ? _fbb.CreateVector<int32_t>(*new_shape) : 0;
+ return circle::CreateReshapeOptions(_fbb, new_shape__);
+}
+
+struct SpaceToBatchNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SpaceToBatchNDOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SpaceToBatchNDOptionsBuilder
+{
+ typedef SpaceToBatchNDOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SpaceToBatchNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SpaceToBatchNDOptionsBuilder &operator=(const SpaceToBatchNDOptionsBuilder &);
+ flatbuffers::Offset<SpaceToBatchNDOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SpaceToBatchNDOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SpaceToBatchNDOptions>
+CreateSpaceToBatchNDOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SpaceToBatchNDOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct BatchToSpaceNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef BatchToSpaceNDOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct BatchToSpaceNDOptionsBuilder
+{
+ typedef BatchToSpaceNDOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit BatchToSpaceNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BatchToSpaceNDOptionsBuilder &operator=(const BatchToSpaceNDOptionsBuilder &);
+ flatbuffers::Offset<BatchToSpaceNDOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BatchToSpaceNDOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BatchToSpaceNDOptions>
+CreateBatchToSpaceNDOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ BatchToSpaceNDOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SkipGramOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SkipGramOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_NGRAM_SIZE = 4,
+ VT_MAX_SKIP_SIZE = 6,
+ VT_INCLUDE_ALL_NGRAMS = 8
+ };
+ int32_t ngram_size() const { return GetField<int32_t>(VT_NGRAM_SIZE, 0); }
+ int32_t max_skip_size() const { return GetField<int32_t>(VT_MAX_SKIP_SIZE, 0); }
+ bool include_all_ngrams() const { return GetField<uint8_t>(VT_INCLUDE_ALL_NGRAMS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NGRAM_SIZE) &&
+ VerifyField<int32_t>(verifier, VT_MAX_SKIP_SIZE) &&
+ VerifyField<uint8_t>(verifier, VT_INCLUDE_ALL_NGRAMS) && verifier.EndTable();
+ }
+};
+
+struct SkipGramOptionsBuilder
+{
+ typedef SkipGramOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_ngram_size(int32_t ngram_size)
+ {
+ fbb_.AddElement<int32_t>(SkipGramOptions::VT_NGRAM_SIZE, ngram_size, 0);
+ }
+ void add_max_skip_size(int32_t max_skip_size)
+ {
+ fbb_.AddElement<int32_t>(SkipGramOptions::VT_MAX_SKIP_SIZE, max_skip_size, 0);
+ }
+ void add_include_all_ngrams(bool include_all_ngrams)
+ {
+ fbb_.AddElement<uint8_t>(SkipGramOptions::VT_INCLUDE_ALL_NGRAMS,
+ static_cast<uint8_t>(include_all_ngrams), 0);
+ }
+ explicit SkipGramOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SkipGramOptionsBuilder &operator=(const SkipGramOptionsBuilder &);
+ flatbuffers::Offset<SkipGramOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SkipGramOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SkipGramOptions>
+CreateSkipGramOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t ngram_size = 0,
+ int32_t max_skip_size = 0, bool include_all_ngrams = false)
+{
+ SkipGramOptionsBuilder builder_(_fbb);
+ builder_.add_max_skip_size(max_skip_size);
+ builder_.add_ngram_size(ngram_size);
+ builder_.add_include_all_ngrams(include_all_ngrams);
+ return builder_.Finish();
+}
+
+struct SpaceToDepthOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SpaceToDepthOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_BLOCK_SIZE = 4
+ };
+ int32_t block_size() const { return GetField<int32_t>(VT_BLOCK_SIZE, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_BLOCK_SIZE) &&
+ verifier.EndTable();
+ }
+};
+
+struct SpaceToDepthOptionsBuilder
+{
+ typedef SpaceToDepthOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_block_size(int32_t block_size)
+ {
+ fbb_.AddElement<int32_t>(SpaceToDepthOptions::VT_BLOCK_SIZE, block_size, 0);
+ }
+ explicit SpaceToDepthOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SpaceToDepthOptionsBuilder &operator=(const SpaceToDepthOptionsBuilder &);
+ flatbuffers::Offset<SpaceToDepthOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SpaceToDepthOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SpaceToDepthOptions>
+CreateSpaceToDepthOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t block_size = 0)
+{
+ SpaceToDepthOptionsBuilder builder_(_fbb);
+ builder_.add_block_size(block_size);
+ return builder_.Finish();
+}
+
+struct DepthToSpaceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef DepthToSpaceOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_BLOCK_SIZE = 4
+ };
+ int32_t block_size() const { return GetField<int32_t>(VT_BLOCK_SIZE, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_BLOCK_SIZE) &&
+ verifier.EndTable();
+ }
+};
+
+struct DepthToSpaceOptionsBuilder
+{
+ typedef DepthToSpaceOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_block_size(int32_t block_size)
+ {
+ fbb_.AddElement<int32_t>(DepthToSpaceOptions::VT_BLOCK_SIZE, block_size, 0);
+ }
+ explicit DepthToSpaceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DepthToSpaceOptionsBuilder &operator=(const DepthToSpaceOptionsBuilder &);
+ flatbuffers::Offset<DepthToSpaceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DepthToSpaceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DepthToSpaceOptions>
+CreateDepthToSpaceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t block_size = 0)
+{
+ DepthToSpaceOptionsBuilder builder_(_fbb);
+ builder_.add_block_size(block_size);
+ return builder_.Finish();
+}
+
+struct SubOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SubOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct SubOptionsBuilder
+{
+ typedef SubOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(SubOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit SubOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SubOptionsBuilder &operator=(const SubOptionsBuilder &);
+ flatbuffers::Offset<SubOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SubOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SubOptions> CreateSubOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ SubOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct DivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef DivOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct DivOptionsBuilder
+{
+ typedef DivOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(DivOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit DivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DivOptionsBuilder &operator=(const DivOptionsBuilder &);
+ flatbuffers::Offset<DivOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DivOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DivOptions> CreateDivOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ DivOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct TopKV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef TopKV2OptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct TopKV2OptionsBuilder
+{
+ typedef TopKV2Options Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit TopKV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TopKV2OptionsBuilder &operator=(const TopKV2OptionsBuilder &);
+ flatbuffers::Offset<TopKV2Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TopKV2Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TopKV2Options> CreateTopKV2Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ TopKV2OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct EmbeddingLookupSparseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef EmbeddingLookupSparseOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_COMBINER = 4
+ };
+ circle::CombinerType combiner() const
+ {
+ return static_cast<circle::CombinerType>(GetField<int8_t>(VT_COMBINER, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_COMBINER) &&
+ verifier.EndTable();
+ }
+};
+
+struct EmbeddingLookupSparseOptionsBuilder
+{
+ typedef EmbeddingLookupSparseOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_combiner(circle::CombinerType combiner)
+ {
+ fbb_.AddElement<int8_t>(EmbeddingLookupSparseOptions::VT_COMBINER,
+ static_cast<int8_t>(combiner), 0);
+ }
+ explicit EmbeddingLookupSparseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ EmbeddingLookupSparseOptionsBuilder &operator=(const EmbeddingLookupSparseOptionsBuilder &);
+ flatbuffers::Offset<EmbeddingLookupSparseOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<EmbeddingLookupSparseOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<EmbeddingLookupSparseOptions>
+CreateEmbeddingLookupSparseOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::CombinerType combiner = circle::CombinerType_SUM)
+{
+ EmbeddingLookupSparseOptionsBuilder builder_(_fbb);
+ builder_.add_combiner(combiner);
+ return builder_.Finish();
+}
+
+struct GatherOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef GatherOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_AXIS = 4
+ };
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_AXIS) &&
+ verifier.EndTable();
+ }
+};
+
+struct GatherOptionsBuilder
+{
+ typedef GatherOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(GatherOptions::VT_AXIS, axis, 0); }
+ explicit GatherOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ GatherOptionsBuilder &operator=(const GatherOptionsBuilder &);
+ flatbuffers::Offset<GatherOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<GatherOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<GatherOptions> CreateGatherOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t axis = 0)
+{
+ GatherOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ return builder_.Finish();
+}
+
+struct TransposeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef TransposeOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct TransposeOptionsBuilder
+{
+ typedef TransposeOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit TransposeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TransposeOptionsBuilder &operator=(const TransposeOptionsBuilder &);
+ flatbuffers::Offset<TransposeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TransposeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TransposeOptions>
+CreateTransposeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ TransposeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ExpOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ExpOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ExpOptionsBuilder
+{
+ typedef ExpOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ExpOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ExpOptionsBuilder &operator=(const ExpOptionsBuilder &);
+ flatbuffers::Offset<ExpOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ExpOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ExpOptions> CreateExpOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ExpOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct CosOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef CosOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct CosOptionsBuilder
+{
+ typedef CosOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit CosOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ CosOptionsBuilder &operator=(const CosOptionsBuilder &);
+ flatbuffers::Offset<CosOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CosOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CosOptions> CreateCosOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ CosOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ReducerOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ReducerOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_KEEP_DIMS = 4
+ };
+ bool keep_dims() const { return GetField<uint8_t>(VT_KEEP_DIMS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_KEEP_DIMS) &&
+ verifier.EndTable();
+ }
+};
+
+struct ReducerOptionsBuilder
+{
+ typedef ReducerOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_keep_dims(bool keep_dims)
+ {
+ fbb_.AddElement<uint8_t>(ReducerOptions::VT_KEEP_DIMS, static_cast<uint8_t>(keep_dims), 0);
+ }
+ explicit ReducerOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ReducerOptionsBuilder &operator=(const ReducerOptionsBuilder &);
+ flatbuffers::Offset<ReducerOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ReducerOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ReducerOptions>
+CreateReducerOptions(flatbuffers::FlatBufferBuilder &_fbb, bool keep_dims = false)
+{
+ ReducerOptionsBuilder builder_(_fbb);
+ builder_.add_keep_dims(keep_dims);
+ return builder_.Finish();
+}
+
+struct SqueezeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SqueezeOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_SQUEEZE_DIMS = 4
+ };
+ const flatbuffers::Vector<int32_t> *squeeze_dims() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_SQUEEZE_DIMS);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SQUEEZE_DIMS) &&
+ verifier.VerifyVector(squeeze_dims()) && verifier.EndTable();
+ }
+};
+
+struct SqueezeOptionsBuilder
+{
+ typedef SqueezeOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_squeeze_dims(flatbuffers::Offset<flatbuffers::Vector<int32_t>> squeeze_dims)
+ {
+ fbb_.AddOffset(SqueezeOptions::VT_SQUEEZE_DIMS, squeeze_dims);
+ }
+ explicit SqueezeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SqueezeOptionsBuilder &operator=(const SqueezeOptionsBuilder &);
+ flatbuffers::Offset<SqueezeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SqueezeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SqueezeOptions>
+CreateSqueezeOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> squeeze_dims = 0)
+{
+ SqueezeOptionsBuilder builder_(_fbb);
+ builder_.add_squeeze_dims(squeeze_dims);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<SqueezeOptions>
+CreateSqueezeOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<int32_t> *squeeze_dims = nullptr)
+{
+ auto squeeze_dims__ = squeeze_dims ? _fbb.CreateVector<int32_t>(*squeeze_dims) : 0;
+ return circle::CreateSqueezeOptions(_fbb, squeeze_dims__);
+}
+
+struct SplitOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SplitOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_NUM_SPLITS = 4
+ };
+ int32_t num_splits() const { return GetField<int32_t>(VT_NUM_SPLITS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NUM_SPLITS) &&
+ verifier.EndTable();
+ }
+};
+
+struct SplitOptionsBuilder
+{
+ typedef SplitOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_num_splits(int32_t num_splits)
+ {
+ fbb_.AddElement<int32_t>(SplitOptions::VT_NUM_SPLITS, num_splits, 0);
+ }
+ explicit SplitOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SplitOptionsBuilder &operator=(const SplitOptionsBuilder &);
+ flatbuffers::Offset<SplitOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SplitOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SplitOptions> CreateSplitOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t num_splits = 0)
+{
+ SplitOptionsBuilder builder_(_fbb);
+ builder_.add_num_splits(num_splits);
+ return builder_.Finish();
+}
+
+struct SplitVOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SplitVOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_NUM_SPLITS = 4
+ };
+ int32_t num_splits() const { return GetField<int32_t>(VT_NUM_SPLITS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NUM_SPLITS) &&
+ verifier.EndTable();
+ }
+};
+
+struct SplitVOptionsBuilder
+{
+ typedef SplitVOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_num_splits(int32_t num_splits)
+ {
+ fbb_.AddElement<int32_t>(SplitVOptions::VT_NUM_SPLITS, num_splits, 0);
+ }
+ explicit SplitVOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SplitVOptionsBuilder &operator=(const SplitVOptionsBuilder &);
+ flatbuffers::Offset<SplitVOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SplitVOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SplitVOptions> CreateSplitVOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t num_splits = 0)
+{
+ SplitVOptionsBuilder builder_(_fbb);
+ builder_.add_num_splits(num_splits);
+ return builder_.Finish();
+}
+
+struct StridedSliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef StridedSliceOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_BEGIN_MASK = 4,
+ VT_END_MASK = 6,
+ VT_ELLIPSIS_MASK = 8,
+ VT_NEW_AXIS_MASK = 10,
+ VT_SHRINK_AXIS_MASK = 12
+ };
+ int32_t begin_mask() const { return GetField<int32_t>(VT_BEGIN_MASK, 0); }
+ int32_t end_mask() const { return GetField<int32_t>(VT_END_MASK, 0); }
+ int32_t ellipsis_mask() const { return GetField<int32_t>(VT_ELLIPSIS_MASK, 0); }
+ int32_t new_axis_mask() const { return GetField<int32_t>(VT_NEW_AXIS_MASK, 0); }
+ int32_t shrink_axis_mask() const { return GetField<int32_t>(VT_SHRINK_AXIS_MASK, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_BEGIN_MASK) &&
+ VerifyField<int32_t>(verifier, VT_END_MASK) &&
+ VerifyField<int32_t>(verifier, VT_ELLIPSIS_MASK) &&
+ VerifyField<int32_t>(verifier, VT_NEW_AXIS_MASK) &&
+ VerifyField<int32_t>(verifier, VT_SHRINK_AXIS_MASK) && verifier.EndTable();
+ }
+};
+
+struct StridedSliceOptionsBuilder
+{
+ typedef StridedSliceOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_begin_mask(int32_t begin_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_BEGIN_MASK, begin_mask, 0);
+ }
+ void add_end_mask(int32_t end_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_END_MASK, end_mask, 0);
+ }
+ void add_ellipsis_mask(int32_t ellipsis_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_ELLIPSIS_MASK, ellipsis_mask, 0);
+ }
+ void add_new_axis_mask(int32_t new_axis_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_NEW_AXIS_MASK, new_axis_mask, 0);
+ }
+ void add_shrink_axis_mask(int32_t shrink_axis_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_SHRINK_AXIS_MASK, shrink_axis_mask, 0);
+ }
+ explicit StridedSliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ StridedSliceOptionsBuilder &operator=(const StridedSliceOptionsBuilder &);
+ flatbuffers::Offset<StridedSliceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<StridedSliceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<StridedSliceOptions>
+CreateStridedSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t begin_mask = 0,
+ int32_t end_mask = 0, int32_t ellipsis_mask = 0,
+ int32_t new_axis_mask = 0, int32_t shrink_axis_mask = 0)
+{
+ StridedSliceOptionsBuilder builder_(_fbb);
+ builder_.add_shrink_axis_mask(shrink_axis_mask);
+ builder_.add_new_axis_mask(new_axis_mask);
+ builder_.add_ellipsis_mask(ellipsis_mask);
+ builder_.add_end_mask(end_mask);
+ builder_.add_begin_mask(begin_mask);
+ return builder_.Finish();
+}
+
+struct LogSoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LogSoftmaxOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LogSoftmaxOptionsBuilder
+{
+ typedef LogSoftmaxOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LogSoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LogSoftmaxOptionsBuilder &operator=(const LogSoftmaxOptionsBuilder &);
+ flatbuffers::Offset<LogSoftmaxOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LogSoftmaxOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LogSoftmaxOptions>
+CreateLogSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LogSoftmaxOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct CastOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef CastOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_IN_DATA_TYPE = 4,
+ VT_OUT_DATA_TYPE = 6
+ };
+ circle::TensorType in_data_type() const
+ {
+ return static_cast<circle::TensorType>(GetField<int8_t>(VT_IN_DATA_TYPE, 0));
+ }
+ circle::TensorType out_data_type() const
+ {
+ return static_cast<circle::TensorType>(GetField<int8_t>(VT_OUT_DATA_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_IN_DATA_TYPE) &&
+ VerifyField<int8_t>(verifier, VT_OUT_DATA_TYPE) && verifier.EndTable();
+ }
+};
+
+struct CastOptionsBuilder
+{
+ typedef CastOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_in_data_type(circle::TensorType in_data_type)
+ {
+ fbb_.AddElement<int8_t>(CastOptions::VT_IN_DATA_TYPE, static_cast<int8_t>(in_data_type), 0);
+ }
+ void add_out_data_type(circle::TensorType out_data_type)
+ {
+ fbb_.AddElement<int8_t>(CastOptions::VT_OUT_DATA_TYPE, static_cast<int8_t>(out_data_type), 0);
+ }
+ explicit CastOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ CastOptionsBuilder &operator=(const CastOptionsBuilder &);
+ flatbuffers::Offset<CastOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CastOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CastOptions>
+CreateCastOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::TensorType in_data_type = circle::TensorType_FLOAT32,
+ circle::TensorType out_data_type = circle::TensorType_FLOAT32)
+{
+ CastOptionsBuilder builder_(_fbb);
+ builder_.add_out_data_type(out_data_type);
+ builder_.add_in_data_type(in_data_type);
+ return builder_.Finish();
+}
+
+struct DequantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef DequantizeOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct DequantizeOptionsBuilder
+{
+ typedef DequantizeOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit DequantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DequantizeOptionsBuilder &operator=(const DequantizeOptionsBuilder &);
+ flatbuffers::Offset<DequantizeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DequantizeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DequantizeOptions>
+CreateDequantizeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ DequantizeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct MaximumMinimumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef MaximumMinimumOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct MaximumMinimumOptionsBuilder
+{
+ typedef MaximumMinimumOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit MaximumMinimumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MaximumMinimumOptionsBuilder &operator=(const MaximumMinimumOptionsBuilder &);
+ flatbuffers::Offset<MaximumMinimumOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MaximumMinimumOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MaximumMinimumOptions>
+CreateMaximumMinimumOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ MaximumMinimumOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct TileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef TileOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct TileOptionsBuilder
+{
+ typedef TileOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit TileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TileOptionsBuilder &operator=(const TileOptionsBuilder &);
+ flatbuffers::Offset<TileOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TileOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TileOptions> CreateTileOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ TileOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ArgMaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ArgMaxOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_OUTPUT_TYPE = 4
+ };
+ circle::TensorType output_type() const
+ {
+ return static_cast<circle::TensorType>(GetField<int8_t>(VT_OUTPUT_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_OUTPUT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct ArgMaxOptionsBuilder
+{
+ typedef ArgMaxOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_output_type(circle::TensorType output_type)
+ {
+ fbb_.AddElement<int8_t>(ArgMaxOptions::VT_OUTPUT_TYPE, static_cast<int8_t>(output_type), 0);
+ }
+ explicit ArgMaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ArgMaxOptionsBuilder &operator=(const ArgMaxOptionsBuilder &);
+ flatbuffers::Offset<ArgMaxOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ArgMaxOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ArgMaxOptions>
+CreateArgMaxOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::TensorType output_type = circle::TensorType_FLOAT32)
+{
+ ArgMaxOptionsBuilder builder_(_fbb);
+ builder_.add_output_type(output_type);
+ return builder_.Finish();
+}
+
+struct ArgMinOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ArgMinOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_OUTPUT_TYPE = 4
+ };
+ circle::TensorType output_type() const
+ {
+ return static_cast<circle::TensorType>(GetField<int8_t>(VT_OUTPUT_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_OUTPUT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct ArgMinOptionsBuilder
+{
+ typedef ArgMinOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_output_type(circle::TensorType output_type)
+ {
+ fbb_.AddElement<int8_t>(ArgMinOptions::VT_OUTPUT_TYPE, static_cast<int8_t>(output_type), 0);
+ }
+ explicit ArgMinOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ArgMinOptionsBuilder &operator=(const ArgMinOptionsBuilder &);
+ flatbuffers::Offset<ArgMinOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ArgMinOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ArgMinOptions>
+CreateArgMinOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::TensorType output_type = circle::TensorType_FLOAT32)
+{
+ ArgMinOptionsBuilder builder_(_fbb);
+ builder_.add_output_type(output_type);
+ return builder_.Finish();
+}
+
+struct GreaterOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef GreaterOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct GreaterOptionsBuilder
+{
+ typedef GreaterOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit GreaterOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ GreaterOptionsBuilder &operator=(const GreaterOptionsBuilder &);
+ flatbuffers::Offset<GreaterOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<GreaterOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<GreaterOptions>
+CreateGreaterOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ GreaterOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct GreaterEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef GreaterEqualOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct GreaterEqualOptionsBuilder
+{
+ typedef GreaterEqualOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit GreaterEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ GreaterEqualOptionsBuilder &operator=(const GreaterEqualOptionsBuilder &);
+ flatbuffers::Offset<GreaterEqualOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<GreaterEqualOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<GreaterEqualOptions>
+CreateGreaterEqualOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ GreaterEqualOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LessOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LessOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LessOptionsBuilder
+{
+ typedef LessOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LessOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LessOptionsBuilder &operator=(const LessOptionsBuilder &);
+ flatbuffers::Offset<LessOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LessOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LessOptions> CreateLessOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LessOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LessEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LessEqualOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LessEqualOptionsBuilder
+{
+ typedef LessEqualOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LessEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LessEqualOptionsBuilder &operator=(const LessEqualOptionsBuilder &);
+ flatbuffers::Offset<LessEqualOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LessEqualOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LessEqualOptions>
+CreateLessEqualOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LessEqualOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct NegOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef NegOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct NegOptionsBuilder
+{
+ typedef NegOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit NegOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ NegOptionsBuilder &operator=(const NegOptionsBuilder &);
+ flatbuffers::Offset<NegOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NegOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NegOptions> CreateNegOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ NegOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SelectOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SelectOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SelectOptionsBuilder
+{
+ typedef SelectOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SelectOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SelectOptionsBuilder &operator=(const SelectOptionsBuilder &);
+ flatbuffers::Offset<SelectOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SelectOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SelectOptions> CreateSelectOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SelectOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SliceOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SliceOptionsBuilder
+{
+ typedef SliceOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SliceOptionsBuilder &operator=(const SliceOptionsBuilder &);
+ flatbuffers::Offset<SliceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SliceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SliceOptions> CreateSliceOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SliceOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct TransposeConvOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef TransposeConvOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_PADDING = 4,
+ VT_STRIDE_W = 6,
+ VT_STRIDE_H = 8
+ };
+ circle::Padding padding() const
+ {
+ return static_cast<circle::Padding>(GetField<int8_t>(VT_PADDING, 0));
+ }
+ int32_t stride_w() const { return GetField<int32_t>(VT_STRIDE_W, 0); }
+ int32_t stride_h() const { return GetField<int32_t>(VT_STRIDE_H, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_PADDING) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_W) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_H) && verifier.EndTable();
+ }
+};
+
+struct TransposeConvOptionsBuilder
+{
+ typedef TransposeConvOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_padding(circle::Padding padding)
+ {
+ fbb_.AddElement<int8_t>(TransposeConvOptions::VT_PADDING, static_cast<int8_t>(padding), 0);
+ }
+ void add_stride_w(int32_t stride_w)
+ {
+ fbb_.AddElement<int32_t>(TransposeConvOptions::VT_STRIDE_W, stride_w, 0);
+ }
+ void add_stride_h(int32_t stride_h)
+ {
+ fbb_.AddElement<int32_t>(TransposeConvOptions::VT_STRIDE_H, stride_h, 0);
+ }
+ explicit TransposeConvOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TransposeConvOptionsBuilder &operator=(const TransposeConvOptionsBuilder &);
+ flatbuffers::Offset<TransposeConvOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TransposeConvOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TransposeConvOptions>
+CreateTransposeConvOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::Padding padding = circle::Padding_SAME, int32_t stride_w = 0,
+ int32_t stride_h = 0)
+{
+ TransposeConvOptionsBuilder builder_(_fbb);
+ builder_.add_stride_h(stride_h);
+ builder_.add_stride_w(stride_w);
+ builder_.add_padding(padding);
+ return builder_.Finish();
+}
+
+struct ExpandDimsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ExpandDimsOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ExpandDimsOptionsBuilder
+{
+ typedef ExpandDimsOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ExpandDimsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ExpandDimsOptionsBuilder &operator=(const ExpandDimsOptionsBuilder &);
+ flatbuffers::Offset<ExpandDimsOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ExpandDimsOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ExpandDimsOptions>
+CreateExpandDimsOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ExpandDimsOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SparseToDenseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SparseToDenseOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_VALIDATE_INDICES = 4
+ };
+ bool validate_indices() const { return GetField<uint8_t>(VT_VALIDATE_INDICES, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_VALIDATE_INDICES) &&
+ verifier.EndTable();
+ }
+};
+
+struct SparseToDenseOptionsBuilder
+{
+ typedef SparseToDenseOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_validate_indices(bool validate_indices)
+ {
+ fbb_.AddElement<uint8_t>(SparseToDenseOptions::VT_VALIDATE_INDICES,
+ static_cast<uint8_t>(validate_indices), 0);
+ }
+ explicit SparseToDenseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SparseToDenseOptionsBuilder &operator=(const SparseToDenseOptionsBuilder &);
+ flatbuffers::Offset<SparseToDenseOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SparseToDenseOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SparseToDenseOptions>
+CreateSparseToDenseOptions(flatbuffers::FlatBufferBuilder &_fbb, bool validate_indices = false)
+{
+ SparseToDenseOptionsBuilder builder_(_fbb);
+ builder_.add_validate_indices(validate_indices);
+ return builder_.Finish();
+}
+
+struct EqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef EqualOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct EqualOptionsBuilder
+{
+ typedef EqualOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit EqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ EqualOptionsBuilder &operator=(const EqualOptionsBuilder &);
+ flatbuffers::Offset<EqualOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<EqualOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<EqualOptions> CreateEqualOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ EqualOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct NotEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef NotEqualOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct NotEqualOptionsBuilder
+{
+ typedef NotEqualOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit NotEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ NotEqualOptionsBuilder &operator=(const NotEqualOptionsBuilder &);
+ flatbuffers::Offset<NotEqualOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NotEqualOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NotEqualOptions>
+CreateNotEqualOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ NotEqualOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ShapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ShapeOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_OUT_TYPE = 4
+ };
+ circle::TensorType out_type() const
+ {
+ return static_cast<circle::TensorType>(GetField<int8_t>(VT_OUT_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_OUT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct ShapeOptionsBuilder
+{
+ typedef ShapeOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_out_type(circle::TensorType out_type)
+ {
+ fbb_.AddElement<int8_t>(ShapeOptions::VT_OUT_TYPE, static_cast<int8_t>(out_type), 0);
+ }
+ explicit ShapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ShapeOptionsBuilder &operator=(const ShapeOptionsBuilder &);
+ flatbuffers::Offset<ShapeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ShapeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ShapeOptions>
+CreateShapeOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::TensorType out_type = circle::TensorType_FLOAT32)
+{
+ ShapeOptionsBuilder builder_(_fbb);
+ builder_.add_out_type(out_type);
+ return builder_.Finish();
+}
+
+struct RankOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef RankOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct RankOptionsBuilder
+{
+ typedef RankOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit RankOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ RankOptionsBuilder &operator=(const RankOptionsBuilder &);
+ flatbuffers::Offset<RankOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<RankOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<RankOptions> CreateRankOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ RankOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct PowOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef PowOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct PowOptionsBuilder
+{
+ typedef PowOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PowOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ PowOptionsBuilder &operator=(const PowOptionsBuilder &);
+ flatbuffers::Offset<PowOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PowOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PowOptions> CreatePowOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ PowOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct FakeQuantOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef FakeQuantOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_MIN = 4,
+ VT_MAX = 6,
+ VT_NUM_BITS = 8,
+ VT_NARROW_RANGE = 10
+ };
+ float min() const { return GetField<float>(VT_MIN, 0.0f); }
+ float max() const { return GetField<float>(VT_MAX, 0.0f); }
+ int32_t num_bits() const { return GetField<int32_t>(VT_NUM_BITS, 0); }
+ bool narrow_range() const { return GetField<uint8_t>(VT_NARROW_RANGE, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<float>(verifier, VT_MIN) &&
+ VerifyField<float>(verifier, VT_MAX) && VerifyField<int32_t>(verifier, VT_NUM_BITS) &&
+ VerifyField<uint8_t>(verifier, VT_NARROW_RANGE) && verifier.EndTable();
+ }
+};
+
+struct FakeQuantOptionsBuilder
+{
+ typedef FakeQuantOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_min(float min) { fbb_.AddElement<float>(FakeQuantOptions::VT_MIN, min, 0.0f); }
+ void add_max(float max) { fbb_.AddElement<float>(FakeQuantOptions::VT_MAX, max, 0.0f); }
+ void add_num_bits(int32_t num_bits)
+ {
+ fbb_.AddElement<int32_t>(FakeQuantOptions::VT_NUM_BITS, num_bits, 0);
+ }
+ void add_narrow_range(bool narrow_range)
+ {
+ fbb_.AddElement<uint8_t>(FakeQuantOptions::VT_NARROW_RANGE, static_cast<uint8_t>(narrow_range),
+ 0);
+ }
+ explicit FakeQuantOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FakeQuantOptionsBuilder &operator=(const FakeQuantOptionsBuilder &);
+ flatbuffers::Offset<FakeQuantOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FakeQuantOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FakeQuantOptions>
+CreateFakeQuantOptions(flatbuffers::FlatBufferBuilder &_fbb, float min = 0.0f, float max = 0.0f,
+ int32_t num_bits = 0, bool narrow_range = false)
+{
+ FakeQuantOptionsBuilder builder_(_fbb);
+ builder_.add_num_bits(num_bits);
+ builder_.add_max(max);
+ builder_.add_min(min);
+ builder_.add_narrow_range(narrow_range);
+ return builder_.Finish();
+}
+
+struct PackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef PackOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_VALUES_COUNT = 4,
+ VT_AXIS = 6
+ };
+ int32_t values_count() const { return GetField<int32_t>(VT_VALUES_COUNT, 0); }
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_VALUES_COUNT) &&
+ VerifyField<int32_t>(verifier, VT_AXIS) && verifier.EndTable();
+ }
+};
+
+struct PackOptionsBuilder
+{
+ typedef PackOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_values_count(int32_t values_count)
+ {
+ fbb_.AddElement<int32_t>(PackOptions::VT_VALUES_COUNT, values_count, 0);
+ }
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(PackOptions::VT_AXIS, axis, 0); }
+ explicit PackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ PackOptionsBuilder &operator=(const PackOptionsBuilder &);
+ flatbuffers::Offset<PackOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PackOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PackOptions>
+CreatePackOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t values_count = 0, int32_t axis = 0)
+{
+ PackOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ builder_.add_values_count(values_count);
+ return builder_.Finish();
+}
+
+struct LogicalOrOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LogicalOrOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LogicalOrOptionsBuilder
+{
+ typedef LogicalOrOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LogicalOrOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LogicalOrOptionsBuilder &operator=(const LogicalOrOptionsBuilder &);
+ flatbuffers::Offset<LogicalOrOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LogicalOrOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LogicalOrOptions>
+CreateLogicalOrOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LogicalOrOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct OneHotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef OneHotOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_AXIS = 4
+ };
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_AXIS) &&
+ verifier.EndTable();
+ }
+};
+
+struct OneHotOptionsBuilder
+{
+ typedef OneHotOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(OneHotOptions::VT_AXIS, axis, 0); }
+ explicit OneHotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ OneHotOptionsBuilder &operator=(const OneHotOptionsBuilder &);
+ flatbuffers::Offset<OneHotOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<OneHotOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<OneHotOptions> CreateOneHotOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t axis = 0)
+{
+ OneHotOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ return builder_.Finish();
+}
+
+struct AbsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef AbsOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct AbsOptionsBuilder
+{
+ typedef AbsOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit AbsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ AbsOptionsBuilder &operator=(const AbsOptionsBuilder &);
+ flatbuffers::Offset<AbsOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<AbsOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<AbsOptions> CreateAbsOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ AbsOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct HardSwishOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef HardSwishOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct HardSwishOptionsBuilder
+{
+ typedef HardSwishOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit HardSwishOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ HardSwishOptionsBuilder &operator=(const HardSwishOptionsBuilder &);
+ flatbuffers::Offset<HardSwishOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<HardSwishOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<HardSwishOptions>
+CreateHardSwishOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ HardSwishOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LogicalAndOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LogicalAndOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LogicalAndOptionsBuilder
+{
+ typedef LogicalAndOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LogicalAndOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LogicalAndOptionsBuilder &operator=(const LogicalAndOptionsBuilder &);
+ flatbuffers::Offset<LogicalAndOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LogicalAndOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LogicalAndOptions>
+CreateLogicalAndOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LogicalAndOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LogicalNotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LogicalNotOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LogicalNotOptionsBuilder
+{
+ typedef LogicalNotOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LogicalNotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LogicalNotOptionsBuilder &operator=(const LogicalNotOptionsBuilder &);
+ flatbuffers::Offset<LogicalNotOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LogicalNotOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LogicalNotOptions>
+CreateLogicalNotOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LogicalNotOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct UnpackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef UnpackOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_NUM = 4,
+ VT_AXIS = 6
+ };
+ int32_t num() const { return GetField<int32_t>(VT_NUM, 0); }
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NUM) &&
+ VerifyField<int32_t>(verifier, VT_AXIS) && verifier.EndTable();
+ }
+};
+
+struct UnpackOptionsBuilder
+{
+ typedef UnpackOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_num(int32_t num) { fbb_.AddElement<int32_t>(UnpackOptions::VT_NUM, num, 0); }
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(UnpackOptions::VT_AXIS, axis, 0); }
+ explicit UnpackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ UnpackOptionsBuilder &operator=(const UnpackOptionsBuilder &);
+ flatbuffers::Offset<UnpackOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<UnpackOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<UnpackOptions> CreateUnpackOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t num = 0, int32_t axis = 0)
+{
+ UnpackOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ builder_.add_num(num);
+ return builder_.Finish();
+}
+
+struct FloorDivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef FloorDivOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct FloorDivOptionsBuilder
+{
+ typedef FloorDivOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit FloorDivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FloorDivOptionsBuilder &operator=(const FloorDivOptionsBuilder &);
+ flatbuffers::Offset<FloorDivOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FloorDivOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FloorDivOptions>
+CreateFloorDivOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ FloorDivOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SquareOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SquareOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SquareOptionsBuilder
+{
+ typedef SquareOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SquareOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SquareOptionsBuilder &operator=(const SquareOptionsBuilder &);
+ flatbuffers::Offset<SquareOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SquareOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SquareOptions> CreateSquareOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SquareOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ZerosLikeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ZerosLikeOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ZerosLikeOptionsBuilder
+{
+ typedef ZerosLikeOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ZerosLikeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ZerosLikeOptionsBuilder &operator=(const ZerosLikeOptionsBuilder &);
+ flatbuffers::Offset<ZerosLikeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ZerosLikeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ZerosLikeOptions>
+CreateZerosLikeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ZerosLikeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct FillOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef FillOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct FillOptionsBuilder
+{
+ typedef FillOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit FillOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FillOptionsBuilder &operator=(const FillOptionsBuilder &);
+ flatbuffers::Offset<FillOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FillOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FillOptions> CreateFillOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ FillOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct FloorModOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef FloorModOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct FloorModOptionsBuilder
+{
+ typedef FloorModOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit FloorModOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FloorModOptionsBuilder &operator=(const FloorModOptionsBuilder &);
+ flatbuffers::Offset<FloorModOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FloorModOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FloorModOptions>
+CreateFloorModOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ FloorModOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct RangeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef RangeOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct RangeOptionsBuilder
+{
+ typedef RangeOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit RangeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ RangeOptionsBuilder &operator=(const RangeOptionsBuilder &);
+ flatbuffers::Offset<RangeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<RangeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<RangeOptions> CreateRangeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ RangeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LeakyReluOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef LeakyReluOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_ALPHA = 4
+ };
+ float alpha() const { return GetField<float>(VT_ALPHA, 0.0f); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<float>(verifier, VT_ALPHA) &&
+ verifier.EndTable();
+ }
+};
+
+struct LeakyReluOptionsBuilder
+{
+ typedef LeakyReluOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_alpha(float alpha) { fbb_.AddElement<float>(LeakyReluOptions::VT_ALPHA, alpha, 0.0f); }
+ explicit LeakyReluOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LeakyReluOptionsBuilder &operator=(const LeakyReluOptionsBuilder &);
+ flatbuffers::Offset<LeakyReluOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LeakyReluOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LeakyReluOptions>
+CreateLeakyReluOptions(flatbuffers::FlatBufferBuilder &_fbb, float alpha = 0.0f)
+{
+ LeakyReluOptionsBuilder builder_(_fbb);
+ builder_.add_alpha(alpha);
+ return builder_.Finish();
+}
+
+struct SquaredDifferenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SquaredDifferenceOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SquaredDifferenceOptionsBuilder
+{
+ typedef SquaredDifferenceOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SquaredDifferenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SquaredDifferenceOptionsBuilder &operator=(const SquaredDifferenceOptionsBuilder &);
+ flatbuffers::Offset<SquaredDifferenceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SquaredDifferenceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SquaredDifferenceOptions>
+CreateSquaredDifferenceOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SquaredDifferenceOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct MirrorPadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef MirrorPadOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_MODE = 4
+ };
+ circle::MirrorPadMode mode() const
+ {
+ return static_cast<circle::MirrorPadMode>(GetField<int8_t>(VT_MODE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_MODE) &&
+ verifier.EndTable();
+ }
+};
+
+struct MirrorPadOptionsBuilder
+{
+ typedef MirrorPadOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_mode(circle::MirrorPadMode mode)
+ {
+ fbb_.AddElement<int8_t>(MirrorPadOptions::VT_MODE, static_cast<int8_t>(mode), 0);
+ }
+ explicit MirrorPadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MirrorPadOptionsBuilder &operator=(const MirrorPadOptionsBuilder &);
+ flatbuffers::Offset<MirrorPadOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MirrorPadOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MirrorPadOptions>
+CreateMirrorPadOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::MirrorPadMode mode = circle::MirrorPadMode_REFLECT)
+{
+ MirrorPadOptionsBuilder builder_(_fbb);
+ builder_.add_mode(mode);
+ return builder_.Finish();
+}
+
+struct UniqueOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef UniqueOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_IDX_OUT_TYPE = 4
+ };
+ circle::TensorType idx_out_type() const
+ {
+ return static_cast<circle::TensorType>(GetField<int8_t>(VT_IDX_OUT_TYPE, 2));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_IDX_OUT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct UniqueOptionsBuilder
+{
+ typedef UniqueOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_idx_out_type(circle::TensorType idx_out_type)
+ {
+ fbb_.AddElement<int8_t>(UniqueOptions::VT_IDX_OUT_TYPE, static_cast<int8_t>(idx_out_type), 2);
+ }
+ explicit UniqueOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ UniqueOptionsBuilder &operator=(const UniqueOptionsBuilder &);
+ flatbuffers::Offset<UniqueOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<UniqueOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<UniqueOptions>
+CreateUniqueOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::TensorType idx_out_type = circle::TensorType_INT32)
+{
+ UniqueOptionsBuilder builder_(_fbb);
+ builder_.add_idx_out_type(idx_out_type);
+ return builder_.Finish();
+}
+
+struct ReverseV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ReverseV2OptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ReverseV2OptionsBuilder
+{
+ typedef ReverseV2Options Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ReverseV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ReverseV2OptionsBuilder &operator=(const ReverseV2OptionsBuilder &);
+ flatbuffers::Offset<ReverseV2Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ReverseV2Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ReverseV2Options>
+CreateReverseV2Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ReverseV2OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct AddNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef AddNOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct AddNOptionsBuilder
+{
+ typedef AddNOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit AddNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ AddNOptionsBuilder &operator=(const AddNOptionsBuilder &);
+ flatbuffers::Offset<AddNOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<AddNOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<AddNOptions> CreateAddNOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ AddNOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct GatherNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef GatherNdOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct GatherNdOptionsBuilder
+{
+ typedef GatherNdOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit GatherNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ GatherNdOptionsBuilder &operator=(const GatherNdOptionsBuilder &);
+ flatbuffers::Offset<GatherNdOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<GatherNdOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<GatherNdOptions>
+CreateGatherNdOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ GatherNdOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct WhereOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef WhereOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct WhereOptionsBuilder
+{
+ typedef WhereOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit WhereOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ WhereOptionsBuilder &operator=(const WhereOptionsBuilder &);
+ flatbuffers::Offset<WhereOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<WhereOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<WhereOptions> CreateWhereOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ WhereOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ReverseSequenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ReverseSequenceOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_SEQ_DIM = 4,
+ VT_BATCH_DIM = 6
+ };
+ int32_t seq_dim() const { return GetField<int32_t>(VT_SEQ_DIM, 0); }
+ int32_t batch_dim() const { return GetField<int32_t>(VT_BATCH_DIM, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_SEQ_DIM) &&
+ VerifyField<int32_t>(verifier, VT_BATCH_DIM) && verifier.EndTable();
+ }
+};
+
+struct ReverseSequenceOptionsBuilder
+{
+ typedef ReverseSequenceOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_seq_dim(int32_t seq_dim)
+ {
+ fbb_.AddElement<int32_t>(ReverseSequenceOptions::VT_SEQ_DIM, seq_dim, 0);
+ }
+ void add_batch_dim(int32_t batch_dim)
+ {
+ fbb_.AddElement<int32_t>(ReverseSequenceOptions::VT_BATCH_DIM, batch_dim, 0);
+ }
+ explicit ReverseSequenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ReverseSequenceOptionsBuilder &operator=(const ReverseSequenceOptionsBuilder &);
+ flatbuffers::Offset<ReverseSequenceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ReverseSequenceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ReverseSequenceOptions>
+CreateReverseSequenceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t seq_dim = 0,
+ int32_t batch_dim = 0)
+{
+ ReverseSequenceOptionsBuilder builder_(_fbb);
+ builder_.add_batch_dim(batch_dim);
+ builder_.add_seq_dim(seq_dim);
+ return builder_.Finish();
+}
+
+struct MatrixDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef MatrixDiagOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct MatrixDiagOptionsBuilder
+{
+ typedef MatrixDiagOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit MatrixDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MatrixDiagOptionsBuilder &operator=(const MatrixDiagOptionsBuilder &);
+ flatbuffers::Offset<MatrixDiagOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MatrixDiagOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MatrixDiagOptions>
+CreateMatrixDiagOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ MatrixDiagOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct QuantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef QuantizeOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct QuantizeOptionsBuilder
+{
+ typedef QuantizeOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit QuantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ QuantizeOptionsBuilder &operator=(const QuantizeOptionsBuilder &);
+ flatbuffers::Offset<QuantizeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<QuantizeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<QuantizeOptions>
+CreateQuantizeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ QuantizeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct MatrixSetDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef MatrixSetDiagOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct MatrixSetDiagOptionsBuilder
+{
+ typedef MatrixSetDiagOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit MatrixSetDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MatrixSetDiagOptionsBuilder &operator=(const MatrixSetDiagOptionsBuilder &);
+ flatbuffers::Offset<MatrixSetDiagOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MatrixSetDiagOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MatrixSetDiagOptions>
+CreateMatrixSetDiagOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ MatrixSetDiagOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct IfOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef IfOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_THEN_SUBGRAPH_INDEX = 4,
+ VT_ELSE_SUBGRAPH_INDEX = 6
+ };
+ int32_t then_subgraph_index() const { return GetField<int32_t>(VT_THEN_SUBGRAPH_INDEX, 0); }
+ int32_t else_subgraph_index() const { return GetField<int32_t>(VT_ELSE_SUBGRAPH_INDEX, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_THEN_SUBGRAPH_INDEX) &&
+ VerifyField<int32_t>(verifier, VT_ELSE_SUBGRAPH_INDEX) && verifier.EndTable();
+ }
+};
+
+struct IfOptionsBuilder
+{
+ typedef IfOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_then_subgraph_index(int32_t then_subgraph_index)
+ {
+ fbb_.AddElement<int32_t>(IfOptions::VT_THEN_SUBGRAPH_INDEX, then_subgraph_index, 0);
+ }
+ void add_else_subgraph_index(int32_t else_subgraph_index)
+ {
+ fbb_.AddElement<int32_t>(IfOptions::VT_ELSE_SUBGRAPH_INDEX, else_subgraph_index, 0);
+ }
+ explicit IfOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ IfOptionsBuilder &operator=(const IfOptionsBuilder &);
+ flatbuffers::Offset<IfOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<IfOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<IfOptions> CreateIfOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t then_subgraph_index = 0,
+ int32_t else_subgraph_index = 0)
+{
+ IfOptionsBuilder builder_(_fbb);
+ builder_.add_else_subgraph_index(else_subgraph_index);
+ builder_.add_then_subgraph_index(then_subgraph_index);
+ return builder_.Finish();
+}
+
+struct WhileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef WhileOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_COND_SUBGRAPH_INDEX = 4,
+ VT_BODY_SUBGRAPH_INDEX = 6
+ };
+ int32_t cond_subgraph_index() const { return GetField<int32_t>(VT_COND_SUBGRAPH_INDEX, 0); }
+ int32_t body_subgraph_index() const { return GetField<int32_t>(VT_BODY_SUBGRAPH_INDEX, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_COND_SUBGRAPH_INDEX) &&
+ VerifyField<int32_t>(verifier, VT_BODY_SUBGRAPH_INDEX) && verifier.EndTable();
+ }
+};
+
+struct WhileOptionsBuilder
+{
+ typedef WhileOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_cond_subgraph_index(int32_t cond_subgraph_index)
+ {
+ fbb_.AddElement<int32_t>(WhileOptions::VT_COND_SUBGRAPH_INDEX, cond_subgraph_index, 0);
+ }
+ void add_body_subgraph_index(int32_t body_subgraph_index)
+ {
+ fbb_.AddElement<int32_t>(WhileOptions::VT_BODY_SUBGRAPH_INDEX, body_subgraph_index, 0);
+ }
+ explicit WhileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ WhileOptionsBuilder &operator=(const WhileOptionsBuilder &);
+ flatbuffers::Offset<WhileOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<WhileOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<WhileOptions> CreateWhileOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t cond_subgraph_index = 0,
+ int32_t body_subgraph_index = 0)
+{
+ WhileOptionsBuilder builder_(_fbb);
+ builder_.add_body_subgraph_index(body_subgraph_index);
+ builder_.add_cond_subgraph_index(cond_subgraph_index);
+ return builder_.Finish();
+}
+
+struct NonMaxSuppressionV4Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef NonMaxSuppressionV4OptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct NonMaxSuppressionV4OptionsBuilder
+{
+ typedef NonMaxSuppressionV4Options Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit NonMaxSuppressionV4OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ NonMaxSuppressionV4OptionsBuilder &operator=(const NonMaxSuppressionV4OptionsBuilder &);
+ flatbuffers::Offset<NonMaxSuppressionV4Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NonMaxSuppressionV4Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NonMaxSuppressionV4Options>
+CreateNonMaxSuppressionV4Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ NonMaxSuppressionV4OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct NonMaxSuppressionV5Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef NonMaxSuppressionV5OptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct NonMaxSuppressionV5OptionsBuilder
+{
+ typedef NonMaxSuppressionV5Options Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit NonMaxSuppressionV5OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ NonMaxSuppressionV5OptionsBuilder &operator=(const NonMaxSuppressionV5OptionsBuilder &);
+ flatbuffers::Offset<NonMaxSuppressionV5Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NonMaxSuppressionV5Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NonMaxSuppressionV5Options>
+CreateNonMaxSuppressionV5Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ NonMaxSuppressionV5OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ScatterNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ScatterNdOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ScatterNdOptionsBuilder
+{
+ typedef ScatterNdOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ScatterNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ScatterNdOptionsBuilder &operator=(const ScatterNdOptionsBuilder &);
+ flatbuffers::Offset<ScatterNdOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ScatterNdOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ScatterNdOptions>
+CreateScatterNdOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ScatterNdOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SelectV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SelectV2OptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SelectV2OptionsBuilder
+{
+ typedef SelectV2Options Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SelectV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SelectV2OptionsBuilder &operator=(const SelectV2OptionsBuilder &);
+ flatbuffers::Offset<SelectV2Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SelectV2Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SelectV2Options>
+CreateSelectV2Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SelectV2OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct DensifyOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef DensifyOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct DensifyOptionsBuilder
+{
+ typedef DensifyOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit DensifyOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DensifyOptionsBuilder &operator=(const DensifyOptionsBuilder &);
+ flatbuffers::Offset<DensifyOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DensifyOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DensifyOptions>
+CreateDensifyOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ DensifyOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SegmentSumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SegmentSumOptionsBuilder Builder;
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SegmentSumOptionsBuilder
+{
+ typedef SegmentSumOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SegmentSumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SegmentSumOptionsBuilder &operator=(const SegmentSumOptionsBuilder &);
+ flatbuffers::Offset<SegmentSumOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SegmentSumOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SegmentSumOptions>
+CreateSegmentSumOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SegmentSumOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct BatchMatMulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef BatchMatMulOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_ADJOINT_LHS = 4,
+ VT_ADJOINT_RHS = 6
+ };
+ bool adjoint_lhs() const { return GetField<uint8_t>(VT_ADJOINT_LHS, 0) != 0; }
+ bool adjoint_rhs() const { return GetField<uint8_t>(VT_ADJOINT_RHS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_ADJOINT_LHS) &&
+ VerifyField<uint8_t>(verifier, VT_ADJOINT_RHS) && verifier.EndTable();
+ }
+};
+
+struct BatchMatMulOptionsBuilder
+{
+ typedef BatchMatMulOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_adjoint_lhs(bool adjoint_lhs)
+ {
+ fbb_.AddElement<uint8_t>(BatchMatMulOptions::VT_ADJOINT_LHS, static_cast<uint8_t>(adjoint_lhs),
+ 0);
+ }
+ void add_adjoint_rhs(bool adjoint_rhs)
+ {
+ fbb_.AddElement<uint8_t>(BatchMatMulOptions::VT_ADJOINT_RHS, static_cast<uint8_t>(adjoint_rhs),
+ 0);
+ }
+ explicit BatchMatMulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BatchMatMulOptionsBuilder &operator=(const BatchMatMulOptionsBuilder &);
+ flatbuffers::Offset<BatchMatMulOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BatchMatMulOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BatchMatMulOptions>
+CreateBatchMatMulOptions(flatbuffers::FlatBufferBuilder &_fbb, bool adjoint_lhs = false,
+ bool adjoint_rhs = false)
+{
+ BatchMatMulOptionsBuilder builder_(_fbb);
+ builder_.add_adjoint_rhs(adjoint_rhs);
+ builder_.add_adjoint_lhs(adjoint_lhs);
+ return builder_.Finish();
+}
+
+struct BCQGatherOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef BCQGatherOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_INPUT_HIDDEN_SIZE = 4,
+ VT_AXIS = 6
+ };
+ int32_t input_hidden_size() const { return GetField<int32_t>(VT_INPUT_HIDDEN_SIZE, 0); }
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_INPUT_HIDDEN_SIZE) &&
+ VerifyField<int32_t>(verifier, VT_AXIS) && verifier.EndTable();
+ }
+};
+
+struct BCQGatherOptionsBuilder
+{
+ typedef BCQGatherOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_input_hidden_size(int32_t input_hidden_size)
+ {
+ fbb_.AddElement<int32_t>(BCQGatherOptions::VT_INPUT_HIDDEN_SIZE, input_hidden_size, 0);
+ }
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(BCQGatherOptions::VT_AXIS, axis, 0); }
+ explicit BCQGatherOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BCQGatherOptionsBuilder &operator=(const BCQGatherOptionsBuilder &);
+ flatbuffers::Offset<BCQGatherOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BCQGatherOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BCQGatherOptions>
+CreateBCQGatherOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t input_hidden_size = 0,
+ int32_t axis = 0)
+{
+ BCQGatherOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ builder_.add_input_hidden_size(input_hidden_size);
+ return builder_.Finish();
+}
+
+struct BCQFullyConnectedOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef BCQFullyConnectedOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_WEIGHTS_HIDDEN_SIZE = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6
+ };
+ int32_t weights_hidden_size() const { return GetField<int32_t>(VT_WEIGHTS_HIDDEN_SIZE, 0); }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_WEIGHTS_HIDDEN_SIZE) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct BCQFullyConnectedOptionsBuilder
+{
+ typedef BCQFullyConnectedOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_weights_hidden_size(int32_t weights_hidden_size)
+ {
+ fbb_.AddElement<int32_t>(BCQFullyConnectedOptions::VT_WEIGHTS_HIDDEN_SIZE, weights_hidden_size,
+ 0);
+ }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(BCQFullyConnectedOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit BCQFullyConnectedOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BCQFullyConnectedOptionsBuilder &operator=(const BCQFullyConnectedOptionsBuilder &);
+ flatbuffers::Offset<BCQFullyConnectedOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BCQFullyConnectedOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BCQFullyConnectedOptions> CreateBCQFullyConnectedOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, int32_t weights_hidden_size = 0,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ BCQFullyConnectedOptionsBuilder builder_(_fbb);
+ builder_.add_weights_hidden_size(weights_hidden_size);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct InstanceNormOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef InstanceNormOptionsBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_EPSILON = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6
+ };
+ float epsilon() const { return GetField<float>(VT_EPSILON, 0.0f); }
+ circle::ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<circle::ActivationFunctionType>(
+ GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<float>(verifier, VT_EPSILON) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct InstanceNormOptionsBuilder
+{
+ typedef InstanceNormOptions Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_epsilon(float epsilon)
+ {
+ fbb_.AddElement<float>(InstanceNormOptions::VT_EPSILON, epsilon, 0.0f);
+ }
+ void add_fused_activation_function(circle::ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(InstanceNormOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit InstanceNormOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ InstanceNormOptionsBuilder &operator=(const InstanceNormOptionsBuilder &);
+ flatbuffers::Offset<InstanceNormOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<InstanceNormOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<InstanceNormOptions> CreateInstanceNormOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, float epsilon = 0.0f,
+ circle::ActivationFunctionType fused_activation_function = circle::ActivationFunctionType_NONE)
+{
+ InstanceNormOptionsBuilder builder_(_fbb);
+ builder_.add_epsilon(epsilon);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct OperatorCode FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef OperatorCodeBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_BUILTIN_CODE = 4,
+ VT_CUSTOM_CODE = 6,
+ VT_VERSION = 8
+ };
+ circle::BuiltinOperator builtin_code() const
+ {
+ return static_cast<circle::BuiltinOperator>(GetField<uint8_t>(VT_BUILTIN_CODE, 0));
+ }
+ const flatbuffers::String *custom_code() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_CUSTOM_CODE);
+ }
+ int32_t version() const { return GetField<int32_t>(VT_VERSION, 1); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_BUILTIN_CODE) &&
+ VerifyOffset(verifier, VT_CUSTOM_CODE) && verifier.VerifyString(custom_code()) &&
+ VerifyField<int32_t>(verifier, VT_VERSION) && verifier.EndTable();
+ }
+};
+
+struct OperatorCodeBuilder
+{
+ typedef OperatorCode Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_builtin_code(circle::BuiltinOperator builtin_code)
+ {
+ fbb_.AddElement<uint8_t>(OperatorCode::VT_BUILTIN_CODE, static_cast<uint8_t>(builtin_code), 0);
+ }
+ void add_custom_code(flatbuffers::Offset<flatbuffers::String> custom_code)
+ {
+ fbb_.AddOffset(OperatorCode::VT_CUSTOM_CODE, custom_code);
+ }
+ void add_version(int32_t version)
+ {
+ fbb_.AddElement<int32_t>(OperatorCode::VT_VERSION, version, 1);
+ }
+ explicit OperatorCodeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ OperatorCodeBuilder &operator=(const OperatorCodeBuilder &);
+ flatbuffers::Offset<OperatorCode> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<OperatorCode>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<OperatorCode>
+CreateOperatorCode(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::BuiltinOperator builtin_code = circle::BuiltinOperator_ADD,
+ flatbuffers::Offset<flatbuffers::String> custom_code = 0, int32_t version = 1)
+{
+ OperatorCodeBuilder builder_(_fbb);
+ builder_.add_version(version);
+ builder_.add_custom_code(custom_code);
+ builder_.add_builtin_code(builtin_code);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<OperatorCode>
+CreateOperatorCodeDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ circle::BuiltinOperator builtin_code = circle::BuiltinOperator_ADD,
+ const char *custom_code = nullptr, int32_t version = 1)
+{
+ auto custom_code__ = custom_code ? _fbb.CreateString(custom_code) : 0;
+ return circle::CreateOperatorCode(_fbb, builtin_code, custom_code__, version);
+}
+
+struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef OperatorBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_OPCODE_INDEX = 4,
+ VT_INPUTS = 6,
+ VT_OUTPUTS = 8,
+ VT_BUILTIN_OPTIONS_TYPE = 10,
+ VT_BUILTIN_OPTIONS = 12,
+ VT_CUSTOM_OPTIONS = 14,
+ VT_CUSTOM_OPTIONS_FORMAT = 16,
+ VT_MUTATING_VARIABLE_INPUTS = 18,
+ VT_INTERMEDIATES = 20
+ };
+ uint32_t opcode_index() const { return GetField<uint32_t>(VT_OPCODE_INDEX, 0); }
+ const flatbuffers::Vector<int32_t> *inputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_INPUTS);
+ }
+ const flatbuffers::Vector<int32_t> *outputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_OUTPUTS);
+ }
+ circle::BuiltinOptions builtin_options_type() const
+ {
+ return static_cast<circle::BuiltinOptions>(GetField<uint8_t>(VT_BUILTIN_OPTIONS_TYPE, 0));
+ }
+ const void *builtin_options() const { return GetPointer<const void *>(VT_BUILTIN_OPTIONS); }
+ template <typename T> const T *builtin_options_as() const;
+ const circle::Conv2DOptions *builtin_options_as_Conv2DOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_Conv2DOptions
+ ? static_cast<const circle::Conv2DOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::DepthwiseConv2DOptions *builtin_options_as_DepthwiseConv2DOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_DepthwiseConv2DOptions
+ ? static_cast<const circle::DepthwiseConv2DOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ConcatEmbeddingsOptions *builtin_options_as_ConcatEmbeddingsOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ConcatEmbeddingsOptions
+ ? static_cast<const circle::ConcatEmbeddingsOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LSHProjectionOptions *builtin_options_as_LSHProjectionOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LSHProjectionOptions
+ ? static_cast<const circle::LSHProjectionOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::Pool2DOptions *builtin_options_as_Pool2DOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_Pool2DOptions
+ ? static_cast<const circle::Pool2DOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SVDFOptions *builtin_options_as_SVDFOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SVDFOptions
+ ? static_cast<const circle::SVDFOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::RNNOptions *builtin_options_as_RNNOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_RNNOptions
+ ? static_cast<const circle::RNNOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::FullyConnectedOptions *builtin_options_as_FullyConnectedOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_FullyConnectedOptions
+ ? static_cast<const circle::FullyConnectedOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SoftmaxOptions *builtin_options_as_SoftmaxOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SoftmaxOptions
+ ? static_cast<const circle::SoftmaxOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ConcatenationOptions *builtin_options_as_ConcatenationOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ConcatenationOptions
+ ? static_cast<const circle::ConcatenationOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::AddOptions *builtin_options_as_AddOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_AddOptions
+ ? static_cast<const circle::AddOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::L2NormOptions *builtin_options_as_L2NormOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_L2NormOptions
+ ? static_cast<const circle::L2NormOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LocalResponseNormalizationOptions *
+ builtin_options_as_LocalResponseNormalizationOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LocalResponseNormalizationOptions
+ ? static_cast<const circle::LocalResponseNormalizationOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LSTMOptions *builtin_options_as_LSTMOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LSTMOptions
+ ? static_cast<const circle::LSTMOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ResizeBilinearOptions *builtin_options_as_ResizeBilinearOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ResizeBilinearOptions
+ ? static_cast<const circle::ResizeBilinearOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::CallOptions *builtin_options_as_CallOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_CallOptions
+ ? static_cast<const circle::CallOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ReshapeOptions *builtin_options_as_ReshapeOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ReshapeOptions
+ ? static_cast<const circle::ReshapeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SkipGramOptions *builtin_options_as_SkipGramOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SkipGramOptions
+ ? static_cast<const circle::SkipGramOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SpaceToDepthOptions *builtin_options_as_SpaceToDepthOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SpaceToDepthOptions
+ ? static_cast<const circle::SpaceToDepthOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::EmbeddingLookupSparseOptions *
+ builtin_options_as_EmbeddingLookupSparseOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_EmbeddingLookupSparseOptions
+ ? static_cast<const circle::EmbeddingLookupSparseOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::MulOptions *builtin_options_as_MulOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_MulOptions
+ ? static_cast<const circle::MulOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::PadOptions *builtin_options_as_PadOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_PadOptions
+ ? static_cast<const circle::PadOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::GatherOptions *builtin_options_as_GatherOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_GatherOptions
+ ? static_cast<const circle::GatherOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::BatchToSpaceNDOptions *builtin_options_as_BatchToSpaceNDOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_BatchToSpaceNDOptions
+ ? static_cast<const circle::BatchToSpaceNDOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SpaceToBatchNDOptions *builtin_options_as_SpaceToBatchNDOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SpaceToBatchNDOptions
+ ? static_cast<const circle::SpaceToBatchNDOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::TransposeOptions *builtin_options_as_TransposeOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_TransposeOptions
+ ? static_cast<const circle::TransposeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ReducerOptions *builtin_options_as_ReducerOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ReducerOptions
+ ? static_cast<const circle::ReducerOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SubOptions *builtin_options_as_SubOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SubOptions
+ ? static_cast<const circle::SubOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::DivOptions *builtin_options_as_DivOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_DivOptions
+ ? static_cast<const circle::DivOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SqueezeOptions *builtin_options_as_SqueezeOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SqueezeOptions
+ ? static_cast<const circle::SqueezeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SequenceRNNOptions *builtin_options_as_SequenceRNNOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SequenceRNNOptions
+ ? static_cast<const circle::SequenceRNNOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::StridedSliceOptions *builtin_options_as_StridedSliceOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_StridedSliceOptions
+ ? static_cast<const circle::StridedSliceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ExpOptions *builtin_options_as_ExpOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ExpOptions
+ ? static_cast<const circle::ExpOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::TopKV2Options *builtin_options_as_TopKV2Options() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_TopKV2Options
+ ? static_cast<const circle::TopKV2Options *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SplitOptions *builtin_options_as_SplitOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SplitOptions
+ ? static_cast<const circle::SplitOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LogSoftmaxOptions *builtin_options_as_LogSoftmaxOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LogSoftmaxOptions
+ ? static_cast<const circle::LogSoftmaxOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::CastOptions *builtin_options_as_CastOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_CastOptions
+ ? static_cast<const circle::CastOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::DequantizeOptions *builtin_options_as_DequantizeOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_DequantizeOptions
+ ? static_cast<const circle::DequantizeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::MaximumMinimumOptions *builtin_options_as_MaximumMinimumOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_MaximumMinimumOptions
+ ? static_cast<const circle::MaximumMinimumOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ArgMaxOptions *builtin_options_as_ArgMaxOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ArgMaxOptions
+ ? static_cast<const circle::ArgMaxOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LessOptions *builtin_options_as_LessOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LessOptions
+ ? static_cast<const circle::LessOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::NegOptions *builtin_options_as_NegOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_NegOptions
+ ? static_cast<const circle::NegOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::PadV2Options *builtin_options_as_PadV2Options() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_PadV2Options
+ ? static_cast<const circle::PadV2Options *>(builtin_options())
+ : nullptr;
+ }
+ const circle::GreaterOptions *builtin_options_as_GreaterOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_GreaterOptions
+ ? static_cast<const circle::GreaterOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::GreaterEqualOptions *builtin_options_as_GreaterEqualOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_GreaterEqualOptions
+ ? static_cast<const circle::GreaterEqualOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LessEqualOptions *builtin_options_as_LessEqualOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LessEqualOptions
+ ? static_cast<const circle::LessEqualOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SelectOptions *builtin_options_as_SelectOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SelectOptions
+ ? static_cast<const circle::SelectOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SliceOptions *builtin_options_as_SliceOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SliceOptions
+ ? static_cast<const circle::SliceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::TransposeConvOptions *builtin_options_as_TransposeConvOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_TransposeConvOptions
+ ? static_cast<const circle::TransposeConvOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SparseToDenseOptions *builtin_options_as_SparseToDenseOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SparseToDenseOptions
+ ? static_cast<const circle::SparseToDenseOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::TileOptions *builtin_options_as_TileOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_TileOptions
+ ? static_cast<const circle::TileOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ExpandDimsOptions *builtin_options_as_ExpandDimsOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ExpandDimsOptions
+ ? static_cast<const circle::ExpandDimsOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::EqualOptions *builtin_options_as_EqualOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_EqualOptions
+ ? static_cast<const circle::EqualOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::NotEqualOptions *builtin_options_as_NotEqualOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_NotEqualOptions
+ ? static_cast<const circle::NotEqualOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ShapeOptions *builtin_options_as_ShapeOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ShapeOptions
+ ? static_cast<const circle::ShapeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::PowOptions *builtin_options_as_PowOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_PowOptions
+ ? static_cast<const circle::PowOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ArgMinOptions *builtin_options_as_ArgMinOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ArgMinOptions
+ ? static_cast<const circle::ArgMinOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::FakeQuantOptions *builtin_options_as_FakeQuantOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_FakeQuantOptions
+ ? static_cast<const circle::FakeQuantOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::PackOptions *builtin_options_as_PackOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_PackOptions
+ ? static_cast<const circle::PackOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LogicalOrOptions *builtin_options_as_LogicalOrOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LogicalOrOptions
+ ? static_cast<const circle::LogicalOrOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::OneHotOptions *builtin_options_as_OneHotOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_OneHotOptions
+ ? static_cast<const circle::OneHotOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LogicalAndOptions *builtin_options_as_LogicalAndOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LogicalAndOptions
+ ? static_cast<const circle::LogicalAndOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LogicalNotOptions *builtin_options_as_LogicalNotOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LogicalNotOptions
+ ? static_cast<const circle::LogicalNotOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::UnpackOptions *builtin_options_as_UnpackOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_UnpackOptions
+ ? static_cast<const circle::UnpackOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::FloorDivOptions *builtin_options_as_FloorDivOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_FloorDivOptions
+ ? static_cast<const circle::FloorDivOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SquareOptions *builtin_options_as_SquareOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SquareOptions
+ ? static_cast<const circle::SquareOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ZerosLikeOptions *builtin_options_as_ZerosLikeOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ZerosLikeOptions
+ ? static_cast<const circle::ZerosLikeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::FillOptions *builtin_options_as_FillOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_FillOptions
+ ? static_cast<const circle::FillOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::BidirectionalSequenceLSTMOptions *
+ builtin_options_as_BidirectionalSequenceLSTMOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_BidirectionalSequenceLSTMOptions
+ ? static_cast<const circle::BidirectionalSequenceLSTMOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::BidirectionalSequenceRNNOptions *
+ builtin_options_as_BidirectionalSequenceRNNOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_BidirectionalSequenceRNNOptions
+ ? static_cast<const circle::BidirectionalSequenceRNNOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::UnidirectionalSequenceLSTMOptions *
+ builtin_options_as_UnidirectionalSequenceLSTMOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_UnidirectionalSequenceLSTMOptions
+ ? static_cast<const circle::UnidirectionalSequenceLSTMOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::FloorModOptions *builtin_options_as_FloorModOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_FloorModOptions
+ ? static_cast<const circle::FloorModOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::RangeOptions *builtin_options_as_RangeOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_RangeOptions
+ ? static_cast<const circle::RangeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ResizeNearestNeighborOptions *
+ builtin_options_as_ResizeNearestNeighborOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ResizeNearestNeighborOptions
+ ? static_cast<const circle::ResizeNearestNeighborOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::LeakyReluOptions *builtin_options_as_LeakyReluOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_LeakyReluOptions
+ ? static_cast<const circle::LeakyReluOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SquaredDifferenceOptions *builtin_options_as_SquaredDifferenceOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SquaredDifferenceOptions
+ ? static_cast<const circle::SquaredDifferenceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::MirrorPadOptions *builtin_options_as_MirrorPadOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_MirrorPadOptions
+ ? static_cast<const circle::MirrorPadOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::AbsOptions *builtin_options_as_AbsOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_AbsOptions
+ ? static_cast<const circle::AbsOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SplitVOptions *builtin_options_as_SplitVOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SplitVOptions
+ ? static_cast<const circle::SplitVOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::UniqueOptions *builtin_options_as_UniqueOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_UniqueOptions
+ ? static_cast<const circle::UniqueOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ReverseV2Options *builtin_options_as_ReverseV2Options() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ReverseV2Options
+ ? static_cast<const circle::ReverseV2Options *>(builtin_options())
+ : nullptr;
+ }
+ const circle::AddNOptions *builtin_options_as_AddNOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_AddNOptions
+ ? static_cast<const circle::AddNOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::GatherNdOptions *builtin_options_as_GatherNdOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_GatherNdOptions
+ ? static_cast<const circle::GatherNdOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::CosOptions *builtin_options_as_CosOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_CosOptions
+ ? static_cast<const circle::CosOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::WhereOptions *builtin_options_as_WhereOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_WhereOptions
+ ? static_cast<const circle::WhereOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::RankOptions *builtin_options_as_RankOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_RankOptions
+ ? static_cast<const circle::RankOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ReverseSequenceOptions *builtin_options_as_ReverseSequenceOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ReverseSequenceOptions
+ ? static_cast<const circle::ReverseSequenceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::MatrixDiagOptions *builtin_options_as_MatrixDiagOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_MatrixDiagOptions
+ ? static_cast<const circle::MatrixDiagOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::QuantizeOptions *builtin_options_as_QuantizeOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_QuantizeOptions
+ ? static_cast<const circle::QuantizeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::MatrixSetDiagOptions *builtin_options_as_MatrixSetDiagOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_MatrixSetDiagOptions
+ ? static_cast<const circle::MatrixSetDiagOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::HardSwishOptions *builtin_options_as_HardSwishOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_HardSwishOptions
+ ? static_cast<const circle::HardSwishOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::IfOptions *builtin_options_as_IfOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_IfOptions
+ ? static_cast<const circle::IfOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::WhileOptions *builtin_options_as_WhileOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_WhileOptions
+ ? static_cast<const circle::WhileOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::DepthToSpaceOptions *builtin_options_as_DepthToSpaceOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_DepthToSpaceOptions
+ ? static_cast<const circle::DepthToSpaceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::NonMaxSuppressionV4Options *builtin_options_as_NonMaxSuppressionV4Options() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_NonMaxSuppressionV4Options
+ ? static_cast<const circle::NonMaxSuppressionV4Options *>(builtin_options())
+ : nullptr;
+ }
+ const circle::NonMaxSuppressionV5Options *builtin_options_as_NonMaxSuppressionV5Options() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_NonMaxSuppressionV5Options
+ ? static_cast<const circle::NonMaxSuppressionV5Options *>(builtin_options())
+ : nullptr;
+ }
+ const circle::ScatterNdOptions *builtin_options_as_ScatterNdOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_ScatterNdOptions
+ ? static_cast<const circle::ScatterNdOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SelectV2Options *builtin_options_as_SelectV2Options() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SelectV2Options
+ ? static_cast<const circle::SelectV2Options *>(builtin_options())
+ : nullptr;
+ }
+ const circle::DensifyOptions *builtin_options_as_DensifyOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_DensifyOptions
+ ? static_cast<const circle::DensifyOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::SegmentSumOptions *builtin_options_as_SegmentSumOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_SegmentSumOptions
+ ? static_cast<const circle::SegmentSumOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::BatchMatMulOptions *builtin_options_as_BatchMatMulOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_BatchMatMulOptions
+ ? static_cast<const circle::BatchMatMulOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::BCQGatherOptions *builtin_options_as_BCQGatherOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_BCQGatherOptions
+ ? static_cast<const circle::BCQGatherOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::BCQFullyConnectedOptions *builtin_options_as_BCQFullyConnectedOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_BCQFullyConnectedOptions
+ ? static_cast<const circle::BCQFullyConnectedOptions *>(builtin_options())
+ : nullptr;
+ }
+ const circle::InstanceNormOptions *builtin_options_as_InstanceNormOptions() const
+ {
+ return builtin_options_type() == circle::BuiltinOptions_InstanceNormOptions
+ ? static_cast<const circle::InstanceNormOptions *>(builtin_options())
+ : nullptr;
+ }
+ const flatbuffers::Vector<uint8_t> *custom_options() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_CUSTOM_OPTIONS);
+ }
+ circle::CustomOptionsFormat custom_options_format() const
+ {
+ return static_cast<circle::CustomOptionsFormat>(GetField<int8_t>(VT_CUSTOM_OPTIONS_FORMAT, 0));
+ }
+ const flatbuffers::Vector<uint8_t> *mutating_variable_inputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_MUTATING_VARIABLE_INPUTS);
+ }
+ const flatbuffers::Vector<int32_t> *intermediates() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_INTERMEDIATES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint32_t>(verifier, VT_OPCODE_INDEX) &&
+ VerifyOffset(verifier, VT_INPUTS) && verifier.VerifyVector(inputs()) &&
+ VerifyOffset(verifier, VT_OUTPUTS) && verifier.VerifyVector(outputs()) &&
+ VerifyField<uint8_t>(verifier, VT_BUILTIN_OPTIONS_TYPE) &&
+ VerifyOffset(verifier, VT_BUILTIN_OPTIONS) &&
+ VerifyBuiltinOptions(verifier, builtin_options(), builtin_options_type()) &&
+ VerifyOffset(verifier, VT_CUSTOM_OPTIONS) && verifier.VerifyVector(custom_options()) &&
+ VerifyField<int8_t>(verifier, VT_CUSTOM_OPTIONS_FORMAT) &&
+ VerifyOffset(verifier, VT_MUTATING_VARIABLE_INPUTS) &&
+ verifier.VerifyVector(mutating_variable_inputs()) &&
+ VerifyOffset(verifier, VT_INTERMEDIATES) && verifier.VerifyVector(intermediates()) &&
+ verifier.EndTable();
+ }
+};
+
+template <>
+inline const circle::Conv2DOptions *Operator::builtin_options_as<circle::Conv2DOptions>() const
+{
+ return builtin_options_as_Conv2DOptions();
+}
+
+template <>
+inline const circle::DepthwiseConv2DOptions *
+Operator::builtin_options_as<circle::DepthwiseConv2DOptions>() const
+{
+ return builtin_options_as_DepthwiseConv2DOptions();
+}
+
+template <>
+inline const circle::ConcatEmbeddingsOptions *
+Operator::builtin_options_as<circle::ConcatEmbeddingsOptions>() const
+{
+ return builtin_options_as_ConcatEmbeddingsOptions();
+}
+
+template <>
+inline const circle::LSHProjectionOptions *
+Operator::builtin_options_as<circle::LSHProjectionOptions>() const
+{
+ return builtin_options_as_LSHProjectionOptions();
+}
+
+template <>
+inline const circle::Pool2DOptions *Operator::builtin_options_as<circle::Pool2DOptions>() const
+{
+ return builtin_options_as_Pool2DOptions();
+}
+
+template <>
+inline const circle::SVDFOptions *Operator::builtin_options_as<circle::SVDFOptions>() const
+{
+ return builtin_options_as_SVDFOptions();
+}
+
+template <>
+inline const circle::RNNOptions *Operator::builtin_options_as<circle::RNNOptions>() const
+{
+ return builtin_options_as_RNNOptions();
+}
+
+template <>
+inline const circle::FullyConnectedOptions *
+Operator::builtin_options_as<circle::FullyConnectedOptions>() const
+{
+ return builtin_options_as_FullyConnectedOptions();
+}
+
+template <>
+inline const circle::SoftmaxOptions *Operator::builtin_options_as<circle::SoftmaxOptions>() const
+{
+ return builtin_options_as_SoftmaxOptions();
+}
+
+template <>
+inline const circle::ConcatenationOptions *
+Operator::builtin_options_as<circle::ConcatenationOptions>() const
+{
+ return builtin_options_as_ConcatenationOptions();
+}
+
+template <>
+inline const circle::AddOptions *Operator::builtin_options_as<circle::AddOptions>() const
+{
+ return builtin_options_as_AddOptions();
+}
+
+template <>
+inline const circle::L2NormOptions *Operator::builtin_options_as<circle::L2NormOptions>() const
+{
+ return builtin_options_as_L2NormOptions();
+}
+
+template <>
+inline const circle::LocalResponseNormalizationOptions *
+Operator::builtin_options_as<circle::LocalResponseNormalizationOptions>() const
+{
+ return builtin_options_as_LocalResponseNormalizationOptions();
+}
+
+template <>
+inline const circle::LSTMOptions *Operator::builtin_options_as<circle::LSTMOptions>() const
+{
+ return builtin_options_as_LSTMOptions();
+}
+
+template <>
+inline const circle::ResizeBilinearOptions *
+Operator::builtin_options_as<circle::ResizeBilinearOptions>() const
+{
+ return builtin_options_as_ResizeBilinearOptions();
+}
+
+template <>
+inline const circle::CallOptions *Operator::builtin_options_as<circle::CallOptions>() const
+{
+ return builtin_options_as_CallOptions();
+}
+
+template <>
+inline const circle::ReshapeOptions *Operator::builtin_options_as<circle::ReshapeOptions>() const
+{
+ return builtin_options_as_ReshapeOptions();
+}
+
+template <>
+inline const circle::SkipGramOptions *Operator::builtin_options_as<circle::SkipGramOptions>() const
+{
+ return builtin_options_as_SkipGramOptions();
+}
+
+template <>
+inline const circle::SpaceToDepthOptions *
+Operator::builtin_options_as<circle::SpaceToDepthOptions>() const
+{
+ return builtin_options_as_SpaceToDepthOptions();
+}
+
+template <>
+inline const circle::EmbeddingLookupSparseOptions *
+Operator::builtin_options_as<circle::EmbeddingLookupSparseOptions>() const
+{
+ return builtin_options_as_EmbeddingLookupSparseOptions();
+}
+
+template <>
+inline const circle::MulOptions *Operator::builtin_options_as<circle::MulOptions>() const
+{
+ return builtin_options_as_MulOptions();
+}
+
+template <>
+inline const circle::PadOptions *Operator::builtin_options_as<circle::PadOptions>() const
+{
+ return builtin_options_as_PadOptions();
+}
+
+template <>
+inline const circle::GatherOptions *Operator::builtin_options_as<circle::GatherOptions>() const
+{
+ return builtin_options_as_GatherOptions();
+}
+
+template <>
+inline const circle::BatchToSpaceNDOptions *
+Operator::builtin_options_as<circle::BatchToSpaceNDOptions>() const
+{
+ return builtin_options_as_BatchToSpaceNDOptions();
+}
+
+template <>
+inline const circle::SpaceToBatchNDOptions *
+Operator::builtin_options_as<circle::SpaceToBatchNDOptions>() const
+{
+ return builtin_options_as_SpaceToBatchNDOptions();
+}
+
+template <>
+inline const circle::TransposeOptions *
+Operator::builtin_options_as<circle::TransposeOptions>() const
+{
+ return builtin_options_as_TransposeOptions();
+}
+
+template <>
+inline const circle::ReducerOptions *Operator::builtin_options_as<circle::ReducerOptions>() const
+{
+ return builtin_options_as_ReducerOptions();
+}
+
+template <>
+inline const circle::SubOptions *Operator::builtin_options_as<circle::SubOptions>() const
+{
+ return builtin_options_as_SubOptions();
+}
+
+template <>
+inline const circle::DivOptions *Operator::builtin_options_as<circle::DivOptions>() const
+{
+ return builtin_options_as_DivOptions();
+}
+
+template <>
+inline const circle::SqueezeOptions *Operator::builtin_options_as<circle::SqueezeOptions>() const
+{
+ return builtin_options_as_SqueezeOptions();
+}
+
+template <>
+inline const circle::SequenceRNNOptions *
+Operator::builtin_options_as<circle::SequenceRNNOptions>() const
+{
+ return builtin_options_as_SequenceRNNOptions();
+}
+
+template <>
+inline const circle::StridedSliceOptions *
+Operator::builtin_options_as<circle::StridedSliceOptions>() const
+{
+ return builtin_options_as_StridedSliceOptions();
+}
+
+template <>
+inline const circle::ExpOptions *Operator::builtin_options_as<circle::ExpOptions>() const
+{
+ return builtin_options_as_ExpOptions();
+}
+
+template <>
+inline const circle::TopKV2Options *Operator::builtin_options_as<circle::TopKV2Options>() const
+{
+ return builtin_options_as_TopKV2Options();
+}
+
+template <>
+inline const circle::SplitOptions *Operator::builtin_options_as<circle::SplitOptions>() const
+{
+ return builtin_options_as_SplitOptions();
+}
+
+template <>
+inline const circle::LogSoftmaxOptions *
+Operator::builtin_options_as<circle::LogSoftmaxOptions>() const
+{
+ return builtin_options_as_LogSoftmaxOptions();
+}
+
+template <>
+inline const circle::CastOptions *Operator::builtin_options_as<circle::CastOptions>() const
+{
+ return builtin_options_as_CastOptions();
+}
+
+template <>
+inline const circle::DequantizeOptions *
+Operator::builtin_options_as<circle::DequantizeOptions>() const
+{
+ return builtin_options_as_DequantizeOptions();
+}
+
+template <>
+inline const circle::MaximumMinimumOptions *
+Operator::builtin_options_as<circle::MaximumMinimumOptions>() const
+{
+ return builtin_options_as_MaximumMinimumOptions();
+}
+
+template <>
+inline const circle::ArgMaxOptions *Operator::builtin_options_as<circle::ArgMaxOptions>() const
+{
+ return builtin_options_as_ArgMaxOptions();
+}
+
+template <>
+inline const circle::LessOptions *Operator::builtin_options_as<circle::LessOptions>() const
+{
+ return builtin_options_as_LessOptions();
+}
+
+template <>
+inline const circle::NegOptions *Operator::builtin_options_as<circle::NegOptions>() const
+{
+ return builtin_options_as_NegOptions();
+}
+
+template <>
+inline const circle::PadV2Options *Operator::builtin_options_as<circle::PadV2Options>() const
+{
+ return builtin_options_as_PadV2Options();
+}
+
+template <>
+inline const circle::GreaterOptions *Operator::builtin_options_as<circle::GreaterOptions>() const
+{
+ return builtin_options_as_GreaterOptions();
+}
+
+template <>
+inline const circle::GreaterEqualOptions *
+Operator::builtin_options_as<circle::GreaterEqualOptions>() const
+{
+ return builtin_options_as_GreaterEqualOptions();
+}
+
+template <>
+inline const circle::LessEqualOptions *
+Operator::builtin_options_as<circle::LessEqualOptions>() const
+{
+ return builtin_options_as_LessEqualOptions();
+}
+
+template <>
+inline const circle::SelectOptions *Operator::builtin_options_as<circle::SelectOptions>() const
+{
+ return builtin_options_as_SelectOptions();
+}
+
+template <>
+inline const circle::SliceOptions *Operator::builtin_options_as<circle::SliceOptions>() const
+{
+ return builtin_options_as_SliceOptions();
+}
+
+template <>
+inline const circle::TransposeConvOptions *
+Operator::builtin_options_as<circle::TransposeConvOptions>() const
+{
+ return builtin_options_as_TransposeConvOptions();
+}
+
+template <>
+inline const circle::SparseToDenseOptions *
+Operator::builtin_options_as<circle::SparseToDenseOptions>() const
+{
+ return builtin_options_as_SparseToDenseOptions();
+}
+
+template <>
+inline const circle::TileOptions *Operator::builtin_options_as<circle::TileOptions>() const
+{
+ return builtin_options_as_TileOptions();
+}
+
+template <>
+inline const circle::ExpandDimsOptions *
+Operator::builtin_options_as<circle::ExpandDimsOptions>() const
+{
+ return builtin_options_as_ExpandDimsOptions();
+}
+
+template <>
+inline const circle::EqualOptions *Operator::builtin_options_as<circle::EqualOptions>() const
+{
+ return builtin_options_as_EqualOptions();
+}
+
+template <>
+inline const circle::NotEqualOptions *Operator::builtin_options_as<circle::NotEqualOptions>() const
+{
+ return builtin_options_as_NotEqualOptions();
+}
+
+template <>
+inline const circle::ShapeOptions *Operator::builtin_options_as<circle::ShapeOptions>() const
+{
+ return builtin_options_as_ShapeOptions();
+}
+
+template <>
+inline const circle::PowOptions *Operator::builtin_options_as<circle::PowOptions>() const
+{
+ return builtin_options_as_PowOptions();
+}
+
+template <>
+inline const circle::ArgMinOptions *Operator::builtin_options_as<circle::ArgMinOptions>() const
+{
+ return builtin_options_as_ArgMinOptions();
+}
+
+template <>
+inline const circle::FakeQuantOptions *
+Operator::builtin_options_as<circle::FakeQuantOptions>() const
+{
+ return builtin_options_as_FakeQuantOptions();
+}
+
+template <>
+inline const circle::PackOptions *Operator::builtin_options_as<circle::PackOptions>() const
+{
+ return builtin_options_as_PackOptions();
+}
+
+template <>
+inline const circle::LogicalOrOptions *
+Operator::builtin_options_as<circle::LogicalOrOptions>() const
+{
+ return builtin_options_as_LogicalOrOptions();
+}
+
+template <>
+inline const circle::OneHotOptions *Operator::builtin_options_as<circle::OneHotOptions>() const
+{
+ return builtin_options_as_OneHotOptions();
+}
+
+template <>
+inline const circle::LogicalAndOptions *
+Operator::builtin_options_as<circle::LogicalAndOptions>() const
+{
+ return builtin_options_as_LogicalAndOptions();
+}
+
+template <>
+inline const circle::LogicalNotOptions *
+Operator::builtin_options_as<circle::LogicalNotOptions>() const
+{
+ return builtin_options_as_LogicalNotOptions();
+}
+
+template <>
+inline const circle::UnpackOptions *Operator::builtin_options_as<circle::UnpackOptions>() const
+{
+ return builtin_options_as_UnpackOptions();
+}
+
+template <>
+inline const circle::FloorDivOptions *Operator::builtin_options_as<circle::FloorDivOptions>() const
+{
+ return builtin_options_as_FloorDivOptions();
+}
+
+template <>
+inline const circle::SquareOptions *Operator::builtin_options_as<circle::SquareOptions>() const
+{
+ return builtin_options_as_SquareOptions();
+}
+
+template <>
+inline const circle::ZerosLikeOptions *
+Operator::builtin_options_as<circle::ZerosLikeOptions>() const
+{
+ return builtin_options_as_ZerosLikeOptions();
+}
+
+template <>
+inline const circle::FillOptions *Operator::builtin_options_as<circle::FillOptions>() const
+{
+ return builtin_options_as_FillOptions();
+}
+
+template <>
+inline const circle::BidirectionalSequenceLSTMOptions *
+Operator::builtin_options_as<circle::BidirectionalSequenceLSTMOptions>() const
+{
+ return builtin_options_as_BidirectionalSequenceLSTMOptions();
+}
+
+template <>
+inline const circle::BidirectionalSequenceRNNOptions *
+Operator::builtin_options_as<circle::BidirectionalSequenceRNNOptions>() const
+{
+ return builtin_options_as_BidirectionalSequenceRNNOptions();
+}
+
+template <>
+inline const circle::UnidirectionalSequenceLSTMOptions *
+Operator::builtin_options_as<circle::UnidirectionalSequenceLSTMOptions>() const
+{
+ return builtin_options_as_UnidirectionalSequenceLSTMOptions();
+}
+
+template <>
+inline const circle::FloorModOptions *Operator::builtin_options_as<circle::FloorModOptions>() const
+{
+ return builtin_options_as_FloorModOptions();
+}
+
+template <>
+inline const circle::RangeOptions *Operator::builtin_options_as<circle::RangeOptions>() const
+{
+ return builtin_options_as_RangeOptions();
+}
+
+template <>
+inline const circle::ResizeNearestNeighborOptions *
+Operator::builtin_options_as<circle::ResizeNearestNeighborOptions>() const
+{
+ return builtin_options_as_ResizeNearestNeighborOptions();
+}
+
+template <>
+inline const circle::LeakyReluOptions *
+Operator::builtin_options_as<circle::LeakyReluOptions>() const
+{
+ return builtin_options_as_LeakyReluOptions();
+}
+
+template <>
+inline const circle::SquaredDifferenceOptions *
+Operator::builtin_options_as<circle::SquaredDifferenceOptions>() const
+{
+ return builtin_options_as_SquaredDifferenceOptions();
+}
+
+template <>
+inline const circle::MirrorPadOptions *
+Operator::builtin_options_as<circle::MirrorPadOptions>() const
+{
+ return builtin_options_as_MirrorPadOptions();
+}
+
+template <>
+inline const circle::AbsOptions *Operator::builtin_options_as<circle::AbsOptions>() const
+{
+ return builtin_options_as_AbsOptions();
+}
+
+template <>
+inline const circle::SplitVOptions *Operator::builtin_options_as<circle::SplitVOptions>() const
+{
+ return builtin_options_as_SplitVOptions();
+}
+
+template <>
+inline const circle::UniqueOptions *Operator::builtin_options_as<circle::UniqueOptions>() const
+{
+ return builtin_options_as_UniqueOptions();
+}
+
+template <>
+inline const circle::ReverseV2Options *
+Operator::builtin_options_as<circle::ReverseV2Options>() const
+{
+ return builtin_options_as_ReverseV2Options();
+}
+
+template <>
+inline const circle::AddNOptions *Operator::builtin_options_as<circle::AddNOptions>() const
+{
+ return builtin_options_as_AddNOptions();
+}
+
+template <>
+inline const circle::GatherNdOptions *Operator::builtin_options_as<circle::GatherNdOptions>() const
+{
+ return builtin_options_as_GatherNdOptions();
+}
+
+template <>
+inline const circle::CosOptions *Operator::builtin_options_as<circle::CosOptions>() const
+{
+ return builtin_options_as_CosOptions();
+}
+
+template <>
+inline const circle::WhereOptions *Operator::builtin_options_as<circle::WhereOptions>() const
+{
+ return builtin_options_as_WhereOptions();
+}
+
+template <>
+inline const circle::RankOptions *Operator::builtin_options_as<circle::RankOptions>() const
+{
+ return builtin_options_as_RankOptions();
+}
+
+template <>
+inline const circle::ReverseSequenceOptions *
+Operator::builtin_options_as<circle::ReverseSequenceOptions>() const
+{
+ return builtin_options_as_ReverseSequenceOptions();
+}
+
+template <>
+inline const circle::MatrixDiagOptions *
+Operator::builtin_options_as<circle::MatrixDiagOptions>() const
+{
+ return builtin_options_as_MatrixDiagOptions();
+}
+
+template <>
+inline const circle::QuantizeOptions *Operator::builtin_options_as<circle::QuantizeOptions>() const
+{
+ return builtin_options_as_QuantizeOptions();
+}
+
+template <>
+inline const circle::MatrixSetDiagOptions *
+Operator::builtin_options_as<circle::MatrixSetDiagOptions>() const
+{
+ return builtin_options_as_MatrixSetDiagOptions();
+}
+
+template <>
+inline const circle::HardSwishOptions *
+Operator::builtin_options_as<circle::HardSwishOptions>() const
+{
+ return builtin_options_as_HardSwishOptions();
+}
+
+template <> inline const circle::IfOptions *Operator::builtin_options_as<circle::IfOptions>() const
+{
+ return builtin_options_as_IfOptions();
+}
+
+template <>
+inline const circle::WhileOptions *Operator::builtin_options_as<circle::WhileOptions>() const
+{
+ return builtin_options_as_WhileOptions();
+}
+
+template <>
+inline const circle::DepthToSpaceOptions *
+Operator::builtin_options_as<circle::DepthToSpaceOptions>() const
+{
+ return builtin_options_as_DepthToSpaceOptions();
+}
+
+template <>
+inline const circle::NonMaxSuppressionV4Options *
+Operator::builtin_options_as<circle::NonMaxSuppressionV4Options>() const
+{
+ return builtin_options_as_NonMaxSuppressionV4Options();
+}
+
+template <>
+inline const circle::NonMaxSuppressionV5Options *
+Operator::builtin_options_as<circle::NonMaxSuppressionV5Options>() const
+{
+ return builtin_options_as_NonMaxSuppressionV5Options();
+}
+
+template <>
+inline const circle::ScatterNdOptions *
+Operator::builtin_options_as<circle::ScatterNdOptions>() const
+{
+ return builtin_options_as_ScatterNdOptions();
+}
+
+template <>
+inline const circle::SelectV2Options *Operator::builtin_options_as<circle::SelectV2Options>() const
+{
+ return builtin_options_as_SelectV2Options();
+}
+
+template <>
+inline const circle::DensifyOptions *Operator::builtin_options_as<circle::DensifyOptions>() const
+{
+ return builtin_options_as_DensifyOptions();
+}
+
+template <>
+inline const circle::SegmentSumOptions *
+Operator::builtin_options_as<circle::SegmentSumOptions>() const
+{
+ return builtin_options_as_SegmentSumOptions();
+}
+
+template <>
+inline const circle::BatchMatMulOptions *
+Operator::builtin_options_as<circle::BatchMatMulOptions>() const
+{
+ return builtin_options_as_BatchMatMulOptions();
+}
+
+template <>
+inline const circle::BCQGatherOptions *
+Operator::builtin_options_as<circle::BCQGatherOptions>() const
+{
+ return builtin_options_as_BCQGatherOptions();
+}
+
+template <>
+inline const circle::BCQFullyConnectedOptions *
+Operator::builtin_options_as<circle::BCQFullyConnectedOptions>() const
+{
+ return builtin_options_as_BCQFullyConnectedOptions();
+}
+
+template <>
+inline const circle::InstanceNormOptions *
+Operator::builtin_options_as<circle::InstanceNormOptions>() const
+{
+ return builtin_options_as_InstanceNormOptions();
+}
+
+struct OperatorBuilder
+{
+ typedef Operator Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_opcode_index(uint32_t opcode_index)
+ {
+ fbb_.AddElement<uint32_t>(Operator::VT_OPCODE_INDEX, opcode_index, 0);
+ }
+ void add_inputs(flatbuffers::Offset<flatbuffers::Vector<int32_t>> inputs)
+ {
+ fbb_.AddOffset(Operator::VT_INPUTS, inputs);
+ }
+ void add_outputs(flatbuffers::Offset<flatbuffers::Vector<int32_t>> outputs)
+ {
+ fbb_.AddOffset(Operator::VT_OUTPUTS, outputs);
+ }
+ void add_builtin_options_type(circle::BuiltinOptions builtin_options_type)
+ {
+ fbb_.AddElement<uint8_t>(Operator::VT_BUILTIN_OPTIONS_TYPE,
+ static_cast<uint8_t>(builtin_options_type), 0);
+ }
+ void add_builtin_options(flatbuffers::Offset<void> builtin_options)
+ {
+ fbb_.AddOffset(Operator::VT_BUILTIN_OPTIONS, builtin_options);
+ }
+ void add_custom_options(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> custom_options)
+ {
+ fbb_.AddOffset(Operator::VT_CUSTOM_OPTIONS, custom_options);
+ }
+ void add_custom_options_format(circle::CustomOptionsFormat custom_options_format)
+ {
+ fbb_.AddElement<int8_t>(Operator::VT_CUSTOM_OPTIONS_FORMAT,
+ static_cast<int8_t>(custom_options_format), 0);
+ }
+ void add_mutating_variable_inputs(
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> mutating_variable_inputs)
+ {
+ fbb_.AddOffset(Operator::VT_MUTATING_VARIABLE_INPUTS, mutating_variable_inputs);
+ }
+ void add_intermediates(flatbuffers::Offset<flatbuffers::Vector<int32_t>> intermediates)
+ {
+ fbb_.AddOffset(Operator::VT_INTERMEDIATES, intermediates);
+ }
+ explicit OperatorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ OperatorBuilder &operator=(const OperatorBuilder &);
+ flatbuffers::Offset<Operator> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Operator>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Operator> CreateOperator(
+ flatbuffers::FlatBufferBuilder &_fbb, uint32_t opcode_index = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> inputs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> outputs = 0,
+ circle::BuiltinOptions builtin_options_type = circle::BuiltinOptions_NONE,
+ flatbuffers::Offset<void> builtin_options = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> custom_options = 0,
+ circle::CustomOptionsFormat custom_options_format = circle::CustomOptionsFormat_FLEXBUFFERS,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> mutating_variable_inputs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> intermediates = 0)
+{
+ OperatorBuilder builder_(_fbb);
+ builder_.add_intermediates(intermediates);
+ builder_.add_mutating_variable_inputs(mutating_variable_inputs);
+ builder_.add_custom_options(custom_options);
+ builder_.add_builtin_options(builtin_options);
+ builder_.add_outputs(outputs);
+ builder_.add_inputs(inputs);
+ builder_.add_opcode_index(opcode_index);
+ builder_.add_custom_options_format(custom_options_format);
+ builder_.add_builtin_options_type(builtin_options_type);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Operator> CreateOperatorDirect(
+ flatbuffers::FlatBufferBuilder &_fbb, uint32_t opcode_index = 0,
+ const std::vector<int32_t> *inputs = nullptr, const std::vector<int32_t> *outputs = nullptr,
+ circle::BuiltinOptions builtin_options_type = circle::BuiltinOptions_NONE,
+ flatbuffers::Offset<void> builtin_options = 0,
+ const std::vector<uint8_t> *custom_options = nullptr,
+ circle::CustomOptionsFormat custom_options_format = circle::CustomOptionsFormat_FLEXBUFFERS,
+ const std::vector<uint8_t> *mutating_variable_inputs = nullptr,
+ const std::vector<int32_t> *intermediates = nullptr)
+{
+ auto inputs__ = inputs ? _fbb.CreateVector<int32_t>(*inputs) : 0;
+ auto outputs__ = outputs ? _fbb.CreateVector<int32_t>(*outputs) : 0;
+ auto custom_options__ = custom_options ? _fbb.CreateVector<uint8_t>(*custom_options) : 0;
+ auto mutating_variable_inputs__ =
+ mutating_variable_inputs ? _fbb.CreateVector<uint8_t>(*mutating_variable_inputs) : 0;
+ auto intermediates__ = intermediates ? _fbb.CreateVector<int32_t>(*intermediates) : 0;
+ return circle::CreateOperator(_fbb, opcode_index, inputs__, outputs__, builtin_options_type,
+ builtin_options, custom_options__, custom_options_format,
+ mutating_variable_inputs__, intermediates__);
+}
+
+struct SubGraph FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef SubGraphBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_TENSORS = 4,
+ VT_INPUTS = 6,
+ VT_OUTPUTS = 8,
+ VT_OPERATORS = 10,
+ VT_NAME = 12,
+ VT_DATA_FORMAT = 14
+ };
+ const flatbuffers::Vector<flatbuffers::Offset<circle::Tensor>> *tensors() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<circle::Tensor>> *>(VT_TENSORS);
+ }
+ const flatbuffers::Vector<int32_t> *inputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_INPUTS);
+ }
+ const flatbuffers::Vector<int32_t> *outputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_OUTPUTS);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<circle::Operator>> *operators() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<circle::Operator>> *>(
+ VT_OPERATORS);
+ }
+ const flatbuffers::String *name() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ circle::DataFormat data_format() const
+ {
+ return static_cast<circle::DataFormat>(GetField<int8_t>(VT_DATA_FORMAT, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TENSORS) &&
+ verifier.VerifyVector(tensors()) && verifier.VerifyVectorOfTables(tensors()) &&
+ VerifyOffset(verifier, VT_INPUTS) && verifier.VerifyVector(inputs()) &&
+ VerifyOffset(verifier, VT_OUTPUTS) && verifier.VerifyVector(outputs()) &&
+ VerifyOffset(verifier, VT_OPERATORS) && verifier.VerifyVector(operators()) &&
+ verifier.VerifyVectorOfTables(operators()) && VerifyOffset(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) && VerifyField<int8_t>(verifier, VT_DATA_FORMAT) &&
+ verifier.EndTable();
+ }
+};
+
+struct SubGraphBuilder
+{
+ typedef SubGraph Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void
+ add_tensors(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::Tensor>>> tensors)
+ {
+ fbb_.AddOffset(SubGraph::VT_TENSORS, tensors);
+ }
+ void add_inputs(flatbuffers::Offset<flatbuffers::Vector<int32_t>> inputs)
+ {
+ fbb_.AddOffset(SubGraph::VT_INPUTS, inputs);
+ }
+ void add_outputs(flatbuffers::Offset<flatbuffers::Vector<int32_t>> outputs)
+ {
+ fbb_.AddOffset(SubGraph::VT_OUTPUTS, outputs);
+ }
+ void add_operators(
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::Operator>>> operators)
+ {
+ fbb_.AddOffset(SubGraph::VT_OPERATORS, operators);
+ }
+ void add_name(flatbuffers::Offset<flatbuffers::String> name)
+ {
+ fbb_.AddOffset(SubGraph::VT_NAME, name);
+ }
+ void add_data_format(circle::DataFormat data_format)
+ {
+ fbb_.AddElement<int8_t>(SubGraph::VT_DATA_FORMAT, static_cast<int8_t>(data_format), 0);
+ }
+ explicit SubGraphBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SubGraphBuilder &operator=(const SubGraphBuilder &);
+ flatbuffers::Offset<SubGraph> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SubGraph>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SubGraph> CreateSubGraph(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::Tensor>>> tensors = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> inputs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> outputs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::Operator>>> operators = 0,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ circle::DataFormat data_format = circle::DataFormat_CHANNELS_LAST)
+{
+ SubGraphBuilder builder_(_fbb);
+ builder_.add_name(name);
+ builder_.add_operators(operators);
+ builder_.add_outputs(outputs);
+ builder_.add_inputs(inputs);
+ builder_.add_tensors(tensors);
+ builder_.add_data_format(data_format);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<SubGraph> CreateSubGraphDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<flatbuffers::Offset<circle::Tensor>> *tensors = nullptr,
+ const std::vector<int32_t> *inputs = nullptr, const std::vector<int32_t> *outputs = nullptr,
+ const std::vector<flatbuffers::Offset<circle::Operator>> *operators = nullptr,
+ const char *name = nullptr, circle::DataFormat data_format = circle::DataFormat_CHANNELS_LAST)
+{
+ auto tensors__ = tensors ? _fbb.CreateVector<flatbuffers::Offset<circle::Tensor>>(*tensors) : 0;
+ auto inputs__ = inputs ? _fbb.CreateVector<int32_t>(*inputs) : 0;
+ auto outputs__ = outputs ? _fbb.CreateVector<int32_t>(*outputs) : 0;
+ auto operators__ =
+ operators ? _fbb.CreateVector<flatbuffers::Offset<circle::Operator>>(*operators) : 0;
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ return circle::CreateSubGraph(_fbb, tensors__, inputs__, outputs__, operators__, name__,
+ data_format);
+}
+
+struct Buffer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef BufferBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_DATA = 4
+ };
+ const flatbuffers::Vector<uint8_t> *data() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_DATA);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_DATA) &&
+ verifier.VerifyVector(data()) && verifier.EndTable();
+ }
+};
+
+struct BufferBuilder
+{
+ typedef Buffer Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_data(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> data)
+ {
+ fbb_.AddOffset(Buffer::VT_DATA, data);
+ }
+ explicit BufferBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BufferBuilder &operator=(const BufferBuilder &);
+ flatbuffers::Offset<Buffer> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Buffer>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Buffer>
+CreateBuffer(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> data = 0)
+{
+ BufferBuilder builder_(_fbb);
+ builder_.add_data(data);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Buffer> CreateBufferDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<uint8_t> *data = nullptr)
+{
+ if (data)
+ {
+ _fbb.ForceVectorAlignment(data->size(), sizeof(uint8_t), 16);
+ }
+ auto data__ = data ? _fbb.CreateVector<uint8_t>(*data) : 0;
+ return circle::CreateBuffer(_fbb, data__);
+}
+
+struct Metadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef MetadataBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_NAME = 4,
+ VT_BUFFER = 6
+ };
+ const flatbuffers::String *name() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ uint32_t buffer() const { return GetField<uint32_t>(VT_BUFFER, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) && VerifyField<uint32_t>(verifier, VT_BUFFER) &&
+ verifier.EndTable();
+ }
+};
+
+struct MetadataBuilder
+{
+ typedef Metadata Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name)
+ {
+ fbb_.AddOffset(Metadata::VT_NAME, name);
+ }
+ void add_buffer(uint32_t buffer) { fbb_.AddElement<uint32_t>(Metadata::VT_BUFFER, buffer, 0); }
+ explicit MetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MetadataBuilder &operator=(const MetadataBuilder &);
+ flatbuffers::Offset<Metadata> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Metadata>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Metadata>
+CreateMetadata(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0, uint32_t buffer = 0)
+{
+ MetadataBuilder builder_(_fbb);
+ builder_.add_buffer(buffer);
+ builder_.add_name(name);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Metadata> CreateMetadataDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ uint32_t buffer = 0)
+{
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ return circle::CreateMetadata(_fbb, name__, buffer);
+}
+
+struct Model FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ typedef ModelBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+ {
+ VT_VERSION = 4,
+ VT_OPERATOR_CODES = 6,
+ VT_SUBGRAPHS = 8,
+ VT_DESCRIPTION = 10,
+ VT_BUFFERS = 12,
+ VT_METADATA_BUFFER = 14,
+ VT_METADATA = 16
+ };
+ uint32_t version() const { return GetField<uint32_t>(VT_VERSION, 0); }
+ const flatbuffers::Vector<flatbuffers::Offset<circle::OperatorCode>> *operator_codes() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<circle::OperatorCode>> *>(
+ VT_OPERATOR_CODES);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<circle::SubGraph>> *subgraphs() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<circle::SubGraph>> *>(
+ VT_SUBGRAPHS);
+ }
+ const flatbuffers::String *description() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_DESCRIPTION);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<circle::Buffer>> *buffers() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<circle::Buffer>> *>(VT_BUFFERS);
+ }
+ const flatbuffers::Vector<int32_t> *metadata_buffer() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_METADATA_BUFFER);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<circle::Metadata>> *metadata() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<circle::Metadata>> *>(
+ VT_METADATA);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint32_t>(verifier, VT_VERSION) &&
+ VerifyOffset(verifier, VT_OPERATOR_CODES) && verifier.VerifyVector(operator_codes()) &&
+ verifier.VerifyVectorOfTables(operator_codes()) &&
+ VerifyOffset(verifier, VT_SUBGRAPHS) && verifier.VerifyVector(subgraphs()) &&
+ verifier.VerifyVectorOfTables(subgraphs()) && VerifyOffset(verifier, VT_DESCRIPTION) &&
+ verifier.VerifyString(description()) && VerifyOffset(verifier, VT_BUFFERS) &&
+ verifier.VerifyVector(buffers()) && verifier.VerifyVectorOfTables(buffers()) &&
+ VerifyOffset(verifier, VT_METADATA_BUFFER) && verifier.VerifyVector(metadata_buffer()) &&
+ VerifyOffset(verifier, VT_METADATA) && verifier.VerifyVector(metadata()) &&
+ verifier.VerifyVectorOfTables(metadata()) && verifier.EndTable();
+ }
+};
+
+struct ModelBuilder
+{
+ typedef Model Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_version(uint32_t version) { fbb_.AddElement<uint32_t>(Model::VT_VERSION, version, 0); }
+ void add_operator_codes(
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::OperatorCode>>>
+ operator_codes)
+ {
+ fbb_.AddOffset(Model::VT_OPERATOR_CODES, operator_codes);
+ }
+ void add_subgraphs(
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::SubGraph>>> subgraphs)
+ {
+ fbb_.AddOffset(Model::VT_SUBGRAPHS, subgraphs);
+ }
+ void add_description(flatbuffers::Offset<flatbuffers::String> description)
+ {
+ fbb_.AddOffset(Model::VT_DESCRIPTION, description);
+ }
+ void
+ add_buffers(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::Buffer>>> buffers)
+ {
+ fbb_.AddOffset(Model::VT_BUFFERS, buffers);
+ }
+ void add_metadata_buffer(flatbuffers::Offset<flatbuffers::Vector<int32_t>> metadata_buffer)
+ {
+ fbb_.AddOffset(Model::VT_METADATA_BUFFER, metadata_buffer);
+ }
+ void add_metadata(
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::Metadata>>> metadata)
+ {
+ fbb_.AddOffset(Model::VT_METADATA, metadata);
+ }
+ explicit ModelBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ModelBuilder &operator=(const ModelBuilder &);
+ flatbuffers::Offset<Model> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Model>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Model> CreateModel(
+ flatbuffers::FlatBufferBuilder &_fbb, uint32_t version = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::OperatorCode>>>
+ operator_codes = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::SubGraph>>> subgraphs = 0,
+ flatbuffers::Offset<flatbuffers::String> description = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::Buffer>>> buffers = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> metadata_buffer = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::Metadata>>> metadata = 0)
+{
+ ModelBuilder builder_(_fbb);
+ builder_.add_metadata(metadata);
+ builder_.add_metadata_buffer(metadata_buffer);
+ builder_.add_buffers(buffers);
+ builder_.add_description(description);
+ builder_.add_subgraphs(subgraphs);
+ builder_.add_operator_codes(operator_codes);
+ builder_.add_version(version);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Model> CreateModelDirect(
+ flatbuffers::FlatBufferBuilder &_fbb, uint32_t version = 0,
+ const std::vector<flatbuffers::Offset<circle::OperatorCode>> *operator_codes = nullptr,
+ const std::vector<flatbuffers::Offset<circle::SubGraph>> *subgraphs = nullptr,
+ const char *description = nullptr,
+ const std::vector<flatbuffers::Offset<circle::Buffer>> *buffers = nullptr,
+ const std::vector<int32_t> *metadata_buffer = nullptr,
+ const std::vector<flatbuffers::Offset<circle::Metadata>> *metadata = nullptr)
+{
+ auto operator_codes__ =
+ operator_codes ? _fbb.CreateVector<flatbuffers::Offset<circle::OperatorCode>>(*operator_codes)
+ : 0;
+ auto subgraphs__ =
+ subgraphs ? _fbb.CreateVector<flatbuffers::Offset<circle::SubGraph>>(*subgraphs) : 0;
+ auto description__ = description ? _fbb.CreateString(description) : 0;
+ auto buffers__ = buffers ? _fbb.CreateVector<flatbuffers::Offset<circle::Buffer>>(*buffers) : 0;
+ auto metadata_buffer__ = metadata_buffer ? _fbb.CreateVector<int32_t>(*metadata_buffer) : 0;
+ auto metadata__ =
+ metadata ? _fbb.CreateVector<flatbuffers::Offset<circle::Metadata>>(*metadata) : 0;
+ return circle::CreateModel(_fbb, version, operator_codes__, subgraphs__, description__, buffers__,
+ metadata_buffer__, metadata__);
+}
+
+inline bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj,
+ QuantizationDetails type)
+{
+ switch (type)
+ {
+ case QuantizationDetails_NONE:
+ {
+ return true;
+ }
+ case QuantizationDetails_CustomQuantization:
+ {
+ auto ptr = reinterpret_cast<const circle::CustomQuantization *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default:
+ return true;
+ }
+}
+
+inline bool
+VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types)
+{
+ if (!values || !types)
+ return !values && !types;
+ if (values->size() != types->size())
+ return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i)
+ {
+ if (!VerifyQuantizationDetails(verifier, values->Get(i),
+ types->GetEnum<QuantizationDetails>(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj,
+ SparseIndexVector type)
+{
+ switch (type)
+ {
+ case SparseIndexVector_NONE:
+ {
+ return true;
+ }
+ case SparseIndexVector_Int32Vector:
+ {
+ auto ptr = reinterpret_cast<const circle::Int32Vector *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case SparseIndexVector_Uint16Vector:
+ {
+ auto ptr = reinterpret_cast<const circle::Uint16Vector *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case SparseIndexVector_Uint8Vector:
+ {
+ auto ptr = reinterpret_cast<const circle::Uint8Vector *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default:
+ return true;
+ }
+}
+
+inline bool
+VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types)
+{
+ if (!values || !types)
+ return !values && !types;
+ if (values->size() != types->size())
+ return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i)
+ {
+ if (!VerifySparseIndexVector(verifier, values->Get(i), types->GetEnum<SparseIndexVector>(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj,
+ BuiltinOptions type)
+{
+ switch (type)
+ {
+ case BuiltinOptions_NONE:
+ {
+ return true;
+ }
+ case BuiltinOptions_Conv2DOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::Conv2DOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DepthwiseConv2DOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::DepthwiseConv2DOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ConcatEmbeddingsOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ConcatEmbeddingsOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LSHProjectionOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LSHProjectionOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_Pool2DOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::Pool2DOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SVDFOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SVDFOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_RNNOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::RNNOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FullyConnectedOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::FullyConnectedOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SoftmaxOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SoftmaxOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ConcatenationOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ConcatenationOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_AddOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::AddOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_L2NormOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::L2NormOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LocalResponseNormalizationOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LocalResponseNormalizationOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LSTMOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LSTMOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ResizeBilinearOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ResizeBilinearOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_CallOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::CallOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ReshapeOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ReshapeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SkipGramOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SkipGramOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SpaceToDepthOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SpaceToDepthOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_EmbeddingLookupSparseOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::EmbeddingLookupSparseOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MulOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::MulOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_PadOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::PadOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_GatherOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::GatherOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BatchToSpaceNDOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::BatchToSpaceNDOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SpaceToBatchNDOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SpaceToBatchNDOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_TransposeOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::TransposeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ReducerOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ReducerOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SubOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SubOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DivOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::DivOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SqueezeOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SqueezeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SequenceRNNOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SequenceRNNOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_StridedSliceOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::StridedSliceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ExpOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ExpOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_TopKV2Options:
+ {
+ auto ptr = reinterpret_cast<const circle::TopKV2Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SplitOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SplitOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LogSoftmaxOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LogSoftmaxOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_CastOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::CastOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DequantizeOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::DequantizeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MaximumMinimumOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::MaximumMinimumOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ArgMaxOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ArgMaxOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LessOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LessOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_NegOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::NegOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_PadV2Options:
+ {
+ auto ptr = reinterpret_cast<const circle::PadV2Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_GreaterOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::GreaterOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_GreaterEqualOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::GreaterEqualOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LessEqualOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LessEqualOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SelectOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SelectOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SliceOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SliceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_TransposeConvOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::TransposeConvOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SparseToDenseOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SparseToDenseOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_TileOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::TileOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ExpandDimsOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ExpandDimsOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_EqualOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::EqualOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_NotEqualOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::NotEqualOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ShapeOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ShapeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_PowOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::PowOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ArgMinOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ArgMinOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FakeQuantOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::FakeQuantOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_PackOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::PackOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LogicalOrOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LogicalOrOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_OneHotOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::OneHotOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LogicalAndOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LogicalAndOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LogicalNotOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LogicalNotOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_UnpackOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::UnpackOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FloorDivOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::FloorDivOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SquareOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SquareOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ZerosLikeOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ZerosLikeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FillOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::FillOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BidirectionalSequenceLSTMOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::BidirectionalSequenceLSTMOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BidirectionalSequenceRNNOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::BidirectionalSequenceRNNOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_UnidirectionalSequenceLSTMOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::UnidirectionalSequenceLSTMOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FloorModOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::FloorModOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_RangeOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::RangeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ResizeNearestNeighborOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ResizeNearestNeighborOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LeakyReluOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::LeakyReluOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SquaredDifferenceOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SquaredDifferenceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MirrorPadOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::MirrorPadOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_AbsOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::AbsOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SplitVOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SplitVOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_UniqueOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::UniqueOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ReverseV2Options:
+ {
+ auto ptr = reinterpret_cast<const circle::ReverseV2Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_AddNOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::AddNOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_GatherNdOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::GatherNdOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_CosOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::CosOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_WhereOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::WhereOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_RankOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::RankOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ReverseSequenceOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ReverseSequenceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MatrixDiagOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::MatrixDiagOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_QuantizeOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::QuantizeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MatrixSetDiagOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::MatrixSetDiagOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_HardSwishOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::HardSwishOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_IfOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::IfOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_WhileOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::WhileOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DepthToSpaceOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::DepthToSpaceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_NonMaxSuppressionV4Options:
+ {
+ auto ptr = reinterpret_cast<const circle::NonMaxSuppressionV4Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_NonMaxSuppressionV5Options:
+ {
+ auto ptr = reinterpret_cast<const circle::NonMaxSuppressionV5Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ScatterNdOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::ScatterNdOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SelectV2Options:
+ {
+ auto ptr = reinterpret_cast<const circle::SelectV2Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DensifyOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::DensifyOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SegmentSumOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::SegmentSumOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BatchMatMulOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::BatchMatMulOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BCQGatherOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::BCQGatherOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BCQFullyConnectedOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::BCQFullyConnectedOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_InstanceNormOptions:
+ {
+ auto ptr = reinterpret_cast<const circle::InstanceNormOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default:
+ return true;
+ }
+}
+
+inline bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types)
+{
+ if (!values || !types)
+ return !values && !types;
+ if (values->size() != types->size())
+ return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i)
+ {
+ if (!VerifyBuiltinOptions(verifier, values->Get(i), types->GetEnum<BuiltinOptions>(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline const circle::Model *GetModel(const void *buf)
+{
+ return flatbuffers::GetRoot<circle::Model>(buf);
+}
+
+inline const circle::Model *GetSizePrefixedModel(const void *buf)
+{
+ return flatbuffers::GetSizePrefixedRoot<circle::Model>(buf);
+}
+
+inline const char *ModelIdentifier() { return "CIR0"; }
+
+inline bool ModelBufferHasIdentifier(const void *buf)
+{
+ return flatbuffers::BufferHasIdentifier(buf, ModelIdentifier());
+}
+
+inline bool VerifyModelBuffer(flatbuffers::Verifier &verifier)
+{
+ return verifier.VerifyBuffer<circle::Model>(ModelIdentifier());
+}
+
+inline bool VerifySizePrefixedModelBuffer(flatbuffers::Verifier &verifier)
+{
+ return verifier.VerifySizePrefixedBuffer<circle::Model>(ModelIdentifier());
+}
+
+inline const char *ModelExtension() { return "circle"; }
+
+inline void FinishModelBuffer(flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<circle::Model> root)
+{
+ fbb.Finish(root, ModelIdentifier());
+}
+
+inline void FinishSizePrefixedModelBuffer(flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<circle::Model> root)
+{
+ fbb.FinishSizePrefixed(root, ModelIdentifier());
+}
+
+} // namespace circle
+
+#endif // FLATBUFFERS_GENERATED_CIRCLESCHEMA_CIRCLE_H_
diff --git a/runtime/onert/frontend/nnapi/CMakeLists.txt b/runtime/onert/frontend/nnapi/CMakeLists.txt
new file mode 100644
index 000000000..dafd84ccf
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/CMakeLists.txt
@@ -0,0 +1,27 @@
+file(GLOB_RECURSE SOURCES_FRONTEND "*.cc")
+file(GLOB_RECURSE TESTS_FRONTEND "*.test.cc")
+list(REMOVE_ITEM SOURCES_FRONTEND ${TESTS_FRONTEND})
+
+set(LIB_ONERT onert)
+
+add_library(${LIB_ONERT} SHARED ${SOURCES_FRONTEND})
+target_link_libraries(${LIB_ONERT} PUBLIC nnfw-nnapi-header)
+target_link_libraries(${LIB_ONERT} PUBLIC onert_core) # TODO Link PRIVATE onert_core
+target_link_libraries(${LIB_ONERT} PRIVATE nnfw_common)
+target_link_libraries(${LIB_ONERT} PRIVATE nnfw_coverage)
+
+set_target_properties(${LIB_ONERT} PROPERTIES OUTPUT_NAME neuralnetworks)
+
+install(TARGETS ${LIB_ONERT} DESTINATION lib)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+add_executable(test_onert_frontend_nnapi ${TESTS_FRONTEND})
+
+target_link_libraries(test_onert_frontend_nnapi PRIVATE ${LIB_ONERT} dl)
+target_link_libraries(test_onert_frontend_nnapi PRIVATE gtest)
+target_link_libraries(test_onert_frontend_nnapi PRIVATE gtest_main)
+
+install(TARGETS test_onert_frontend_nnapi DESTINATION unittest_standalone)
diff --git a/runtime/onert/frontend/nnapi/compilation.cc b/runtime/onert/frontend/nnapi/compilation.cc
new file mode 100644
index 000000000..871c040ef
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/compilation.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+
+#include <new>
+
+#include "wrapper/ANeuralNetworksModel.h"
+#include "wrapper/ANeuralNetworksCompilation.h"
+#include "util/logging.h"
+
+//
+// NNAPI Implementation
+//
+int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model,
+ ANeuralNetworksCompilation **compilation)
+{
+ if ((model == nullptr) || (compilation == nullptr))
+ {
+ VERBOSE(NNAPI::Compilation) << "create: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (!model->isFinished())
+ {
+ VERBOSE(NNAPI::Compilation) << "create: Model define is not finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ *compilation = new (std::nothrow) ANeuralNetworksCompilation(model);
+ if (*compilation == nullptr)
+ {
+ VERBOSE(NNAPI::Compilation) << "create: ail to create compilation object" << std::endl;
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksCompilation_finish(ANeuralNetworksCompilation *compilation)
+{
+ if (compilation == nullptr)
+ {
+ VERBOSE(NNAPI::Compilation) << "finish: Incorrect null pointer parameter" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (compilation->state() != ::onert::compiler::State::CREATED)
+ {
+ VERBOSE(NNAPI::Compilation) << "finish: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ if (!compilation->finish())
+ {
+ VERBOSE(NNAPI::Compilation) << "finish: Fail to compile" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksCompilation_free(ANeuralNetworksCompilation *compilation)
+{
+ delete compilation;
+}
+
+int ANeuralNetworksCompilation_setPreference(ANeuralNetworksCompilation *compilation,
+ int32_t preference)
+{
+ if (compilation == nullptr)
+ {
+ VERBOSE(NNAPI::Compilation) << "setPreference: Incorrect null pointer parameter" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (compilation->state() != ::onert::compiler::State::CREATED)
+ {
+ VERBOSE(NNAPI::Compilation) << "setPreference: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ const PreferenceCode FIRST_PREFERENCE_CODE = ANEURALNETWORKS_PREFER_LOW_POWER;
+ const PreferenceCode LAST_PREFERENCE_CODE = ANEURALNETWORKS_PREFER_SUSTAINED_SPEED;
+ if ((preference < FIRST_PREFERENCE_CODE) || (preference > LAST_PREFERENCE_CODE))
+ {
+ VERBOSE(NNAPI::Compilation) << "setPreference: Incorrect preference code" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ // NYI: nothing to set
+ return ANEURALNETWORKS_NO_ERROR;
+}
diff --git a/runtime/onert/frontend/nnapi/event.cc b/runtime/onert/frontend/nnapi/event.cc
new file mode 100644
index 000000000..593b74e90
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/event.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+
+#include "wrapper/ANeuralNetworksEvent.h"
+
+int ANeuralNetworksEvent_wait(ANeuralNetworksEvent *event)
+{
+ if (event == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (!event->waitFinish())
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksEvent_free(ANeuralNetworksEvent *event) { delete event; }
diff --git a/runtime/onert/frontend/nnapi/execution.cc b/runtime/onert/frontend/nnapi/execution.cc
new file mode 100644
index 000000000..56ca5ef00
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/execution.cc
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+
+#include <new>
+
+#include "wrapper/ANeuralNetworksCompilation.h"
+#include "wrapper/ANeuralNetworksExecution.h"
+#include "wrapper/ANeuralNetworksMemory.h"
+#include "wrapper/ANeuralNetworksEvent.h"
+#include "wrapper/NNAPIConvert.h"
+#include "util/logging.h"
+
+//
+// NNAPI Implementation
+//
+int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution)
+{
+ if ((compilation == nullptr) || (execution == nullptr))
+ {
+ VERBOSE(NNAPI::Execution) << "create: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ std::shared_ptr<onert::exec::ExecutorMap> executors;
+
+ compilation->publish(executors);
+
+ if (executors == nullptr)
+ {
+ VERBOSE(NNAPI::Execution) << "create: Never compiled yet" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ *execution = new (std::nothrow) ANeuralNetworksExecution{executors};
+ if (*execution == nullptr)
+ {
+ VERBOSE(NNAPI::Execution) << "create: Fail to create execution object" << std::endl;
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+// NOTE Handle optional input
+// Unspecified shape on model build
+// Optional and omitted input on execution: skip input setting (workaround for LSTM)
+// Optional but not omitted input on execution: cannot handle
+// Normal input on execution: cannot handle
+// Fully specified shape on model build
+// Optional input on execution: cannot handle
+// Normal input: handle normally
+int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, const void *buffer,
+ size_t length)
+{
+ // Don't check type
+ // Comment about ANeuralNetworksOperandType in NeuralNetworks.h:
+ // If the input or output is optional and omitted then it need not have a fully specified tensor
+ // operand type
+ if ((execution == nullptr) || ((buffer == nullptr) && (length != 0)))
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if ((buffer != nullptr) && (length == 0))
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Zero length input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ const auto operand_index = execution->getInputOperandIndex(index);
+ if (!operand_index.valid())
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Invalid input index" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ // Omitted optional input
+ // LSTM operation's some inputs can be optional input
+ // Transpose operation's permutation input can be optional input
+ if ((buffer == nullptr) && (length == 0))
+ {
+ uint32_t dims[1] = {0};
+ ANeuralNetworksOperandType compared_shape;
+ compared_shape.dimensionCount = 1;
+ compared_shape.dimensions = dims;
+ if (execution->hasUnspecifiedDims(operand_index))
+ {
+ return ANEURALNETWORKS_NO_ERROR;
+ }
+ else if (type == nullptr && execution->IsOptionalInput(operand_index))
+ {
+ if (!execution->setOptionalInput(index, type, buffer, length))
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Fail to set optional input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ return ANEURALNETWORKS_NO_ERROR;
+ }
+ // TODO Changes the condition to check zero sized
+ else if (execution->compareShape(&compared_shape, operand_index))
+ {
+ if (!execution->setInput(index, type, buffer, length))
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Fail to set input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ return ANEURALNETWORKS_NO_ERROR;
+ }
+ else
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Cannot handle fully-specified shape on model build "
+ "but omitted input on execution"
+ << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ if (type != nullptr)
+ {
+ if (!execution->compareDataType(type, operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Data type mismatch" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!execution->compareShape(type, operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Shape mismatch" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (NNAPIConvert::calculateSizeFromType(type) != length)
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Invalid length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+ else
+ {
+ if (execution->hasUnspecifiedDims(operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Unspecified dimension value" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (execution->getOperandSize(operand_index) != length)
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Invalid length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ if (!execution->setInput(index, type, buffer, length))
+ {
+ VERBOSE(NNAPI::Execution) << "setInput: Fail to set input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, void *buffer,
+ size_t length)
+{
+ // Don't check type
+ // Comment about ANeuralNetworksOperandType in NeuralNetworks.h:
+ // If the input or output is optional and omitted then it need not have a fully specified tensor
+ // operand type
+ if ((execution == nullptr) || ((buffer == nullptr) && (length != 0)))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if ((buffer != nullptr) && (length == 0))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Zero length output" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ // Handle optional output
+ if (buffer == nullptr)
+ {
+ return ANEURALNETWORKS_NO_ERROR;
+ }
+
+ const auto operand_index = execution->getOutputOperandIndex(index);
+ if (!operand_index.valid())
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Invalid output index" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (type != nullptr)
+ {
+ if (!execution->compareDataType(type, operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Data type mismatch" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!execution->compareShape(type, operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Shape mismatch" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (NNAPIConvert::calculateSizeFromType(type) != length)
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Invalid length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+ else
+ {
+ if (execution->hasUnspecifiedDims(operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Unspecified dimension value" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (execution->getOperandSize(operand_index) != length)
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Invalid length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ if (!execution->setOutput(index, type, buffer, length))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutput: Fail to set output" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution,
+ ANeuralNetworksEvent **event)
+{
+ if ((execution == nullptr) || (event == nullptr))
+ {
+ VERBOSE(NNAPI::Execution) << "startCompute: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ // TODO: Handle event
+ auto instance = execution->instance();
+ *event = new (std::nothrow) ANeuralNetworksEvent{instance};
+ if (*event == nullptr)
+ {
+ VERBOSE(NNAPI::Execution) << "startCompute: Fail to create event" << std::endl;
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+
+ if (!execution->startExecute())
+ {
+ VERBOSE(NNAPI::Execution) << "startCompute: Fail to start execution" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_compute(ANeuralNetworksExecution *execution)
+{
+ if (execution == nullptr)
+ {
+ VERBOSE(NNAPI::Execution) << "Compute: Incorrect null pointer parameter" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (!execution->execute())
+ {
+ VERBOSE(NNAPI::Execution) << "Compute: Fail to execution" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksExecution_free(ANeuralNetworksExecution *execution) { delete execution; }
+
+int ANeuralNetworksExecution_setInputFromMemory(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length)
+{
+ if ((execution == nullptr) || (memory == nullptr))
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Incorrect null pointer parameter(s)"
+ << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (length == 0)
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Zero length input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ const auto operand_index = execution->getInputOperandIndex(index);
+ if (!operand_index.valid())
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Invalid input index" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (type != nullptr)
+ {
+ if (!execution->compareDataType(type, operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Data type mismatch" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!execution->compareShape(type, operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Shape mismatch" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (NNAPIConvert::calculateSizeFromType(type) != length)
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Invalid length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+ else
+ {
+ if (execution->hasUnspecifiedDims(operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Unspecified dimension value" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (execution->getOperandSize(operand_index) != length)
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Invalid length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ if (!memory->vaildAccess(offset, length))
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Invalid memory access" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!execution->setInput(index, type, reinterpret_cast<const void *>(memory->base() + offset),
+ length))
+ {
+ VERBOSE(NNAPI::Execution) << "setInputFromMemory: Fail to set input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_setOutputFromMemory(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length)
+{
+ if ((execution == nullptr) || (memory == nullptr))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Incorrect null pointer parameter(s)"
+ << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (length == 0)
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Zero length input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ const auto operand_index = execution->getOutputOperandIndex(index);
+ if (!operand_index.valid())
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Invalid output index" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (type != nullptr)
+ {
+ if (!execution->compareDataType(type, operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Data type mismatch" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!execution->compareShape(type, operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Shape mismatch" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (NNAPIConvert::calculateSizeFromType(type) != length)
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Invalid length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+ else
+ {
+ if (execution->hasUnspecifiedDims(operand_index))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Unspecified dimension value" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (execution->getOperandSize(operand_index) != length)
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Invalid length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ if (!memory->vaildAccess(offset, length))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Invalid memory access" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!execution->setOutput(index, type, reinterpret_cast<void *>(memory->base() + offset), length))
+ {
+ VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Fail to set input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_getOutputOperandRank(ANeuralNetworksExecution *execution,
+ int32_t index, uint32_t *rank)
+{
+ if ((execution == nullptr) || (rank == nullptr))
+ {
+ VERBOSE(NNAPI::Execution) << "getOutputOperandRank: Incorrect null pointer parameter(s)"
+ << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const auto operand_index = execution->getOutputOperandIndex(index);
+ if (!operand_index.valid())
+ {
+ VERBOSE(NNAPI::Execution) << "getOutputOperandRank: Invalid output index" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!execution->getOutputOperandRank(index, rank))
+ {
+ VERBOSE(NNAPI::Execution) << "getOutputOperandRank: Fail to get rank" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_getOutputOperandDimensions(ANeuralNetworksExecution *execution,
+ int32_t index, uint32_t *dimensions)
+{
+ if ((execution == nullptr) || (dimensions == nullptr))
+ {
+ VERBOSE(NNAPI::Execution) << "getOutputOperandDimensions: Incorrect null pointer parameter(s)"
+ << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const auto operand_index = execution->getOutputOperandIndex(index);
+ if (!operand_index.valid())
+ {
+ VERBOSE(NNAPI::Execution) << "getOutputOperandDimensions: Invalid output index" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!execution->getOutputOperandDimensions(index, dimensions))
+ {
+ VERBOSE(NNAPI::Execution) << "getOutputOperandDimensions: Fail to get rank" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
diff --git a/runtime/onert/frontend/nnapi/memory.cc b/runtime/onert/frontend/nnapi/memory.cc
new file mode 100644
index 000000000..6e568a926
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/memory.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+#include <sys/mman.h>
+#include <new>
+#include <memory>
+
+#include <memory>
+#include "wrapper/ANeuralNetworksMemory.h"
+
+int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset,
+ ANeuralNetworksMemory **memory)
+{
+ if (memory == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ *memory = new (std::nothrow) ANeuralNetworksMemory{size, protect, fd, offset};
+ if (*memory == nullptr)
+ {
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksMemory_free(ANeuralNetworksMemory *memory) { delete memory; }
diff --git a/runtime/onert/frontend/nnapi/model.cc b/runtime/onert/frontend/nnapi/model.cc
new file mode 100644
index 000000000..8c7bd1789
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/model.cc
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+#include <NeuralNetworksEx.h>
+
+#include <new>
+
+#include "wrapper/ANeuralNetworksModel.h"
+#include "wrapper/ANeuralNetworksMemory.h"
+#include "util/logging.h"
+
+int ANeuralNetworksModel_create(ANeuralNetworksModel **model)
+{
+ if (model == nullptr)
+ {
+ VERBOSE(NNAPI::Model) << "create: Incorrect null pointer parameter" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ *model = new (std::nothrow) ANeuralNetworksModel{};
+ if (*model == nullptr)
+ {
+ VERBOSE(NNAPI::Model) << "create: Fail to create model object" << std::endl;
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksModel_free(ANeuralNetworksModel *model) { delete model; }
+
+int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model,
+ const ANeuralNetworksOperandType *type)
+{
+ if ((model == nullptr) || (type == nullptr))
+ {
+ VERBOSE(NNAPI::Model) << "addOperand: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ VERBOSE(NNAPI::Model) << "addOperand: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ // scale and zeroPoint should be zero for scalars and non-fixed point tensors
+ // Quantized:
+ // scale: a 32 bit floating point value greater than zero
+ // zeroPoint: a 32 bit integer, in range [0, 255]
+ if (type->type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM)
+ {
+ if (!(type->scale > 0.0f))
+ {
+ VERBOSE(NNAPI::Model) << "addOperand: Incorrect scale value for quantization" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if ((type->zeroPoint < 0) || (type->zeroPoint > 255))
+ {
+ VERBOSE(NNAPI::Model) << "addOperand: Incorrect zeroPoint value for quantization"
+ << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+ // NOTE Validation of scale and zeroPoint would be skipped for a while.
+ // We do not know whether scalar type can have scale and zeroPoint.
+ // To pass ValidationTest and GeneratedTest, this validation code
+ // would not be implemented until we can define this issue clearly.
+ //
+ // scale and zeroPoint should be zero for scalars and non-fixed point tensors
+ // else if ((type->scale != 0.0f) || (type->zeroPoint != 0))
+ // {
+ // return ANEURALNETWORKS_BAD_DATA;
+ // }
+
+ // dimensionCount should be zero for scalars
+ if ((type->dimensionCount != 0) &&
+ ((type->type == ANEURALNETWORKS_FLOAT32) || (type->type == ANEURALNETWORKS_INT32) ||
+ (type->type == ANEURALNETWORKS_UINT32)))
+ {
+ VERBOSE(NNAPI::Model) << "addOperand: Incorrect data type" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!model->addOperand(type))
+ {
+ VERBOSE(NNAPI::Model) << "addOperand: Fail to add operand" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index,
+ const void *buffer, size_t length)
+{
+ const bool optional_operand = ((buffer == nullptr) && (length == 0));
+
+ if ((model == nullptr) || ((buffer == nullptr) && (length != 0)))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValue: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValue: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ // Negative index value is not allowed
+ if (index < 0)
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValue: Invalid index value (negative)" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ // NOTE OperandIndex uses uint32_t as its underlying type as various NNAPI
+ // functions such as ANeuralNetworksModel_addOperation use uint32_t to represent operand
+ // index
+ // ANeuralNetworksModel_setOperandValue, however, uses int32_t to represent operand index.
+ //
+ // Below, static_cast<uint32_t>(...) is introduced to eliminate compiler warning.
+ uint32_t ind = static_cast<uint32_t>(index);
+
+ if (!model->isExistOperand(ind))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValue: Invalid index value (not exist)" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!optional_operand && (model->operandSize(ind) != length))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValue: Invalid data length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (model->isUsageSet(ind))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValue: Already set operand" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ // NNAPI spec in NeuralNetworks.h
+ // For values of length greater than ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES,
+ // the application is responsible for not changing the content of this region
+ // until all executions using this model have completed
+ bool copy_value = false;
+ if (length <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES)
+ {
+ copy_value = true;
+ }
+
+ if (!model->setOperandValue(ind, buffer, length, optional_operand, copy_value))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValue: Fail to set operand value" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model, int32_t index,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ if ((model == nullptr) || (memory == nullptr))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Incorrect null pointer parameter(s)"
+ << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ // Negative index value is not allowed
+ if (index < 0)
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid index value (negative)"
+ << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ // NOTE OperandIndex uses uint32_t as its underlying type as various NNAPI
+ // functions such as ANeuralNetworksModel_addOperation use uint32_t to represent operand
+ // index
+ // ANeuralNetworksModel_setOperandValue, however, uses int32_t to represent operand index.
+ //
+ // Below, static_cast<uint32_t>(...) is introduced to eliminate compiler warning.
+ uint32_t ind = static_cast<uint32_t>(index);
+
+ if (!model->isExistOperand(ind))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid index value (not exist)"
+ << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if ((model->operandSize(ind) != length) || (memory->size() < (offset + length)))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid data length" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (model->isUsageSet(ind))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Already set operand" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!model->setOperandValue(ind, memory->base() + offset, length))
+ {
+ VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Fail to set operand value" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationType type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr))
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ const ANeuralNetworksOperationType FIRST_OPERATION = ANEURALNETWORKS_ADD;
+ const ANeuralNetworksOperationType LAST_OPERATION = ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR;
+ if ((type < FIRST_OPERATION) || (type > LAST_OPERATION))
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ for (uint32_t i = 0; i < outputCount; i++)
+ {
+ if (model->isUsageSet(outputs[i]))
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Already set output operand" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ if (!model->addOperation(type, inputCount, inputs, outputCount, outputs))
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Fail to add operation" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationTypeEx type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr))
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Incorrect null pointer parameter(s)" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ const ANeuralNetworksOperationTypeEx FIRST_OPERATION = ANEURALNETWORKS_CAST_EX;
+ const ANeuralNetworksOperationTypeEx LAST_OPERATION = ANEURALNETWORKS_SPLIT_V_EX;
+ if ((type < FIRST_OPERATION) || (type > LAST_OPERATION))
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Invalid operation type" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ for (uint32_t i = 0; i < outputCount; i++)
+ {
+ if (model->isUsageSet(outputs[i]))
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Already set output operand" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ if (!model->addOperationEx(type, inputCount, inputs, outputCount, outputs))
+ {
+ VERBOSE(NNAPI::Model) << "addOperation: Fail to add operation" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr))
+ {
+ VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Incorrect null pointer parameter(s)"
+ << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ for (uint32_t n = 0; n < inputCount; ++n)
+ {
+ uint32_t ind = inputs[n];
+ if (model->isUsageSet(ind))
+ {
+ VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Already set input operand" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!model->addModelInput(ind))
+ {
+ VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Fail to add input" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ for (uint32_t n = 0; n < outputCount; ++n)
+ {
+ uint32_t ind = outputs[n];
+
+ if (!model->isOperationOutput(ind))
+ {
+ VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Need to set output operand" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (!model->addModelOutput(ind))
+ {
+ VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Fail to add output" << std::endl;
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_finish(ANeuralNetworksModel *model)
+{
+ if (model == nullptr)
+ {
+ VERBOSE(NNAPI::Model) << "finish: Incorrect null pointer parameter" << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ VERBOSE(NNAPI::Model) << "finish: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ if (!model->finish())
+ {
+ VERBOSE(NNAPI::Model) << "finish: Fail to generate internal graph" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_relaxComputationFloat32toFloat16(ANeuralNetworksModel *model, bool allow)
+{
+ if (model == nullptr)
+ {
+ VERBOSE(NNAPI::Model) << "relaxComputationFloat32toFloat16: Incorrect null pointer parameter"
+ << std::endl;
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ VERBOSE(NNAPI::Model) << "relaxComputationFloat32toFloat16: Already finished" << std::endl;
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ model->allowFloat32toFloat16(allow);
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc
new file mode 100644
index 000000000..81cd38f4f
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ANeuralNetworksCompilation.h"
+
+#include "util/logging.h"
+
+// TODO Support multiple subgraphs
+ANeuralNetworksCompilation::ANeuralNetworksCompilation(const ANeuralNetworksModel *model) noexcept
+ : _subgraphs{model->getSubGraphs()}, _compiler{new onert::compiler::Compiler{_subgraphs}}
+{
+ if (model->allowedToFp16())
+ {
+ _compiler->enableToFp16();
+ }
+}
+
+bool ANeuralNetworksCompilation::finish() noexcept
+{
+ try
+ {
+ _executors = _compiler->compile();
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h
new file mode 100644
index 000000000..5f0650b9a
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __COMPILATION_H__
+#define __COMPILATION_H__
+
+#include "ANeuralNetworksModel.h"
+
+#include "compiler/Compiler.h"
+#include "ir/Graph.h"
+#include "ir/Subgraphs.h"
+#include "exec/IExecutor.h"
+
+struct ANeuralNetworksCompilation
+{
+public:
+ ANeuralNetworksCompilation(const ANeuralNetworksModel *model) noexcept;
+
+public:
+ bool finish() noexcept;
+
+ onert::compiler::State state(void) noexcept { return _compiler->state(); }
+ void publish(std::shared_ptr<onert::exec::ExecutorMap> &executors) noexcept
+ {
+ executors = _executors;
+ }
+
+private:
+ std::shared_ptr<onert::ir::Subgraphs> _subgraphs;
+ std::shared_ptr<onert::compiler::Compiler> _compiler;
+ std::shared_ptr<onert::exec::ExecutorMap> _executors;
+};
+
+#endif
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc
new file mode 100644
index 000000000..2bea729be
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ANeuralNetworksEvent.h"
+
+#include "exec/Execution.h"
+#include "util/logging.h"
+
+ANeuralNetworksEvent::ANeuralNetworksEvent(const std::shared_ptr<onert::exec::Execution> &execution)
+ : _execution{execution}
+{
+ // DO NOTHING
+}
+
+bool ANeuralNetworksEvent::waitFinish(void) noexcept
+{
+ try
+ {
+ _execution->waitFinish();
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.h
new file mode 100644
index 000000000..7b462d3d6
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EVENT_H__
+#define __EVENT_H__
+
+#include <NeuralNetworks.h>
+
+#include <memory>
+
+namespace onert
+{
+namespace exec
+{
+class Execution;
+} // namespace exec
+} // namespace onert
+
+struct ANeuralNetworksEvent
+{
+public:
+ ANeuralNetworksEvent(const std::shared_ptr<onert::exec::Execution> &execution);
+
+public:
+ bool waitFinish(void) noexcept;
+
+private:
+ const std::shared_ptr<onert::exec::Execution> _execution;
+};
+
+#endif
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc
new file mode 100644
index 000000000..6114b74b0
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ANeuralNetworksExecution.h"
+#include "NNAPIConvert.h"
+#include "util/logging.h"
+
+const onert::ir::OperandIndex ANeuralNetworksExecution::getInputOperandIndex(int32_t index) noexcept
+{
+ if (index < 0)
+ {
+ // Negative index: return invalid index
+ return onert::ir::OperandIndex{};
+ }
+
+ uint32_t cast_index = static_cast<uint32_t>(index);
+ if (cast_index >= _execution->primary_subgraph().getInputs().size())
+ {
+ // Return invalid index
+ return onert::ir::OperandIndex{};
+ }
+
+ onert::ir::IOIndex input_index{cast_index};
+ const auto operand_index = _execution->primary_subgraph().getInputs().at(input_index);
+ return operand_index;
+}
+
+const onert::ir::OperandIndex
+ANeuralNetworksExecution::getOutputOperandIndex(int32_t index) noexcept
+{
+ if (index < 0)
+ {
+ // Negative index: return invalid index
+ return onert::ir::OperandIndex{};
+ }
+
+ uint32_t cast_index = static_cast<uint32_t>(index);
+ if (cast_index >= _execution->primary_subgraph().getOutputs().size())
+ {
+ // Return invalid index
+ return onert::ir::OperandIndex{};
+ }
+
+ onert::ir::IOIndex output_index{cast_index};
+ const auto operand_index = _execution->primary_subgraph().getOutputs().at(output_index);
+ return operand_index;
+}
+
+bool ANeuralNetworksExecution::compareDataType(const ANeuralNetworksOperandType *type,
+ const onert::ir::OperandIndex index) noexcept
+{
+ try
+ {
+ const auto operand_type = _execution->primary_subgraph().operands().at(index).typeInfo();
+ const auto typeInfo = NNAPIConvert::getTypeInfo(type);
+
+ if (operand_type != typeInfo)
+ {
+ // Data type mismatch
+ return false;
+ }
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksExecution::compareShape(const ANeuralNetworksOperandType *type,
+ const onert::ir::OperandIndex index) noexcept
+{
+ // Passed shape should be specified
+ if (hasUnspecifiedDims(index))
+ {
+ return false;
+ }
+
+ const auto &operand_shape = _execution->primary_subgraph().operands().at(index).shape();
+ const auto &shape_from_type = NNAPIConvert::getShape(type);
+
+ return operand_shape == shape_from_type;
+}
+
+bool ANeuralNetworksExecution::IsOptionalInput(const onert::ir::OperandIndex index) noexcept
+{
+ const auto &operand_shape = _execution->primary_subgraph().operands().at(index).shape();
+ for (int32_t i = 0; i < operand_shape.rank(); ++i)
+ {
+ if (operand_shape.dim(i) != 0)
+ return false;
+ }
+ return true;
+}
+
+bool ANeuralNetworksExecution::hasUnspecifiedDims(const onert::ir::OperandIndex index) noexcept
+{
+ const auto operand_shape = _execution->primary_subgraph().operands().at(index).shape();
+
+ return operand_shape.hasUnspecifiedDims();
+}
+
+size_t ANeuralNetworksExecution::getOperandSize(const onert::ir::OperandIndex index) noexcept
+{
+ try
+ {
+ return _execution->primary_subgraph().operands().at(index).operandSize();
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return 0;
+ }
+}
+
+bool ANeuralNetworksExecution::setInput(uint32_t index, const ANeuralNetworksOperandType *type,
+ const void *buffer, size_t length) noexcept
+{
+ try
+ {
+ onert::ir::IOIndex input_index{index};
+ const auto operand_index = getInputOperandIndex(index);
+
+ const auto type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo();
+ const auto shape = (type != nullptr)
+ ? NNAPIConvert::getShape(type)
+ : _execution->primary_subgraph().operands().at(operand_index).shape();
+
+ // NOTE The nnapi does not provide setting io_layout and not support changing layout. In other
+ // words, we can assume that io_layout from nnapi always is the same as layout of the used
+ // model.
+ // TODO Set layout of model
+ _execution->setInput(input_index, type_info, shape, buffer, length, onert::ir::Layout::NHWC);
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksExecution::setOptionalInput(uint32_t index,
+ const ANeuralNetworksOperandType *type,
+ const void *buffer, size_t length) noexcept
+{
+ assert(type == nullptr);
+ assert(buffer == nullptr);
+ assert(length == 0);
+ try
+ {
+ onert::ir::IOIndex input_index{index};
+ const auto operand_index = getInputOperandIndex(index);
+
+ const auto type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo();
+ const auto shape = (type != nullptr)
+ ? NNAPIConvert::getShape(type)
+ : _execution->primary_subgraph().operands().at(operand_index).shape();
+
+ // ANeuralNetworksExecution::setInput() uses only shape information
+ ANeuralNetworksOperandType optional_input_type;
+ optional_input_type.dimensionCount = shape.rank();
+ std::vector<uint32_t> dims(optional_input_type.dimensionCount);
+ for (uint32_t i = 0; i < optional_input_type.dimensionCount; ++i)
+ {
+ dims.at(i) = shape.dim(i);
+ }
+ optional_input_type.dimensions = dims.data();
+
+ return setInput(index, &optional_input_type, buffer, length);
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksExecution::setOutput(uint32_t index, const ANeuralNetworksOperandType *type,
+ void *buffer, size_t length) noexcept
+{
+ try
+ {
+ onert::ir::IOIndex output_index{index};
+ const auto operand_index = getOutputOperandIndex(index);
+
+ const auto type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo();
+ const auto shape = (type != nullptr)
+ ? NNAPIConvert::getShape(type)
+ : _execution->primary_subgraph().operands().at(operand_index).shape();
+
+ // NOTE The nnapi does not provide setting io_layout and not support changing layout. In other
+ // words, we can assume that io_layout from nnapi always is the same as layout of the used
+ // model.
+ // TODO Set layout of model
+ _execution->setOutput(output_index, type_info, shape, buffer, length, onert::ir::Layout::NHWC);
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksExecution::startExecute(void) noexcept
+{
+ try
+ {
+ _execution->startExecute();
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksExecution::execute(void) noexcept
+{
+ try
+ {
+ _execution->execute();
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+const std::shared_ptr<onert::exec::Execution> ANeuralNetworksExecution::instance(void) noexcept
+{
+ return _execution;
+}
+
+bool ANeuralNetworksExecution::getOutputOperandRank(uint32_t index, uint32_t *rank) noexcept
+{
+ try
+ {
+ onert::ir::IOIndex output_index{index};
+
+ // Check execution is finished
+ if (!_execution->isFinished())
+ {
+ return false;
+ }
+
+ const auto shape = _execution->getOutputShape(output_index);
+ if (shape.hasUnspecifiedDims())
+ {
+ throw std::runtime_error{"Internal error: Output tensor has unspecified dims"};
+ }
+
+ *rank = shape.rank();
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksExecution::getOutputOperandDimensions(uint32_t index, uint32_t *dimensions)
+{
+ try
+ {
+ onert::ir::IOIndex output_index{index};
+
+ // Check execution is finished
+ if (!_execution->isFinished())
+ {
+ return false;
+ }
+
+ const auto shape = _execution->getOutputShape(output_index);
+ if (shape.hasUnspecifiedDims())
+ {
+ throw std::runtime_error{"Internal error: Output tensor has unspecified dims"};
+ }
+
+ for (int i = 0; i < shape.rank(); i++)
+ {
+ auto dim = shape.dim(i);
+
+ if (dim <= 0)
+ {
+ throw std::runtime_error{"Invalid dimension value"};
+ }
+
+ dimensions[i] = static_cast<uint32_t>(dim);
+ }
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h
new file mode 100644
index 000000000..1f4b868f6
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EXECUTION_H__
+#define __EXECUTION_H__
+
+#include <NeuralNetworks.h>
+
+#include <memory>
+
+#include "exec/Execution.h"
+
+struct ANeuralNetworksExecution
+{
+public:
+ ANeuralNetworksExecution(const std::shared_ptr<onert::exec::ExecutorMap> &executors)
+ : _execution{std::make_shared<onert::exec::Execution>(executors)}
+ {
+ // DO NOTHING
+ }
+
+public:
+ bool setInput(uint32_t index, const ANeuralNetworksOperandType *type, const void *buffer,
+ size_t length) noexcept;
+ bool setOptionalInput(uint32_t index, const ANeuralNetworksOperandType *type, const void *buffer,
+ size_t length) noexcept;
+ bool setOutput(uint32_t index, const ANeuralNetworksOperandType *type, void *buffer,
+ size_t length) noexcept;
+ bool startExecute(void) noexcept;
+ bool execute(void) noexcept;
+
+ const onert::ir::OperandIndex getInputOperandIndex(int32_t index) noexcept;
+ const onert::ir::OperandIndex getOutputOperandIndex(int32_t index) noexcept;
+ bool compareDataType(const ANeuralNetworksOperandType *type,
+ const onert::ir::OperandIndex index) noexcept;
+ bool compareShape(const ANeuralNetworksOperandType *type,
+ const onert::ir::OperandIndex index) noexcept;
+ bool IsOptionalInput(const onert::ir::OperandIndex index) noexcept;
+ bool hasUnspecifiedDims(const onert::ir::OperandIndex index) noexcept;
+ size_t getOperandSize(const onert::ir::OperandIndex index) noexcept;
+ const std::shared_ptr<onert::exec::Execution> instance(void) noexcept;
+
+ /**
+ * @brief Get output operand's rank
+ * @param[in] index Output index
+ * @param[out] rank Output operand's rank
+ * @return @c true if success to get rank, otherwise @c false
+ */
+ bool getOutputOperandRank(uint32_t index, uint32_t *rank) noexcept;
+ /**
+ * @brief Get dimensions of the output operand
+ * @param[in] index Output index
+ * @param[out] dimensions Output operand's dimensions
+ * @return @c true if success to get rank, otherwise @c false
+ * @note This must be called after execution is finished to get resolved output shape
+ * unspecified in model
+ */
+ bool getOutputOperandDimensions(uint32_t index, uint32_t *dimensions);
+
+private:
+ std::shared_ptr<onert::exec::Execution> _execution;
+};
+
+#endif
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.cc
new file mode 100644
index 000000000..9cc100585
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+#include <sys/mman.h>
+
+#include "ANeuralNetworksMemory.h"
+
+//
+// ANeuralNetworksMemory
+//
+ANeuralNetworksMemory::ANeuralNetworksMemory(size_t size, int protect, int fd, size_t offset)
+{
+ _base = reinterpret_cast<uint8_t *>(mmap(nullptr, size, protect, MAP_PRIVATE, fd, offset));
+ _size = size;
+}
+
+ANeuralNetworksMemory::~ANeuralNetworksMemory() { munmap(reinterpret_cast<void *>(_base), _size); }
+
+bool ANeuralNetworksMemory::vaildAccess(size_t offset, size_t length) const
+{
+ if ((offset >= _size) || (length > _size))
+ {
+ return false;
+ }
+
+ if ((offset + length) >= _size)
+ {
+ return false;
+ }
+
+ return true;
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.h
new file mode 100644
index 000000000..48a1bc5fc
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEMORY_H__
+#define __MEMORY_H__
+
+#include <cstdint>
+
+struct ANeuralNetworksMemory
+{
+public:
+ ANeuralNetworksMemory(size_t size, int protect, int fd, size_t offset);
+ ~ANeuralNetworksMemory();
+
+public:
+ size_t size(void) const { return _size; }
+ uint8_t *base(void) { return _base; }
+ uint8_t *base(void) const { return _base; }
+ bool vaildAccess(size_t offset, size_t length) const;
+
+private:
+ size_t _size;
+ uint8_t *_base;
+};
+
+#endif // __MEMORY_H__
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc
new file mode 100644
index 000000000..97b820aea
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ANeuralNetworksModel.h"
+#include "OperationFactory.h"
+#include "NNAPIConvert.h"
+
+#include "ir/Operations.Include.h"
+#include "util/logging.h"
+
+#include <memory>
+
+//
+// ANeuralNetworksModel
+//
+ANeuralNetworksModel::ANeuralNetworksModel() noexcept
+ : _optional_operands{}, _operand_usages{}, _allowFloat32toFloat16{false}
+{
+ _graph = std::make_shared<onert::ir::Graph>();
+}
+
+bool ANeuralNetworksModel::addOperand(const ANeuralNetworksOperandType *type) noexcept
+{
+ try
+ {
+ const auto shape = NNAPIConvert::getShape(type);
+ const auto typeInfo = NNAPIConvert::getTypeInfo(type);
+ _graph->addOperand(shape, typeInfo);
+ _operand_usages.emplace_back(OperandUsage::NOT_DEFINED);
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksModel::setOperandValue(uint32_t index, const void *buffer, size_t length,
+ bool optional, bool copy) noexcept
+{
+ const onert::ir::OperandIndex ind{index};
+
+ try
+ {
+ _operand_usages[index] = OperandUsage::CONSTANT;
+
+ // Remain operands.at(ind).data()->base() as nullptr for optional operand
+ // This will be filled when model finished
+ if (optional)
+ {
+ setOptionalOperand(ind);
+ }
+
+ using onert::ir::CachedData;
+ using onert::ir::ExternalData;
+ if (copy)
+ {
+ _graph->operands().at(ind).data(
+ std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length));
+ }
+ else
+ {
+ _graph->operands().at(ind).data(
+ std::make_unique<ExternalData>(reinterpret_cast<const uint8_t *>(buffer), length));
+ }
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksModel::addOperation(ANeuralNetworksOperationType type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs) noexcept
+{
+ try
+ {
+ for (uint32_t i = 0; i < outputCount; i++)
+ {
+ _operand_usages[outputs[i]] = OperandUsage::OPERATION_OUTPUT;
+ }
+
+ auto &factory = OperationFactory::get();
+ OperationFactory::Param param{inputCount, inputs, outputCount, outputs};
+
+ auto node = factory.create(type, param, _graph->operands());
+ _graph->addOperation(std::unique_ptr<onert::ir::Operation>{node});
+
+ // TODO Move these codes to delegate.cpp
+ if (type == ANEURALNETWORKS_FULLY_CONNECTED)
+ {
+ const auto &input_operand =
+ _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::INPUT));
+ auto &weights_operand =
+ _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::WEIGHT));
+ if (input_operand.typeInfo().type() == onert::ir::DataType::FLOAT32 &&
+ weights_operand.typeInfo().type() == onert::ir::DataType::QUANT_UINT8_ASYMM)
+ {
+ weights_operand.type(onert::ir::DataType::QUANT_INT8_SYMM);
+ }
+ }
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksModel::addOperationEx(ANeuralNetworksOperationTypeEx type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs) noexcept
+{
+ try
+ {
+ for (uint32_t i = 0; i < outputCount; i++)
+ {
+ _operand_usages[outputs[i]] = OperandUsage::OPERATION_OUTPUT;
+ }
+
+ auto &factory = OperationFactory::get();
+ OperationFactory::Param param{inputCount, inputs, outputCount, outputs};
+
+ auto node = factory.create(type, param, _graph->operands());
+ _graph->addOperation(std::unique_ptr<onert::ir::Operation>{node});
+ }
+ catch (const std::exception &e)
+ {
+ return false;
+ }
+ return true;
+}
+
+bool ANeuralNetworksModel::addModelInput(uint32_t index) noexcept
+{
+ try
+ {
+ _operand_usages[index] = OperandUsage::MODEL_INPUT;
+
+ const onert::ir::OperandIndex ind{index};
+ _graph->addInput(ind);
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+bool ANeuralNetworksModel::addModelOutput(uint32_t index) noexcept
+{
+ try
+ {
+ const onert::ir::OperandIndex ind{index};
+
+ // Duplicated output is not allowed
+ if (_graph->getOutputs().contains(ind))
+ {
+ return false;
+ }
+
+ _graph->addOutput(ind);
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << std::endl;
+
+ return false;
+ }
+
+ return true;
+}
+
+void ANeuralNetworksModel::allowFloat32toFloat16(bool allow) noexcept
+{
+ _allowFloat32toFloat16 = allow;
+}
+
+bool ANeuralNetworksModel::finish() noexcept
+{
+ try
+ {
+ fillOptionalOperand();
+
+ _graph->finishBuilding();
+
+ _operand_usages.clear();
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << '\n';
+
+ return false;
+ }
+
+ return true;
+}
+
+bool ANeuralNetworksModel::isFinished() noexcept { return !_graph->isBuildingPhase(); }
+
+bool ANeuralNetworksModel::isExistOperand(uint32_t index) noexcept
+{
+ return _graph->operands().exist(onert::ir::OperandIndex{index});
+}
+
+size_t ANeuralNetworksModel::operandSize(uint32_t index) noexcept
+{
+ try
+ {
+ return _graph->operands().at(onert::ir::OperandIndex{index}).operandSize();
+ }
+ catch (const std::exception &e)
+ {
+ VERBOSE(EXCEPTION) << e.what() << '\n';
+
+ return 0;
+ }
+}
+
+bool ANeuralNetworksModel::isUsageSet(uint32_t index) noexcept
+{
+ return (_operand_usages[index] != OperandUsage::NOT_DEFINED);
+}
+
+bool ANeuralNetworksModel::isOperationOutput(uint32_t index) noexcept
+{
+ return (_operand_usages[index] == OperandUsage::OPERATION_OUTPUT);
+}
+
+void ANeuralNetworksModel::setOptionalOperand(const onert::ir::OperandIndex idx)
+{
+ _optional_operands.insert(idx);
+}
+
+void ANeuralNetworksModel::fillOptionalOperand(void)
+{
+ _graph->operations().iterate([&](const onert::ir::OperationIndex &, onert::ir::Operation &node) {
+ for (auto input : node.getInputs())
+ {
+ // TODO fill default value for optional operands
+ if (_optional_operands.find(input) != _optional_operands.end())
+ {
+ throw std::runtime_error{"Optional operand is not supported yet"};
+ }
+ }
+ });
+}
+
+std::shared_ptr<onert::ir::Subgraphs> ANeuralNetworksModel::getSubGraphs() const
+{
+ auto all_subgs = std::make_shared<onert::ir::Subgraphs>();
+
+ all_subgs->push(onert::ir::SubgraphIndex{0}, _graph);
+ // TODO Find all child subgraphs and copy them to all_subgs
+ // Must find the same subgraph by using to compare pointer of subgraphs and set subgraph's index
+ // to operands of control flow operations
+ // Must clean all child subgraphs's pointer to prevent memory leak in case of that graph has
+ // subgraph itself recursively
+
+ return all_subgs;
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h
new file mode 100644
index 000000000..df6c97c44
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MODEL_H__
+#define __MODEL_H__
+
+#include <unordered_set>
+#include <NeuralNetworks.h>
+#include <NeuralNetworksEx.h>
+
+#include "ir/Graph.h"
+#include "ir/Subgraphs.h"
+
+struct ANeuralNetworksModel
+{
+public:
+ enum class OperandUsage
+ {
+ NOT_DEFINED = 0,
+ MODEL_INPUT,
+ CONSTANT,
+ OPERATION_OUTPUT,
+ };
+
+public:
+ ANeuralNetworksModel() noexcept;
+
+public:
+ bool addOperand(const ANeuralNetworksOperandType *type) noexcept;
+ bool setOperandValue(uint32_t index, const void *buffer, size_t length, bool optional = false,
+ bool copy = false) noexcept;
+ bool addOperation(ANeuralNetworksOperationType type, uint32_t inputCount, const uint32_t *inputs,
+ uint32_t outputCount, const uint32_t *outputs) noexcept;
+ bool addOperationEx(ANeuralNetworksOperationTypeEx type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs) noexcept;
+ bool addModelInput(uint32_t index) noexcept;
+ bool addModelOutput(uint32_t index) noexcept;
+ void allowFloat32toFloat16(bool allow) noexcept;
+ bool allowedToFp16() const noexcept { return _allowFloat32toFloat16; }
+ bool finish() noexcept;
+
+ onert::ir::Graph &deref(void) { return *_graph; }
+ bool isFinished() noexcept;
+ bool isExistOperand(uint32_t index) noexcept;
+ size_t operandSize(uint32_t index) noexcept;
+ bool isUsageSet(uint32_t index) noexcept;
+ bool isOperationOutput(uint32_t index) noexcept;
+ std::shared_ptr<onert::ir::Subgraphs> getSubGraphs() const;
+
+private:
+ void setOptionalOperand(const onert::ir::OperandIndex idx);
+ void fillOptionalOperand(void);
+
+private:
+ std::shared_ptr<onert::ir::Graph> _graph;
+ std::unordered_set<onert::ir::OperandIndex> _optional_operands;
+ std::vector<OperandUsage> _operand_usages;
+ bool _allowFloat32toFloat16;
+};
+
+#endif // __MODEL_H__
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.test.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.test.cc
new file mode 100644
index 000000000..bb42f2b08
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.test.cc
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ANeuralNetworksModel.h"
+
+TEST(MODEL, neg_model_build)
+{
+ ANeuralNetworksModel model;
+ ASSERT_FALSE(model.isFinished());
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc
new file mode 100644
index 000000000..63d4e3c09
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NNAPIConvert.h"
+
+#include <numeric>
+
+using namespace onert::ir;
+
+DataType NNAPIConvert::getDataType(OperandCode type)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ return DataType::FLOAT32;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ return DataType::INT32;
+ case ANEURALNETWORKS_UINT32:
+ return DataType::UINT32;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ return DataType::QUANT_UINT8_ASYMM;
+ case ANEURALNETWORKS_TENSOR_QUANT8_SYMM:
+ return DataType::QUANT_INT8_SYMM;
+ case ANEURALNETWORKS_BOOL:
+ case ANEURALNETWORKS_TENSOR_BOOL8:
+ return DataType::BOOL8;
+ default:
+ throw std::runtime_error("Unsupported type");
+ }
+}
+
+TypeInfo NNAPIConvert::getTypeInfo(const ANeuralNetworksOperandType *type)
+{
+ return TypeInfo(getDataType((OperandCode)(type->type)), type->scale, type->zeroPoint);
+}
+
+Shape NNAPIConvert::getShape(const ANeuralNetworksOperandType *type)
+{
+ Shape shape(type->dimensionCount);
+
+ for (uint32_t axis = 0; axis < type->dimensionCount; ++axis)
+ {
+ shape.dim(axis) = type->dimensions[axis];
+ }
+
+ return shape;
+}
+
+size_t NNAPIConvert::calculateSizeFromType(const ANeuralNetworksOperandType *type)
+{
+ auto shape = getShape(type);
+ auto data_type = getDataType((OperandCode)(type->type));
+
+ return shape.num_elements() * sizeOfDataType(data_type);
+}
+
+Activation NNAPIConvert::getFusedActivation(FuseCode act)
+{
+ switch (act)
+ {
+ case ANEURALNETWORKS_FUSED_NONE:
+ return Activation::NONE;
+ case ANEURALNETWORKS_FUSED_RELU:
+ return Activation::RELU;
+ case ANEURALNETWORKS_FUSED_RELU1:
+ return Activation::RELU1;
+ case ANEURALNETWORKS_FUSED_RELU6:
+ return Activation::RELU6;
+ default:
+ throw std::runtime_error("Unsupported activation type");
+ }
+}
+
+PaddingType NNAPIConvert::getPaddingType(PaddingCode type)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_PADDING_SAME:
+ return PaddingType::SAME;
+ case ANEURALNETWORKS_PADDING_VALID:
+ return PaddingType::VALID;
+ default:
+ throw std::runtime_error("Unsupported type");
+ }
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.h b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.h
new file mode 100644
index 000000000..4fd985e6e
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file NNAPIConvert.h
+ * @brief This file contains convereter(s)\n
+ * from NNAPI frontend's struct to onert's internal struct
+ */
+#ifndef __ONERT_NNAPI_CONVERT_H__
+#define __ONERT_NNAPI_CONVERT_H__
+
+#include <NeuralNetworks.h>
+
+#include <ir/TypeInfo.h>
+#include <ir/Shape.h>
+#include <ir/Padding.h>
+#include <ir/InternalType.h>
+
+class NNAPIConvert
+{
+
+public:
+ /**
+ * @brief Convert data type from NNAPI to internal data type
+ * @param[in] type NNAPI's data type
+ * @return onert's internal data type
+ */
+ static onert::ir::DataType getDataType(OperandCode type);
+
+ /**
+ * @brief Convert operand type info from NNAPI to interanl operand type info
+ * @param[in] type NNAPI's operand type
+ * @return onert's internal operand type info
+ */
+ static onert::ir::TypeInfo getTypeInfo(const ANeuralNetworksOperandType *type);
+
+ /**
+ * @brief Convert operand shape info from NNAPI to internal operand shape
+ * @param[in] type NNAPI's operand type
+ * @return onert's internal operand shape
+ */
+ static onert::ir::Shape getShape(const ANeuralNetworksOperandType *type);
+
+ /**
+ * @brief Calcaulate operand size from NNAPI type
+ * @param[in] type NNAPI's operand type
+ * @return Operand size
+ */
+ static size_t calculateSizeFromType(const ANeuralNetworksOperandType *type);
+
+ /**
+ * @brief Convert NNAPI FuseCode to internal activation type
+ * @param[in] act NNAPI's FuseCode type
+ * @return onert's internal activation type
+ */
+ static onert::ir::Activation getFusedActivation(FuseCode act);
+
+ /**
+ * @brief Convert NNAPI PaddingCode to internal padding type
+ * @param[in] type NNAPI's PaddingCode type
+ * @return onert's internal padding type
+ */
+ static onert::ir::PaddingType getPaddingType(PaddingCode type);
+};
+
+#endif // __ONERT_NNAPI_CONVERT_H__
diff --git a/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc
new file mode 100644
index 000000000..a84ce1b8d
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc
@@ -0,0 +1,1919 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OperationFactory.h"
+#include "NNAPIConvert.h"
+
+#include <ir/Operations.Include.h>
+#include <string.h>
+
+namespace
+{
+using namespace onert::ir;
+
+void replaceDataType(Operands &operands, const OperandIndex &index, const DataType type)
+{
+ assert(operands.exist(index));
+ operands.at(index).type(type);
+}
+
+ExplicitPadding makeExplicitPadding(Operands &operands, const OperandIndex &left_index,
+ const OperandIndex &right_index, const OperandIndex &top_index,
+ const OperandIndex &bottom_index)
+{
+ auto left = operands.at(left_index).asScalar<int32_t>();
+ auto right = operands.at(right_index).asScalar<int32_t>();
+ auto top = operands.at(top_index).asScalar<int32_t>();
+ auto bottom = operands.at(bottom_index).asScalar<int32_t>();
+
+ if (left < 0 || right < 0 || top < 0 || bottom < 0)
+ {
+ throw std::runtime_error{"Cannot handle negative explicit padding value"};
+ }
+
+ ExplicitPadding param;
+ param.left = static_cast<uint32_t>(left);
+ param.right = static_cast<uint32_t>(right);
+ param.top = static_cast<uint32_t>(top);
+ param.bottom = static_cast<uint32_t>(bottom);
+
+ return param;
+}
+
+Stride makeStride(Operands &operands, const OperandIndex &horizontal_index,
+ const OperandIndex &vertical_index)
+{
+ auto horizontal = operands.at(horizontal_index).asScalar<int32_t>();
+ auto vertical = operands.at(vertical_index).asScalar<int32_t>();
+
+ if (vertical < 0 || horizontal < 0)
+ {
+ throw std::runtime_error{"Cannot handle negative stride value"};
+ }
+
+ Stride stride;
+ stride.horizontal = static_cast<uint32_t>(horizontal);
+ stride.vertical = static_cast<uint32_t>(vertical);
+
+ return stride;
+}
+
+uint32_t getUint32Scalar(Operands &operands, const OperandIndex index)
+{
+ auto int32_value = operands.at(index).asScalar<int32_t>();
+ if (int32_value < 0)
+ {
+ throw std::runtime_error{"Cannot handle negative value"};
+ }
+
+ return static_cast<uint32_t>(int32_value);
+}
+
+OperationFactory::Generator
+getElementwiseActivationGenerator(const onert::ir::operation::ElementwiseActivation::Type op_type,
+ float alpha = 0.f, float beta = 0.f)
+{
+ return [op_type, alpha, beta](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 1);
+ assert(init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+
+ OperandIndexSequence inputs{init_param.inputs[0]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::ElementwiseActivation::Param param;
+ param.op_type = op_type;
+ param.alpha = alpha;
+ param.beta = beta;
+
+ return new operation::ElementwiseActivation{inputs, outputs, param};
+ };
+}
+
+OperationFactory::Generator getElementwiseBinaryGenerator(
+ const onert::ir::operation::ElementwiseBinary::ElementwiseBinaryType op_type)
+{
+ return [op_type](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 2);
+ assert(init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Lefthand side operand
+ // 1 -> Righthand side operand
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::ElementwiseBinary::Param param;
+ param.op_type = op_type;
+
+ return new operation::ElementwiseBinary{inputs, outputs, param};
+ };
+}
+
+OperationFactory::Generator
+getElementwiseUnaryGenerator(const onert::ir::operation::ElementwiseUnary::Type op_type)
+{
+ return [op_type](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 1);
+ assert(init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+
+ OperandIndexSequence inputs{init_param.inputs[0]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::ElementwiseUnary::Param param;
+ param.op_type = op_type;
+
+ if (op_type == operation::ElementwiseUnary::Type::CAST)
+ {
+ // NNAPI uses QUANT_UINT8_ASYMM to represent UINT8 type for ANEURALNETWORKS_CAST's
+ // input/output
+ if (operands.at(inputs.at(0)).typeInfo().type() == DataType::QUANT_UINT8_ASYMM)
+ {
+ replaceDataType(operands, inputs.at(0), DataType::UINT8);
+ }
+ if (operands.at(outputs.at(0)).typeInfo().type() == DataType::QUANT_UINT8_ASYMM)
+ {
+ replaceDataType(operands, outputs.at(0), DataType::UINT8);
+ }
+ }
+
+ return new operation::ElementwiseUnary{inputs, outputs, param};
+ };
+}
+
+OperationFactory::Generator
+getBinaryArithmeticGenerator(const onert::ir::operation::BinaryArithmetic::ArithmeticType op_type)
+{
+ return [op_type](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 3);
+ assert(init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Lefthand side operand
+ // 1 -> Righthand side operand
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::BinaryArithmetic::Param param;
+ param.arithmetic_type = op_type;
+ const auto activation_index = OperandIndex{init_param.inputs[2]};
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+
+ return new operation::BinaryArithmetic{inputs, outputs, param};
+ };
+}
+
+OperationFactory::Generator
+getPool2DGenerator(const onert::ir::operation::Pool2D::PoolType pool_type)
+{
+ return [pool_type](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 7 || init_param.input_count == 10);
+ assert(init_param.output_count == 1);
+
+ // In common
+ // 0 -> IFM Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::Pool2D::Param param;
+ param.op_type = pool_type;
+ if (init_param.input_count == 7) // support implicit padding
+ {
+ // Each input should be interpreted as follows:
+ //
+ // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index
+ // 2 -> Horizontal (over width) Stride Index
+ // 3 -> Vertial (over height) Stride Index
+ // 4 -> Filter Width Index
+ // 5 -> Filter Height Index
+ // 6 -> FuseCode (activation) Index
+
+ const auto padding_index = OperandIndex{init_param.inputs[1]};
+ const auto hstride_index = OperandIndex{init_param.inputs[2]};
+ const auto vstride_index = OperandIndex{init_param.inputs[3]};
+ const auto kw_index = OperandIndex{init_param.inputs[4]};
+ const auto kh_index = OperandIndex{init_param.inputs[5]};
+ const auto activation_index = OperandIndex{init_param.inputs[6]};
+
+ param.padding.type =
+ NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>());
+ param.stride = makeStride(operands, hstride_index, vstride_index);
+ param.kw = getUint32Scalar(operands, kw_index);
+ param.kh = operands.at(kh_index).asScalar<uint32_t>();
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+ }
+ else // support explicit padding
+ {
+ // Each input should be interpreted as follows:
+ //
+ // 1 -> Padding_left index
+ // 2 -> Padding_right index
+ // 3 -> Padding_top index
+ // 4 -> Padding_bottom index
+ // 5 -> Horizontal (over width) Stride Index
+ // 6 -> Vertial (over height) Stride Index
+ // 7 -> Filter Width Index
+ // 8 -> Filter Height Index
+ // 9 -> FuseCode (activation) Index
+
+ const auto padding_left_index = OperandIndex{init_param.inputs[1]};
+ const auto padding_right_index = OperandIndex{init_param.inputs[2]};
+ const auto padding_top_index = OperandIndex{init_param.inputs[3]};
+ const auto padding_bottom_index = OperandIndex{init_param.inputs[4]};
+ const auto hstride_index = OperandIndex{init_param.inputs[5]};
+ const auto vstride_index = OperandIndex{init_param.inputs[6]};
+ const auto kw_index = OperandIndex{init_param.inputs[7]};
+ const auto kh_index = OperandIndex{init_param.inputs[8]};
+ const auto activation_index = OperandIndex{init_param.inputs[9]};
+
+ param.padding.type = PaddingType::EXPLICIT;
+ param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index,
+ padding_top_index, padding_bottom_index);
+ param.stride = makeStride(operands, hstride_index, vstride_index);
+ param.kw = getUint32Scalar(operands, kw_index);
+ param.kh = getUint32Scalar(operands, kh_index);
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+ }
+ return new operation::Pool2D{inputs, outputs, param};
+ };
+}
+
+OperationFactory::Generator
+getReduceGenerator(const onert::ir::operation::Reduce::ReduceType reduce_type)
+{
+ return [reduce_type](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 3);
+ assert(init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Reduced Axes Tensor Index
+ // 2 -> keep_dims Index
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::Reduce::Param param;
+ param.reduce_type = reduce_type;
+ param.keep_dims = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<int8_t>() != 0;
+
+ return new operation::Reduce{inputs, outputs, param};
+ };
+}
+
+template <typename T>
+Operation *CreateSimpleUnaryOp(const OperationFactory::Param &init_param, Operands &)
+{
+ assert(init_param.input_count == 1 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ return new T{inputs, outputs};
+}
+
+// A generator function for binary ops with no params
+template <typename T>
+Operation *createSimpleBinaryOp(const OperationFactory::Param &init_param, Operands &)
+{
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ return new T{inputs, outputs};
+}
+
+OperationFactory::Generator getComparisonGenerator(operation::Comparison::ComparisonType type)
+{
+ return [type](const OperationFactory::Param &init_param, Operands &) -> Operation * {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input0 Tensor Index
+ // 1 -> input1 Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ operation::Comparison::Param param;
+ param.comparison_type = type;
+
+ return new operation::Comparison{inputs, outputs, param};
+ };
+}
+
+} // namespace
+
+OperationFactory &OperationFactory::get()
+{
+ static OperationFactory factory;
+ return factory;
+}
+
+OperationFactory::OperationFactory()
+{
+ // Each input should be interpreted as follows:
+ // 0 -> Input Tensor Index
+ // 1 -> Block size Index
+ _map[ANEURALNETWORKS_BATCH_TO_SPACE_ND] = createSimpleBinaryOp<operation::BatchToSpaceND>;
+
+ _map[ANEURALNETWORKS_DEPTHWISE_CONV_2D] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert((init_param.input_count == 8 || init_param.input_count == 11) &&
+ init_param.output_count == 1);
+
+ // In common
+ // 0 -> IFM Tensor Index
+ // 1 -> Kernel Tensor Index
+ // 2 -> Bias Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::DepthwiseConv2D::Param param;
+ if (init_param.input_count == 8)
+ {
+ // Imlicit Padding case
+ // Each input should be interpreted as follows:
+ //
+ // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index
+ // 4 -> Stride (width) Index
+ // 5 -> Stride (height) INdex
+ // 6 -> Depthwise multiplier
+ // 7 -> Activation Index
+
+ const auto padding_index = OperandIndex{init_param.inputs[3]};
+ const auto hstride_index = OperandIndex{init_param.inputs[4]};
+ const auto vstride_index = OperandIndex{init_param.inputs[5]};
+ const auto multiplier_index = OperandIndex{init_param.inputs[6]};
+ const auto activation_index = OperandIndex{init_param.inputs[7]};
+
+ param.padding.type =
+ NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>());
+ param.stride = makeStride(operands, hstride_index, vstride_index);
+ param.multiplier = getUint32Scalar(operands, multiplier_index);
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+ }
+ else
+ {
+ // Explicit Padding case
+ // Each input should be interpreted as follows:
+ //
+ // 3 -> Padding On the Left
+ // 4 -> Padding On the Right
+ // 5 -> Padding On the Top
+ // 6 -> Padding On the Bottom
+ // 7 -> Stride (width) Index
+ // 8 -> Stride (height) Index
+ // 9 -> Depthwise multiplier
+ // 10-> Activation Index
+
+ const auto padding_left_index = OperandIndex{init_param.inputs[3]};
+ const auto padding_right_index = OperandIndex{init_param.inputs[4]};
+ const auto padding_top_index = OperandIndex{init_param.inputs[5]};
+ const auto padding_bottom_index = OperandIndex{init_param.inputs[6]};
+ const auto hstride_index = OperandIndex{init_param.inputs[7]};
+ const auto vstride_index = OperandIndex{init_param.inputs[8]};
+ const auto multiplier_index = OperandIndex{init_param.inputs[9]};
+ const auto activation_index = OperandIndex{init_param.inputs[10]};
+
+ param.padding.type = PaddingType::EXPLICIT;
+ param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index,
+ padding_top_index, padding_bottom_index);
+ param.stride = makeStride(operands, hstride_index, vstride_index);
+ param.multiplier = getUint32Scalar(operands, multiplier_index);
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+ }
+
+ // TODO set dilation
+ param.dilation.width_factor = 1;
+ param.dilation.height_factor = 1;
+
+ return new operation::DepthwiseConv2D{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_MAX_POOL_2D] = getPool2DGenerator(operation::Pool2D::PoolType::MAX);
+
+ _map[ANEURALNETWORKS_AVERAGE_POOL_2D] = getPool2DGenerator(operation::Pool2D::PoolType::AVG);
+
+ _map[ANEURALNETWORKS_CONCATENATION] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count >= 2); // At least one one input tensor and axis
+ assert(init_param.output_count == 1);
+
+ // When there are N + 1 inputs, each input should be interpreted as follows:
+ //
+ // [0, N) -> Input tensors
+ // N -> Axis
+ //
+
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < init_param.input_count - 1; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::Concat::Param param;
+ const OperandIndex axis_index{init_param.inputs[init_param.input_count - 1]};
+ param.axis = operands.at(axis_index).asScalar<int32_t>();
+
+ return new operation::Concat{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_RESHAPE] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> A tensor, specifying the tensor to be reshaped.
+ // 1 -> A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32, defining the shape of the output
+ // tensor
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::Reshape::Param param{};
+
+ return new operation::Reshape{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_FULLY_CONNECTED] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 4 && init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> A tensor, specifying the input.
+ // 1 -> A 2-D tensor, specifying the weights
+ // 2 -> A 1-D tensor, specifying the bias
+ // 3 -> An INT32 value, and has to be one of the FuseCode values
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::FullyConnected::Param param;
+ const auto activation_index = OperandIndex{init_param.inputs[3]};
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+ param.weights_format = FullyConnectedWeightsFormat::Default;
+
+ return new operation::FullyConnected{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_SOFTMAX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> A 2-D or 4-D tensor, specifying the tensor to be reshaped.
+ // 1 -> FLOAT32 value, specifying the positive scaling factor for the exponent, beta.
+
+ OperandIndexSequence inputs{init_param.inputs[0]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ const auto beta_index = OperandIndex{init_param.inputs[1]};
+
+ operation::Softmax::Param param;
+ param.beta = operands.at(beta_index).asScalar<float>();
+
+ return new operation::Softmax{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_CAST] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::CAST);
+
+ // ANEURALNETWORKS_CAST_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_CAST_EX
+ _map[ANEURALNETWORKS_CAST_EX] = _map[ANEURALNETWORKS_CAST];
+
+ _map[ANEURALNETWORKS_CONV_2D] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ using operation::Conv2D;
+
+ // inputCount is either 7 or 10 acccording to NN API specification.
+ // - Padding is implicit when inputCount is 7
+ // - Padding is explicit when inputCount is 10
+ assert(init_param.input_count == 7 || init_param.input_count == 10 ||
+ init_param.input_count == 13);
+ assert(init_param.output_count == 1);
+
+ // 0 -> IFM Tensor Index
+ // 1 -> Kernel Tensor Index
+ // 2 -> Bias Tensor Index
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ Conv2D::Param param;
+ if (init_param.input_count == 7) // support implicit padding
+ {
+ // Each input should be interpreted as follows:
+ //
+ // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index
+ // 4 -> Stride (width) Index
+ // 5 -> Stride (height) INdex
+ // 6 -> Activation Index
+
+ const auto padding_index = OperandIndex{init_param.inputs[3]};
+ const auto hstride_index = OperandIndex{init_param.inputs[4]};
+ const auto vstride_index = OperandIndex{init_param.inputs[5]};
+ const auto activation_index = OperandIndex{init_param.inputs[6]};
+
+ param.padding.type =
+ NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>());
+ param.stride = makeStride(operands, hstride_index, vstride_index);
+
+ param.dilation.width_factor = 1;
+ param.dilation.height_factor = 1;
+
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+ }
+ else if (init_param.input_count == 10) // support explicit padding
+ {
+ // Each input should be interpreted as follows:
+ //
+ // 3 -> Padding_left index
+ // 4 -> Padding_right index
+ // 5 -> Padding_top index
+ // 6 -> Padding_bottom index
+ // 7 -> Stride (width) Index
+ // 8 -> Stride (height) INdex
+ // 9 -> Activation Index
+
+ const auto padding_left_index = OperandIndex{init_param.inputs[3]};
+ const auto padding_right_index = OperandIndex{init_param.inputs[4]};
+ const auto padding_top_index = OperandIndex{init_param.inputs[5]};
+ const auto padding_bottom_index = OperandIndex{init_param.inputs[6]};
+ const auto hstride_index = OperandIndex{init_param.inputs[7]};
+ const auto vstride_index = OperandIndex{init_param.inputs[8]};
+ const auto activation_index = OperandIndex{init_param.inputs[9]};
+
+ param.padding.type = PaddingType::EXPLICIT;
+ param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index,
+ padding_top_index, padding_bottom_index);
+ param.stride = makeStride(operands, hstride_index, vstride_index);
+
+ param.dilation.width_factor = 1;
+ param.dilation.height_factor = 1;
+
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+ }
+ else if (init_param.input_count == 13) // support dilation
+ {
+ // Each input should be interpreted as follows:
+ //
+ // 3 -> Padding_left Index
+ // 4 -> Padding_right Index
+ // 5 -> Padding_top Index
+ // 6 -> Padding_bottom Index
+ // 7 -> Stride (width) Index
+ // 8 -> Stride (height) Index
+ // 9 -> Activation Index
+ // 11 -> Dilation (width_factor) Index
+ // 12 -> Dilation (height_factor) INdex
+
+ const auto padding_left_index = OperandIndex{init_param.inputs[3]};
+ const auto padding_right_index = OperandIndex{init_param.inputs[4]};
+ const auto padding_top_index = OperandIndex{init_param.inputs[5]};
+ const auto padding_bottom_index = OperandIndex{init_param.inputs[6]};
+ const auto hstride_index = OperandIndex{init_param.inputs[7]};
+ const auto vstride_index = OperandIndex{init_param.inputs[8]};
+ const auto activation_index = OperandIndex{init_param.inputs[9]};
+ const auto width_factor_index = OperandIndex{init_param.inputs[11]};
+ const auto height_factor_index = OperandIndex{init_param.inputs[12]};
+
+ param.padding.type = PaddingType::EXPLICIT;
+ param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index,
+ padding_top_index, padding_bottom_index);
+ param.stride = makeStride(operands, hstride_index, vstride_index);
+
+ auto width_factor = operands.at(width_factor_index).asScalar<int32_t>();
+ auto height_factor = operands.at(height_factor_index).asScalar<int32_t>();
+
+ param.dilation.width_factor = width_factor;
+ param.dilation.height_factor = height_factor;
+
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+ }
+ else
+ {
+ throw std::runtime_error{"Conv2D: unsupported input operand count"};
+ }
+
+ return new Conv2D{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_ADD] =
+ getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::ADD);
+
+ _map[ANEURALNETWORKS_ADDV2_EX] = _map[ANEURALNETWORKS_ADD];
+
+ _map[ANEURALNETWORKS_REDUCE_SUM] =
+ getReduceGenerator(onert::ir::operation::Reduce::ReduceType::SUM);
+
+ // ANEURALNETWORKS_REDUCE_SUM_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_REDUCE_SUM_EX
+ _map[ANEURALNETWORKS_REDUCE_SUM_EX] = _map[ANEURALNETWORKS_REDUCE_SUM];
+
+ _map[ANEURALNETWORKS_SUB] =
+ getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::SUB);
+
+ _map[ANEURALNETWORKS_SLICE] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Begins Tensor Index
+ // 2 -> Sizes Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+
+ return new operation::Slice{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_STRIDED_SLICE] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 7 && init_param.output_count == 1);
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2],
+ init_param.inputs[3]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 1 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the starts of
+ // the dimensions of the input tensor to be sliced. The length must be
+ // of rank(input0).
+ // 2 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the ends of
+ // the dimensions of the input tensor to be sliced. The length must be
+ // of rank(input0).
+ // 3 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the strides of
+ // the dimensions of the input tensor to be sliced. The length must be
+ // of rank(input0).
+ // 4 -> An {@link ANEURALNETWORKS_INT32} scalar, begin_mask. If the ith bit
+ // of begin_mask is set, begin[i] is ignored and the fullest possible
+ // range in that dimension is used instead.
+ // 5 -> An {@link ANEURALNETWORKS_INT32} scalar, end_mask. If the ith bit of
+ // end_mask is set, end[i] is ignored and the fullest possible range in
+ // that dimension is used instead.
+ // 6 -> An {@link ANEURALNETWORKS_INT32} scalar, shrink_axis_mask. An int32
+ // mask. If the ith bit of shrink_axis_mask is set, it implies that the
+ // ith specification shrinks the dimensionality by 1. A slice of size 1
+ // starting from begin[i] in the dimension must be preserved.
+
+ operation::StridedSlice::Param param;
+
+ param.begin_mask = operands.at(OperandIndex{init_param.inputs[4]}).asScalar<std::int32_t>();
+ param.end_mask = operands.at(OperandIndex{init_param.inputs[5]}).asScalar<std::int32_t>();
+ param.shrink_axis_mask =
+ operands.at(OperandIndex{init_param.inputs[6]}).asScalar<std::int32_t>();
+
+ return new operation::StridedSlice{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_TRANSPOSE] = createSimpleBinaryOp<operation::Transpose>;
+
+ _map[ANEURALNETWORKS_MUL] =
+ getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::MUL);
+
+ _map[ANEURALNETWORKS_SQUEEZE] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 1 || init_param.input_count == 2);
+ assert(init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> An n-D tensor, the tensor to be squeezed.
+ // 1 -> An optional 1-D tensor of ANEURALNETWORKS_TENSOR_INT32. The dimensions to squeeze.
+ // If specified only squeezes the dimensions listed. Otherwise, squeezes all dimensions.
+ // The dimension index starts at 0. An error must be reported if squeezing a dimension that
+ // is not 1.
+
+ // Add mandatory input index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ // Add dims index if specified
+ operation::Squeeze::Param param{};
+ if (init_param.input_count == 2)
+ {
+ auto squeeze_dims_idx = OperandIndex{init_param.inputs[1]};
+ assert(operands.at(squeeze_dims_idx).shape().rank() == 1);
+ assert(operands.at(squeeze_dims_idx).shape().dim(0) >= 0);
+ assert(static_cast<uint32_t>(operands.at(squeeze_dims_idx).shape().dim(0)) <=
+ sizeof(param.dims));
+ param.ndim = operands.at(squeeze_dims_idx).shape().dim(0);
+ if (param.ndim > 0)
+ {
+ assert(operands.at(squeeze_dims_idx).data());
+ memcpy(param.dims, operands.at(squeeze_dims_idx).data()->base(),
+ param.ndim * sizeof(param.dims[0]));
+ }
+ }
+
+ return new operation::Squeeze{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_TANH] = getElementwiseActivationGenerator(
+ onert::ir::operation::ElementwiseActivation::Type::TANH, 1.f, 1.f);
+
+ _map[ANEURALNETWORKS_LOG] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::LOG);
+
+ _map[ANEURALNETWORKS_LOGISTIC] = getElementwiseActivationGenerator(
+ onert::ir::operation::ElementwiseActivation::Type::LOGISTIC);
+
+ _map[ANEURALNETWORKS_DIV] =
+ getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::DIV);
+
+ _map[ANEURALNETWORKS_EXP] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::EXP);
+
+ // ANEURALNETWORKS_EXP_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_EXP_EX
+ _map[ANEURALNETWORKS_EXP_EX] = _map[ANEURALNETWORKS_EXP];
+
+ // Each input should be interpreted as follows:
+ // 0 -> Input Tensor Index
+ // 1 -> Axis Tensor Index
+ _map[ANEURALNETWORKS_EXPAND_DIMS] = createSimpleBinaryOp<operation::ExpandDims>;
+
+ _map[ANEURALNETWORKS_GREATER] =
+ getComparisonGenerator(operation::Comparison::ComparisonType::Greater);
+ _map[ANEURALNETWORKS_GREATER_EQUAL] =
+ getComparisonGenerator(operation::Comparison::ComparisonType::GreaterEqual);
+ _map[ANEURALNETWORKS_LESS] = getComparisonGenerator(operation::Comparison::ComparisonType::Less);
+ _map[ANEURALNETWORKS_LESS_EQUAL] =
+ getComparisonGenerator(operation::Comparison::ComparisonType::LessEqual);
+ _map[ANEURALNETWORKS_NOT_EQUAL] =
+ getComparisonGenerator(operation::Comparison::ComparisonType::NotEqual);
+ _map[ANEURALNETWORKS_EQUAL] =
+ getComparisonGenerator(operation::Comparison::ComparisonType::Equal);
+
+ // ANEURALNETWORKS_GREATER_EQUAL_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_GREATER_EQUAL_EX
+ _map[ANEURALNETWORKS_GREATER_EQUAL_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input0 Tensor Index
+ // 1 -> input1 Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ operation::Comparison::Param param;
+ param.comparison_type = operation::Comparison::ComparisonType::GreaterEqual;
+
+ // Output operand type must be boolean
+ replaceDataType(operands, outputs.at(0), DataType::BOOL8);
+
+ return new operation::Comparison{inputs, outputs, param};
+ };
+
+ // ANEURALNETWORKS_LESS_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_LESS_EX
+ _map[ANEURALNETWORKS_LESS_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input0 Tensor Index
+ // 1 -> input1 Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ operation::Comparison::Param param;
+ param.comparison_type = operation::Comparison::ComparisonType::Less;
+
+ // Output operand type must be boolean
+ replaceDataType(operands, outputs.at(0), DataType::BOOL8);
+
+ return new operation::Comparison{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_REDUCE_ALL] =
+ getReduceGenerator(onert::ir::operation::Reduce::ReduceType::ALL);
+
+ _map[ANEURALNETWORKS_REDUCE_ANY] =
+ getReduceGenerator(onert::ir::operation::Reduce::ReduceType::ANY);
+
+ _map[ANEURALNETWORKS_REDUCE_MAX] =
+ getReduceGenerator(onert::ir::operation::Reduce::ReduceType::MAX);
+
+ // ANEURALNETWORKS_REDUCE_MAX_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_REDUCE_MAX_EX
+ _map[ANEURALNETWORKS_REDUCE_MAX_EX] = _map[ANEURALNETWORKS_REDUCE_MAX];
+
+ // ANEURALNETWORKS_NOT_EQUAL_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_NOT_EQUAL_EX
+ _map[ANEURALNETWORKS_NOT_EQUAL_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input1 Tensor Index
+ // 1 -> input2 Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ operation::Comparison::Param param;
+ param.comparison_type = operation::Comparison::ComparisonType::NotEqual;
+
+ // Output operand type must be boolean
+ replaceDataType(operands, outputs.at(0), DataType::BOOL8);
+
+ return new operation::Comparison{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_LOGICAL_AND] = getElementwiseBinaryGenerator(
+ operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_AND);
+
+ // ANEURALNETWORKS_LOGICAL_AND_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_LOGICAL_AND_EX
+ _map[ANEURALNETWORKS_LOGICAL_AND_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input0 Tensor Index
+ // 1 -> input1 Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ // This operation's operands must be boolean type.
+ replaceDataType(operands, inputs.at(0), DataType::BOOL8);
+ replaceDataType(operands, inputs.at(1), DataType::BOOL8);
+ replaceDataType(operands, outputs.at(0), DataType::BOOL8);
+
+ operation::ElementwiseBinary::Param param;
+ param.op_type = operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_AND;
+
+ return new operation::ElementwiseBinary{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_RSQRT] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::RSQRT);
+
+ _map[ANEURALNETWORKS_SELECT] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Condition Tensor Index
+ // 1 -> Input X(true) Tensor Index
+ // 2 -> Input Y(false) Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+
+ return new operation::Select{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_SELECT_V2_EX] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Condition Tensor Index
+ // 1 -> Input X(true) Tensor Index
+ // 2 -> Input Y(false) Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+
+ return new operation::Select{inputs, outputs};
+ };
+
+ // ANEURALNETWORKS_RSQRT_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_RSQRT_EX
+ _map[ANEURALNETWORKS_RSQRT_EX] = _map[ANEURALNETWORKS_RSQRT];
+
+ _map[ANEURALNETWORKS_RELU] =
+ getElementwiseActivationGenerator(onert::ir::operation::ElementwiseActivation::Type::RELU,
+ onert::ir::operation::ElementwiseActivation::infinity, 0);
+
+ _map[ANEURALNETWORKS_RESIZE_BILINEAR] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Index
+ // 1 -> Height Index
+ // 2 -> Width Index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ operation::ResizeBilinear::Param param;
+ param.height_out = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<int32_t>();
+ param.width_out = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<int32_t>();
+ param.align_corners = false;
+ param.half_pixel_centers = false;
+ return new operation::ResizeBilinear{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert((init_param.input_count == 3 || init_param.input_count == 4) &&
+ init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Index
+ // 1 -> Height Index
+ // 2 -> Width Index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ operation::ResizeNearestNeighbor::Param param;
+ param.height_out = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<int32_t>();
+ param.width_out = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<int32_t>();
+ param.align_corners = false;
+ // The layout input is not supported yet
+ return new operation::ResizeNearestNeighbor{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_RELU1] = getElementwiseActivationGenerator(
+ onert::ir::operation::ElementwiseActivation::Type::RELU, 1.f, -1.f);
+
+ _map[ANEURALNETWORKS_RELU6] = getElementwiseActivationGenerator(
+ onert::ir::operation::ElementwiseActivation::Type::RELU, 6.f, 0.f);
+
+ _map[ANEURALNETWORKS_REVERSE_EX] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Axis Tensor Index
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ return new operation::Reverse{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_RNN] = [](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 6 && init_param.output_count == 2);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Weights Tensor Index
+ // 2 -> Recurrent Weights Tensor Index
+ // 3 -> Bias Tensor Index
+ // 4 -> Hidden state (in) Index
+ // 5 -> Activation Index
+
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < init_param.input_count - 1; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+ OperandIndexSequence outputs;
+ for (uint32_t n = 0; n < init_param.output_count; ++n)
+ {
+ outputs.append(OperandIndex{init_param.outputs[n]});
+ }
+
+ operation::RNN::Param param;
+ const auto activation_index = OperandIndex{init_param.inputs[5]};
+ param.activation =
+ NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>());
+
+ return new operation::RNN{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_FLOOR] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::FLOOR);
+
+ _map[ANEURALNETWORKS_SPACE_TO_BATCH_ND] = [](const OperationFactory::Param &init_param,
+ Operands &) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Block size Index
+ // 2 -> Paddings Index
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < init_param.input_count; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+
+ return new operation::SpaceToBatchND{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_SPACE_TO_DEPTH] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Block size Index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ operation::SpaceToDepth::Param param;
+ param.block_size = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<std::int32_t>();
+
+ return new operation::SpaceToDepth{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_L2_POOL_2D] = getPool2DGenerator(operation::Pool2D::PoolType::L2);
+
+ _map[ANEURALNETWORKS_EMBEDDING_LOOKUP] = [](const OperationFactory::Param &init_param,
+ Operands &) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Lookups Index
+ // 1 -> Values Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ return new operation::EmbeddingLookup{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_L2_NORMALIZATION] = [](const OperationFactory::Param &init_param,
+ Operands &) {
+ assert(init_param.input_count == 1 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ // 0 -> input Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ return new operation::L2Normalization{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_HASHTABLE_LOOKUP] = [](const OperationFactory::Param &init_param,
+ Operands &) {
+ assert(init_param.input_count == 3 && init_param.output_count == 2);
+
+ // Each output should be interpreted as follows:
+ //
+ // 0 -> Output Index
+ // 1 -> Hits Index
+ OperandIndexSequence outputs{init_param.outputs[0], init_param.outputs[1]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Lookups Index
+ // 1 -> Keys Index
+ // 2 -> Values Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+
+ return new operation::HashtableLookup{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_PRELU] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ // 1 -> alpha Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ return new operation::PReLU{inputs, outputs};
+ };
+
+ // ANEURALNETWORKS_PRELU_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_PRELU_EX
+ _map[ANEURALNETWORKS_PRELU_EX] = _map[ANEURALNETWORKS_PRELU];
+
+ _map[ANEURALNETWORKS_TRANSPOSE_CONV_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 6 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Output Shape Index
+ // 1 -> Weights Index
+ // 2 -> Input Tensor Index
+ // 3 -> Padding Type
+ // 4 -> Stride width
+ // 5 -> Stride height
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+
+ operation::TransposeConv::Param param;
+
+ const auto padding_index = OperandIndex{init_param.inputs[3]};
+ const auto hstride_index = OperandIndex{init_param.inputs[4]};
+ const auto vstride_index = OperandIndex{init_param.inputs[5]};
+
+ param.padding.type =
+ NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>());
+ param.stride = makeStride(operands, hstride_index, vstride_index);
+
+ return new operation::TransposeConv{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_SQRT] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::SQRT);
+
+ // ANEURALNETWORKS_SQRT_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_SQRT_EX
+ _map[ANEURALNETWORKS_SQRT_EX] = _map[ANEURALNETWORKS_SQRT];
+
+ _map[ANEURALNETWORKS_LOGICAL_OR] = getElementwiseBinaryGenerator(
+ operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR);
+
+ // ANEURALNETWORKS_LOGICAL_OR_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_LOGICAL_OR_EX
+ _map[ANEURALNETWORKS_LOGICAL_OR_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input0 Tensor Index
+ // 1 -> input1 Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ // This operation's operands must be boolean type.
+ replaceDataType(operands, inputs.at(0), DataType::BOOL8);
+ replaceDataType(operands, inputs.at(1), DataType::BOOL8);
+ replaceDataType(operands, outputs.at(0), DataType::BOOL8);
+
+ operation::ElementwiseBinary::Param param;
+ param.op_type = operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR;
+
+ return new operation::ElementwiseBinary{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_LOGICAL_NOT] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::LOGICAL_NOT);
+
+ // ANEURALNETWORKS_LOGICAL_NOT_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_LOGICAL_NOT_EX
+ _map[ANEURALNETWORKS_LOGICAL_NOT_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 1 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ // This operation's operands must be boolean type.
+ replaceDataType(operands, inputs.at(0), DataType::BOOL8);
+ replaceDataType(operands, outputs.at(0), DataType::BOOL8);
+
+ operation::ElementwiseUnary::Param param;
+ param.op_type = operation::ElementwiseUnary::Type::LOGICAL_NOT;
+
+ return new operation::ElementwiseUnary{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_LSTM] = [](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 23 && init_param.output_count == 4);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Input to Input Tensor Index
+ // 2 -> Input to Forget Tensor Index
+ // 3 -> Input to Cell Tensor Index
+ // 4 -> Input to Output Tensor Index
+ // 5 -> Recurrent to Input Weights Tensor Index
+ // 6 -> Recurrent to Forget Weights Tensor Index
+ // 7 -> Recurrent to Cell Weights Tensor Index
+ // 8 -> Recurrent to Output Weights Tensor Index
+ // 9 -> Cell to Input Weights Tensor Index
+ // 10 -> Cell to Forget Weights Tensor Index
+ // 11 -> Cell to Output Weights Tensor Index
+ // 12 -> Input Gate Bias Tensor Index
+ // 13 -> Forget Gate Bias Tensor Index
+ // 14 -> Cell Bias Tensor Index
+ // 15 -> Output Gate Bias Tensor Index
+ // 16 -> Projection Weights Tensor Index
+ // 17 -> Projection Bias Tensor Index
+ // 18 -> Output State In Tensor Index
+ // 19 -> Cell State In Tensor Index
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < init_param.input_count - 3; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+
+ // Each output should be interpreted as follows:
+ //
+ // 0 -> Scratch Buffer Tensor Index
+ // 1 -> Output State Out Tensor Index
+ // 2 -> Cell State Out Tensor Index
+ // 3 -> Output Tensor Index
+ OperandIndexSequence outputs;
+ for (uint32_t n = 0; n < init_param.output_count; ++n)
+ {
+ outputs.append(OperandIndex{init_param.outputs[n]});
+ }
+
+ operation::LSTM::Param param;
+ const auto activation_index = OperandIndex{init_param.inputs[20]};
+ switch (operands.at(activation_index).asScalar<int32_t>())
+ {
+ case 0:
+ param.activation = Activation::NONE;
+ break;
+ case 1:
+ param.activation = Activation::RELU;
+ break;
+ case 2:
+ param.activation = Activation::RELU1;
+ break;
+ case 3:
+ param.activation = Activation::RELU6;
+ break;
+ case 4:
+ param.activation = Activation::TANH;
+ break;
+ case 6:
+ param.activation = Activation::SIGMOID;
+ break;
+ default:
+ throw std::runtime_error("Unsupported activation type");
+ break;
+ }
+ param.cell_threshold = operands.at(OperandIndex{init_param.inputs[21]}).asScalar<float>();
+ param.projection_threshold = operands.at(OperandIndex{init_param.inputs[22]}).asScalar<float>();
+ // This is initialization to prevent warning or error by static code analyzer. LSTM operation
+ // does not need time_major
+ param.time_major = false;
+
+ return new operation::LSTM{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert((init_param.input_count >= 24 || init_param.input_count <= 28) &&
+ (init_param.output_count >= 1 && init_param.output_count <= 3));
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Input to Input Tensor Index
+ // 2 -> Input to Forget Tensor Index
+ // 3 -> Input to Cell Tensor Index
+ // 4 -> Input to Output Tensor Index
+ // 5 -> Recurrent to Input Weights Tensor Index
+ // 6 -> Recurrent to Forget Weights Tensor Index
+ // 7 -> Recurrent to Cell Weights Tensor Index
+ // 8 -> Recurrent to Output Weights Tensor Index
+ // 9 -> Cell to Input Weights Tensor Index
+ // 10 -> Cell to Forget Weights Tensor Index
+ // 11 -> Cell to Output Weights Tensor Index
+ // 12 -> Input Gate Bias Tensor Index
+ // 13 -> Forget Gate Bias Tensor Index
+ // 14 -> Cell Bias Tensor Index
+ // 15 -> Output Gate Bias Tensor Index
+ // 16 -> Projection Weights Tensor Index
+ // 17 -> Projection Bias Tensor Index
+ // 18 -> Output State In Tensor Index
+ // 19 -> Cell State In Tensor Index
+ assert(init_param.input_count - 3 > 20);
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < 20; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+
+ // 24 -> Input Layer Normalization Weights Tensor Index
+ // 25 -> Forget Layer Normalization Weights Tensor Index
+ // 26 -> Cell Layer Normalization Weights Tensor Index
+ // 27 -> Output Layer Normalization Weights Tensor Index
+ if (init_param.input_count > 24)
+ {
+ for (uint32_t n = 24; n < 28; ++n)
+ {
+ if (init_param.input_count > n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+ }
+ }
+
+ // Each output should be interpreted as follows:
+ //
+ // 0 -> Output Tensor Index -> 3
+ // 1 -> Output State Out Tensor Index
+ // 2 -> Cell State Out Tensor Index
+ const OperandIndex scratch_buffer_index;
+ OperandIndex output_state_index =
+ init_param.output_count >= 2 ? OperandIndex{init_param.outputs[1]} : OperandIndex();
+ OperandIndex cell_state_index =
+ init_param.output_count >= 3 ? OperandIndex{init_param.outputs[2]} : OperandIndex();
+ const OperandIndex output_index = OperandIndex{init_param.outputs[0]};
+ OperandIndexSequence outputs{scratch_buffer_index, output_state_index, cell_state_index,
+ output_index};
+
+ operation::LSTM::Param param;
+ const auto activation_index = OperandIndex{init_param.inputs[20]};
+ switch (operands.at(activation_index).asScalar<int32_t>())
+ {
+ case 0:
+ param.activation = Activation::NONE;
+ break;
+ case 1:
+ param.activation = Activation::RELU;
+ break;
+ case 2:
+ param.activation = Activation::RELU1;
+ break;
+ case 3:
+ param.activation = Activation::RELU6;
+ break;
+ case 4:
+ param.activation = Activation::TANH;
+ break;
+ case 6:
+ param.activation = Activation::SIGMOID;
+ break;
+ default:
+ throw std::runtime_error("Unsupported activation type");
+ break;
+ }
+ param.cell_threshold = operands.at(OperandIndex{init_param.inputs[21]}).asScalar<float>();
+ param.projection_threshold = operands.at(OperandIndex{init_param.inputs[22]}).asScalar<float>();
+ param.time_major = operands.at(OperandIndex{init_param.inputs[23]}).asScalar<bool>();
+
+ return new operation::LSTM{inputs, outputs, param};
+ };
+
+ // ANEURALNETWORKS_EQUAL_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_EQUAL_EX
+ _map[ANEURALNETWORKS_EQUAL_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input0 Tensor Index
+ // 1 -> input1 Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ operation::Comparison::Param param;
+ param.comparison_type = operation::Comparison::ComparisonType::Equal;
+
+ // Output operand type must be boolean
+ replaceDataType(operands, outputs.at(0), DataType::BOOL8);
+
+ return new operation::Comparison{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_SQUARED_DIFFERENCE_EX] = [](const OperationFactory::Param &init_param,
+ Operands &) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> LHS Tensor Index
+ // 1 -> RHS Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ return new operation::SquaredDifference{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_TOPK_V2] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 2);
+
+ // Each output should be interpreted as follows:
+ //
+ // 0 -> Index for Output Values
+ // 1 -> Index for Output Indices
+ OperandIndexSequence outputs{init_param.outputs[0], init_param.outputs[1]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Index for Input Data
+ // 1 -> Index for K
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ operation::TopKV2::Param param;
+ param.k = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<std::int32_t>();
+
+ return new operation::TopKV2{inputs, outputs, param};
+ };
+
+ // ANEURALNETWORKS_CAST_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_CAST_EX
+ _map[ANEURALNETWORKS_TOPK_V2_EX] = _map[ANEURALNETWORKS_TOPK_V2];
+
+ _map[ANEURALNETWORKS_GATHER] = [](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ // 1 -> axis Index
+ // 2 -> indices Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[2]};
+
+ operation::Gather::Param param;
+ param.axis = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<int32_t>();
+
+ return new operation::Gather{inputs, outputs, param};
+ };
+
+ // ANEURALNETWORKS_GATHER_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_GATHER_EX
+ _map[ANEURALNETWORKS_GATHER_EX] = _map[ANEURALNETWORKS_GATHER];
+
+ _map[ANEURALNETWORKS_NEG] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::NEG);
+
+ // ANEURALNETWORKS_NEG_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_NEG_EX
+ _map[ANEURALNETWORKS_NEG_EX] = _map[ANEURALNETWORKS_NEG];
+
+ _map[ANEURALNETWORKS_ABS] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::ABS);
+
+ // ANEURALNETWORKS_ABS_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_ABS_EX
+ _map[ANEURALNETWORKS_ABS_EX] = _map[ANEURALNETWORKS_ABS];
+
+ _map[ANEURALNETWORKS_ARGMAX] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Axis Tensor Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ operation::ArgMax::Param param;
+ // NNAPI ARGMAX output type is always int32
+ param.output_type = DataType::INT32;
+
+ return new operation::ArgMax{inputs, outputs, param};
+ };
+
+ // ANEURALNETWORKS_ARGMAX_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_ARGMAX_EX
+ _map[ANEURALNETWORKS_ARGMAX_EX] = _map[ANEURALNETWORKS_ARGMAX];
+
+ _map[ANEURALNETWORKS_DEQUANTIZE] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::DEQUANTIZE);
+
+ _map[ANEURALNETWORKS_MEAN] = [](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> ifm Tensor Index
+ // 1 -> axis Tensor Index
+ // 2 -> keep_dims Index
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ operation::Reduce::Param param;
+ param.reduce_type = operation::Reduce::ReduceType::MEAN;
+ param.keep_dims = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<int32_t>() != 0;
+
+ return new operation::Reduce{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 5 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ operation::LocalResponseNormalization::Param param;
+ param.radius = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<std::int32_t>();
+ param.bias = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<float>();
+ param.alpha = operands.at(OperandIndex{init_param.inputs[3]}).asScalar<float>();
+ param.beta = operands.at(OperandIndex{init_param.inputs[4]}).asScalar<float>();
+
+ return new operation::LocalResponseNormalization{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_DEPTH_TO_SPACE] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Block size Index
+ OperandIndexSequence inputs{init_param.inputs[0]};
+
+ operation::DepthToSpace::Param param;
+ param.block_size = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<std::int32_t>();
+
+ return new operation::DepthToSpace{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_PACK_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count >= 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < init_param.input_count - 2; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+
+ operation::Pack::Param param;
+ const auto num_index = OperandIndex{init_param.inputs[init_param.input_count - 2]};
+ const auto axis_index = OperandIndex{init_param.inputs[init_param.input_count - 1]};
+ param.num = operands.at(num_index).asScalar<int32_t>();
+ param.axis = operands.at(axis_index).asScalar<int32_t>();
+
+ return new operation::Pack{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_REDUCE_MIN] =
+ getReduceGenerator(onert::ir::operation::Reduce::ReduceType::MIN);
+
+ // ANEURALNETWORKS_REDUCE_MIN_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_REDUCE_MIN_EX
+ _map[ANEURALNETWORKS_REDUCE_MIN_EX] = _map[ANEURALNETWORKS_REDUCE_MIN];
+
+ _map[ANEURALNETWORKS_SPLIT] = [](const OperationFactory::Param &init_param, Operands &operands) {
+ assert(init_param.input_count == 3);
+ assert(init_param.output_count >= 1); // At least one output tensor and axis
+
+ OperandIndexSequence inputs{init_param.inputs[1], init_param.inputs[0]};
+ OperandIndexSequence outputs;
+ for (uint32_t n = 0; n < init_param.output_count; ++n)
+ {
+ outputs.append(OperandIndex{init_param.outputs[n]});
+ }
+
+ operation::Split::Param param;
+ param.num_splits = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<std::int32_t>();
+
+ return new operation::Split{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_SPLIT_V_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 4);
+ assert(init_param.output_count >= 1); // At least one output tensor and axis
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+ OperandIndexSequence outputs;
+ for (uint32_t n = 0; n < init_param.output_count; ++n)
+ {
+ outputs.append(OperandIndex{init_param.outputs[n]});
+ }
+
+ operation::SplitV::Param param;
+ param.num_splits = operands.at(OperandIndex{init_param.inputs[3]}).asScalar<std::int32_t>();
+ return new operation::SplitV{inputs, outputs, param};
+ };
+
+ // ANEURALNETWORKS_SPLIT_EX is deprecated
+ // TODO Remove ANEURALNETWORKS_SPLIT_EX
+ _map[ANEURALNETWORKS_SPLIT_EX] = _map[ANEURALNETWORKS_SPLIT];
+
+ _map[ANEURALNETWORKS_UNPACK_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 3 && init_param.output_count >= 1);
+
+ OperandIndexSequence inputs{init_param.inputs[0]};
+ OperandIndexSequence outputs;
+ for (uint32_t n = 0; n < init_param.output_count; ++n)
+ {
+ outputs.append(OperandIndex{init_param.outputs[n]});
+ }
+
+ operation::Unpack::Param param;
+ const auto num_index = OperandIndex{init_param.inputs[1]};
+ const auto axis_index = OperandIndex{init_param.inputs[2]};
+ param.num = operands.at(num_index).asScalar<int32_t>();
+ param.axis = operands.at(axis_index).asScalar<int32_t>();
+
+ return new operation::Unpack{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_PAD] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count >= 2 && init_param.input_count <= 3 &&
+ init_param.output_count >= 1);
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+ if (init_param.input_count == 3)
+ {
+ inputs.append(OperandIndex{init_param.inputs[2]});
+ }
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ return new operation::Pad{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_PAD_V2] = _map[ANEURALNETWORKS_PAD];
+
+ _map[ANEURALNETWORKS_MINIMUM] =
+ getElementwiseBinaryGenerator(operation::ElementwiseBinary::ElementwiseBinaryType::MIN);
+
+ _map[ANEURALNETWORKS_MAXIMUM] =
+ getElementwiseBinaryGenerator(operation::ElementwiseBinary::ElementwiseBinaryType::MAX);
+
+ _map[ANEURALNETWORKS_ONE_HOT_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 5);
+ assert(init_param.output_count == 1);
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> indices tensor
+ // 1 -> depth tensor
+ // 2 -> on_value tensor
+ // 3 -> off_value tensor
+ // 4 -> axis scalar
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < init_param.input_count - 1; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::OneHot::Param param;
+ param.axis = operands.at(OperandIndex{init_param.inputs[4]}).asScalar<std::int32_t>();
+
+ return new operation::OneHot{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_COS_EX] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::COS);
+
+ _map[ANEURALNETWORKS_SIN] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::SIN);
+
+ _map[ANEURALNETWORKS_SHAPE_EX] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 1 && init_param.output_count == 1);
+
+ OperandIndexSequence inputs{init_param.inputs[0]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ return new operation::Shape{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_REDUCE_PROD] =
+ getReduceGenerator(onert::ir::operation::Reduce::ReduceType::PROD);
+
+ _map[ANEURALNETWORKS_ROUND_EX] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::ROUND);
+
+ _map[ANEURALNETWORKS_RANGE_EX] = [](const OperationFactory::Param &init_param, Operands &) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ // 0 -> start Tensor Index
+ // 1 -> limit Tensor Index
+ // 2 -> delta Tensor Index
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+
+ return new operation::Range{inputs, outputs};
+ };
+
+ // Each input should be interpreted as follows:
+ // 0 -> LHS Tensor Index
+ // 1 -> RHS Tensor Index
+ _map[ANEURALNETWORKS_POW] = createSimpleBinaryOp<operation::Pow>;
+
+ // Each input should be interpreted as follows:
+ // 0 -> A tensor, specifying the input.
+ // 1 -> A 1-D tensor, specifying the value
+ _map[ANEURALNETWORKS_FILL_EX] = createSimpleBinaryOp<operation::Fill>;
+
+ _map[ANEURALNETWORKS_ZEROS_LIKE_EX] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::ZEROS_LIKE);
+ // Each input should be interpreted as follows:
+ // 0 -> Input Tensor Index
+ // 1 -> Multiple Tensor Index
+ _map[ANEURALNETWORKS_TILE] = createSimpleBinaryOp<operation::Tile>;
+
+ _map[ANEURALNETWORKS_MATRIX_BAND_PART_EX] = [](const OperationFactory::Param &init_param,
+ Operands &) {
+ assert(init_param.input_count == 3);
+ assert(init_param.output_count == 1);
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> A tensor, input
+ // 1 -> A 0-D tensor, number of lower diagnonals to keep
+ // 2 -> A 0-D tensor, number of upper diagnonals to keep
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ return new operation::MatrixBandPart{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_BATCH_MATMUL_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 4 && init_param.output_count == 1);
+
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Lhs Tensor Index
+ // 1 -> Rhs Tensor Index
+ // 2 -> adj_x boolean scalar Index
+ // 3 -> adj_y boolean scalar Index
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ operation::BatchMatMul::Param param;
+ param.adj_x = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<bool>();
+ param.adj_y = operands.at(OperandIndex{init_param.inputs[3]}).asScalar<bool>();
+
+ return new operation::BatchMatMul{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_EINSUM_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ // Each input should be interpreted as follows:
+ //
+ // 0....n - 1 -> n Input Tensors Index
+ // n -> equation
+ assert(init_param.input_count >= 1 && init_param.output_count == 1);
+
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < init_param.input_count - 1; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::Einsum::Param param;
+ const OperandIndex equation_index{init_param.inputs[init_param.input_count - 1]};
+ std::vector<char> equation_vector = operands.at(equation_index).asVector<char>();
+ param.equation = std::string(equation_vector.begin(), equation_vector.end());
+
+ return new operation::Einsum{inputs, outputs, param};
+ };
+
+ // 0 -> Input Tensor Index
+ // 1 -> int32, int64, An 1-D int tensor Index
+ _map[ANEURALNETWORKS_BROADCAST_TO_EX] = createSimpleBinaryOp<operation::BroadcastTo>;
+
+ _map[ANEURALNETWORKS_STATELESS_RANDOM_UNIFORM_EX] = [](const OperationFactory::Param &init_param,
+ Operands &) {
+ assert(init_param.input_count == 2 && init_param.output_count == 1);
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Shape Tensor Index
+ // 1 -> int32, int64, An 1-D int tensor Index
+
+ OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]};
+
+ return new operation::StatelessRandomUniform{inputs, outputs};
+ };
+
+ _map[ANEURALNETWORKS_FUSED_BATCH_NORM_V3_EX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ // Each input should be interpreted as follows:
+ //
+ // 0....4 -> 5 Input Tensors Index
+ // n-2 -> is_training
+ // n-1 -> data_format
+ // n -> epsilon
+
+ assert(init_param.input_count == 8 && init_param.output_count == 1);
+
+ OperandIndexSequence inputs;
+ for (uint32_t n = 0; n < init_param.input_count - 3; ++n)
+ {
+ inputs.append(OperandIndex{init_param.inputs[n]});
+ }
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ operation::FusedBatchNorm::Param param;
+ const OperandIndex is_training_index{init_param.inputs[init_param.input_count - 3]};
+ param.is_training = operands.at(is_training_index).asScalar<bool>();
+
+ const OperandIndex data_format_index{init_param.inputs[init_param.input_count - 2]};
+ std::vector<char> data_format_vector = operands.at(data_format_index).asVector<char>();
+ param.data_format = std::string(data_format_vector.begin(), data_format_vector.end());
+
+ const OperandIndex epsilon_index{init_param.inputs[init_param.input_count - 1]};
+ param.epsilon = operands.at(epsilon_index).asScalar<float>();
+ return new operation::FusedBatchNorm{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_LOG_SOFTMAX] = [](const OperationFactory::Param &init_param,
+ Operands &operands) {
+ assert(init_param.input_count == 3 && init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> A tensor specifying the input logits.
+ // 1 -> A scalar, specifying the positive scaling factor for the exponent, beta.
+ // 2 -> An scalar specifying the axis to reduce across.
+
+ OperandIndexSequence inputs{init_param.inputs[0]};
+ OperandIndexSequence outputs{init_param.outputs[0]};
+
+ const auto beta_index = OperandIndex{init_param.inputs[1]};
+ const auto axis_index = OperandIndex{init_param.inputs[2]};
+
+ operation::LogSoftmax::Param param;
+ param.beta = operands.at(beta_index).asScalar<float>();
+ param.axis = operands.at(axis_index).asScalar<int>();
+
+ return new operation::LogSoftmax{inputs, outputs, param};
+ };
+
+ _map[ANEURALNETWORKS_QUANTIZE] =
+ getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::QUANTIZE);
+}
+
+Operation *OperationFactory::create(ANeuralNetworksOperationType type,
+ const OperationFactory::Param &param, Operands &operands)
+{
+ auto it = _map.find(type);
+ if (it == _map.end())
+ {
+ throw std::runtime_error("Unsupported operation type: " + std::to_string(type));
+ }
+ return it->second(param, operands);
+}
diff --git a/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h
new file mode 100644
index 000000000..367cf74db
--- /dev/null
+++ b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OPERATION_FACTORY_H__
+#define __OPERATION_FACTORY_H__
+
+#include <unordered_map>
+
+#include "ir/Operands.h"
+#include "ir/Operation.h"
+#include "NeuralNetworks.h"
+#include "NeuralNetworksEx.h"
+
+/**
+ * @brief A class to create a onert operation object from NN API input parameters
+ */
+class OperationFactory
+{
+public:
+ struct Param
+ {
+ uint32_t input_count;
+ const uint32_t *inputs;
+ uint32_t output_count;
+ const uint32_t *outputs;
+ };
+
+public:
+ using Generator =
+ std::function<onert::ir::Operation *(const OperationFactory::Param &, onert::ir::Operands &)>;
+
+public:
+ static OperationFactory &get();
+
+private:
+ OperationFactory();
+
+public:
+ onert::ir::Operation *create(ANeuralNetworksOperationType, const OperationFactory::Param &param,
+ onert::ir::Operands &operands);
+ // TODO add "register" method for separating registration, possibly supporting custom-ops
+
+private:
+ std::unordered_map<ANeuralNetworksOperationType, Generator> _map;
+};
+
+#endif // __OPERATION_FACTORY_H__
diff --git a/runtime/onert/frontend/tflite/CMakeLists.txt b/runtime/onert/frontend/tflite/CMakeLists.txt
new file mode 100644
index 000000000..e84eb3e3e
--- /dev/null
+++ b/runtime/onert/frontend/tflite/CMakeLists.txt
@@ -0,0 +1,19 @@
+if(NOT BUILD_TFLITE_LOADER)
+ return()
+endif(NOT BUILD_TFLITE_LOADER)
+
+set(TFLITE_LOADER_SOURCES src/tflite_loader.cc)
+
+add_library(tflite_loader SHARED ${TFLITE_LOADER_SOURCES})
+
+target_include_directories(tflite_loader PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+target_link_libraries(tflite_loader PRIVATE onert_core)
+target_link_libraries(tflite_loader PRIVATE base_loader nnfw_common nnfw_coverage)
+
+if(CMAKE_BUILD_TYPE_LC STREQUAL "release")
+ add_custom_command(TARGET tflite_loader POST_BUILD
+ COMMAND ${CMAKE_STRIP} "--strip-unneeded" $<TARGET_FILE_NAME:tflite_loader>)
+endif()
+
+install(TARGETS tflite_loader DESTINATION lib)
diff --git a/runtime/onert/frontend/tflite/include/tflite_loader.h b/runtime/onert/frontend/tflite/include/tflite_loader.h
new file mode 100644
index 000000000..743c05f9e
--- /dev/null
+++ b/runtime/onert/frontend/tflite/include/tflite_loader.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TFLITE_TFLITE_LOADER_H__
+#define __TFLITE_TFLITE_LOADER_H__
+
+#include "ir/Graph.h"
+
+#include <memory>
+
+namespace onert
+{
+namespace tflite_loader
+{
+
+std::unique_ptr<ir::Subgraphs> loadModel(const char *filename);
+
+} // namespace tflite_loader
+} // namespace onert
+
+#endif // __TFLITE_TFLITE_LOADER_H__
diff --git a/runtime/onert/frontend/tflite/src/tflite_loader.cc b/runtime/onert/frontend/tflite/src/tflite_loader.cc
new file mode 100644
index 000000000..91919a0a2
--- /dev/null
+++ b/runtime/onert/frontend/tflite/src/tflite_loader.cc
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tflite_loader.h"
+#include "base_loader.h"
+#include "tflite_schema_generated.h"
+
+namespace onert
+{
+namespace tflite_loader
+{
+
+namespace
+{
+
+struct LoaderDomain
+{
+ using Verifier = flatbuffers::Verifier;
+ using ActivationFunctionType = onert_tflite::ActivationFunctionType;
+ using Buffer = onert_tflite::Buffer;
+ using BuiltinOperator = onert_tflite::BuiltinOperator;
+ using CustomOptionsFormat = onert_tflite::CustomOptionsFormat;
+ using Model = onert_tflite::Model;
+ using Operator = onert_tflite::Operator;
+ using Padding = onert_tflite::Padding;
+ using Pool2DOptions = onert_tflite::Pool2DOptions;
+ using Tensor = onert_tflite::Tensor;
+ using TensorType = onert_tflite::TensorType;
+ using SubGraph = onert_tflite::SubGraph;
+ using DimensionType = onert_tflite::DimensionType;
+ using SparseIndexVector = onert_tflite::SparseIndexVector;
+
+ static const char *EnumNameBuiltinOperator(BuiltinOperator e)
+ {
+ return onert_tflite::EnumNameBuiltinOperator(e);
+ }
+ static const char *EnumNameActivationFunctionType(ActivationFunctionType e)
+ {
+ return onert_tflite::EnumNameActivationFunctionType(e);
+ }
+ static const char *EnumNameTensorType(TensorType e)
+ {
+ return onert_tflite::EnumNameTensorType(e);
+ }
+ static const Model *GetModel(const void *buf) { return onert_tflite::GetModel(buf); }
+ static bool VerifyModelBuffer(Verifier &verifier)
+ {
+ return onert_tflite::VerifyModelBuffer(verifier);
+ }
+};
+
+class TFLiteLoader final : public base_loader::BaseLoader<LoaderDomain>
+{
+public:
+ using BaseLoader::BaseLoader;
+
+ bool allowOptionalInputTensor(BuiltinOperator op) override
+ {
+ switch (op)
+ {
+ case BuiltinOperator::BuiltinOperator_FULLY_CONNECTED:
+ case BuiltinOperator::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+private:
+ std::unique_ptr<ir::Graph> loadSubgraph(const onert_tflite::SubGraph *tflite_subg) override
+ {
+ auto subg = std::make_unique<ir::Graph>();
+ // Load tensors
+ _tensor_to_operand.resize(tflite_subg->tensors()->size());
+ for (flatbuffers::uoffset_t i = 0; i < tflite_subg->tensors()->size(); ++i)
+ {
+ _tensor_to_operand[i] = loadOperand(tflite_subg->tensors()->Get(i), *subg);
+ }
+ // Set inputs
+ for (const std::int32_t input_ind : *tflite_subg->inputs())
+ {
+ subg->addInput(tensorIdxToOperandIdx(input_ind),
+ _tensor_names.at(_tensor_to_operand[input_ind]));
+ }
+ // Set outputs
+ for (const std::int32_t output_ind : *tflite_subg->outputs())
+ {
+ subg->addOutput(tensorIdxToOperandIdx(output_ind),
+ _tensor_names.at(_tensor_to_operand[output_ind]));
+ }
+ // Create operations
+ for (const auto *op : *tflite_subg->operators())
+ {
+ loadOperation(op, *subg);
+ }
+
+ subg->finishBuilding();
+
+ return subg;
+ }
+};
+
+} // namespace
+
+std::unique_ptr<ir::Subgraphs> loadModel(const char *filename)
+{
+ auto subgraphs = std::make_unique<ir::Subgraphs>();
+ TFLiteLoader loader(subgraphs);
+ loader.loadFromFile(filename);
+ return subgraphs;
+}
+
+} // namespace tflite_loader
+} // namespace onert
diff --git a/runtime/onert/frontend/tflite/src/tflite_schema_generated.h b/runtime/onert/frontend/tflite/src/tflite_schema_generated.h
new file mode 100644
index 000000000..c6e9147cd
--- /dev/null
+++ b/runtime/onert/frontend/tflite/src/tflite_schema_generated.h
@@ -0,0 +1,9553 @@
+/*
+ * Copyright (c) 2019-2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// automatically generated by the FlatBuffers compiler, do not modify
+
+#ifndef FLATBUFFERS_GENERATED_TFLITESCHEMA_ONERT_TFLITE_H_
+#define FLATBUFFERS_GENERATED_TFLITESCHEMA_ONERT_TFLITE_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace onert_tflite
+{
+
+struct CustomQuantization;
+
+struct QuantizationParameters;
+
+struct Int32Vector;
+
+struct Uint16Vector;
+
+struct Uint8Vector;
+
+struct DimensionMetadata;
+
+struct SparsityParameters;
+
+struct Tensor;
+
+struct Conv2DOptions;
+
+struct Pool2DOptions;
+
+struct DepthwiseConv2DOptions;
+
+struct ConcatEmbeddingsOptions;
+
+struct LSHProjectionOptions;
+
+struct SVDFOptions;
+
+struct RNNOptions;
+
+struct SequenceRNNOptions;
+
+struct BidirectionalSequenceRNNOptions;
+
+struct FullyConnectedOptions;
+
+struct SoftmaxOptions;
+
+struct ConcatenationOptions;
+
+struct AddOptions;
+
+struct MulOptions;
+
+struct L2NormOptions;
+
+struct LocalResponseNormalizationOptions;
+
+struct LSTMOptions;
+
+struct UnidirectionalSequenceLSTMOptions;
+
+struct BidirectionalSequenceLSTMOptions;
+
+struct ResizeBilinearOptions;
+
+struct ResizeNearestNeighborOptions;
+
+struct CallOptions;
+
+struct PadOptions;
+
+struct PadV2Options;
+
+struct ReshapeOptions;
+
+struct SpaceToBatchNDOptions;
+
+struct BatchToSpaceNDOptions;
+
+struct SkipGramOptions;
+
+struct SpaceToDepthOptions;
+
+struct DepthToSpaceOptions;
+
+struct SubOptions;
+
+struct DivOptions;
+
+struct TopKV2Options;
+
+struct EmbeddingLookupSparseOptions;
+
+struct GatherOptions;
+
+struct TransposeOptions;
+
+struct ExpOptions;
+
+struct CosOptions;
+
+struct ReducerOptions;
+
+struct SqueezeOptions;
+
+struct SplitOptions;
+
+struct SplitVOptions;
+
+struct StridedSliceOptions;
+
+struct LogSoftmaxOptions;
+
+struct CastOptions;
+
+struct DequantizeOptions;
+
+struct MaximumMinimumOptions;
+
+struct TileOptions;
+
+struct ArgMaxOptions;
+
+struct ArgMinOptions;
+
+struct GreaterOptions;
+
+struct GreaterEqualOptions;
+
+struct LessOptions;
+
+struct LessEqualOptions;
+
+struct NegOptions;
+
+struct SelectOptions;
+
+struct SliceOptions;
+
+struct TransposeConvOptions;
+
+struct ExpandDimsOptions;
+
+struct SparseToDenseOptions;
+
+struct EqualOptions;
+
+struct NotEqualOptions;
+
+struct ShapeOptions;
+
+struct RankOptions;
+
+struct PowOptions;
+
+struct FakeQuantOptions;
+
+struct PackOptions;
+
+struct LogicalOrOptions;
+
+struct OneHotOptions;
+
+struct AbsOptions;
+
+struct HardSwishOptions;
+
+struct LogicalAndOptions;
+
+struct LogicalNotOptions;
+
+struct UnpackOptions;
+
+struct FloorDivOptions;
+
+struct SquareOptions;
+
+struct ZerosLikeOptions;
+
+struct FillOptions;
+
+struct FloorModOptions;
+
+struct RangeOptions;
+
+struct LeakyReluOptions;
+
+struct SquaredDifferenceOptions;
+
+struct MirrorPadOptions;
+
+struct UniqueOptions;
+
+struct ReverseV2Options;
+
+struct AddNOptions;
+
+struct GatherNdOptions;
+
+struct WhereOptions;
+
+struct ReverseSequenceOptions;
+
+struct MatrixDiagOptions;
+
+struct QuantizeOptions;
+
+struct MatrixSetDiagOptions;
+
+struct IfOptions;
+
+struct WhileOptions;
+
+struct NonMaxSuppressionV4Options;
+
+struct NonMaxSuppressionV5Options;
+
+struct ScatterNdOptions;
+
+struct SelectV2Options;
+
+struct DensifyOptions;
+
+struct SegmentSumOptions;
+
+struct BatchMatMulOptions;
+
+struct OperatorCode;
+
+struct Operator;
+
+struct SubGraph;
+
+struct Buffer;
+
+struct Metadata;
+
+struct Model;
+
+enum TensorType
+{
+ TensorType_FLOAT32 = 0,
+ TensorType_FLOAT16 = 1,
+ TensorType_INT32 = 2,
+ TensorType_UINT8 = 3,
+ TensorType_INT64 = 4,
+ TensorType_STRING = 5,
+ TensorType_BOOL = 6,
+ TensorType_INT16 = 7,
+ TensorType_COMPLEX64 = 8,
+ TensorType_INT8 = 9,
+ TensorType_FLOAT64 = 10,
+ TensorType_MIN = TensorType_FLOAT32,
+ TensorType_MAX = TensorType_FLOAT64
+};
+
+inline const TensorType (&EnumValuesTensorType())[11]
+{
+ static const TensorType values[] = {TensorType_FLOAT32, TensorType_FLOAT16, TensorType_INT32,
+ TensorType_UINT8, TensorType_INT64, TensorType_STRING,
+ TensorType_BOOL, TensorType_INT16, TensorType_COMPLEX64,
+ TensorType_INT8, TensorType_FLOAT64};
+ return values;
+}
+
+inline const char *const *EnumNamesTensorType()
+{
+ static const char *const names[] = {"FLOAT32", "FLOAT16", "INT32", "UINT8",
+ "INT64", "STRING", "BOOL", "INT16",
+ "COMPLEX64", "INT8", "FLOAT64", nullptr};
+ return names;
+}
+
+inline const char *EnumNameTensorType(TensorType e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesTensorType()[index];
+}
+
+enum QuantizationDetails
+{
+ QuantizationDetails_NONE = 0,
+ QuantizationDetails_CustomQuantization = 1,
+ QuantizationDetails_MIN = QuantizationDetails_NONE,
+ QuantizationDetails_MAX = QuantizationDetails_CustomQuantization
+};
+
+inline const QuantizationDetails (&EnumValuesQuantizationDetails())[2]
+{
+ static const QuantizationDetails values[] = {QuantizationDetails_NONE,
+ QuantizationDetails_CustomQuantization};
+ return values;
+}
+
+inline const char *const *EnumNamesQuantizationDetails()
+{
+ static const char *const names[] = {"NONE", "CustomQuantization", nullptr};
+ return names;
+}
+
+inline const char *EnumNameQuantizationDetails(QuantizationDetails e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesQuantizationDetails()[index];
+}
+
+template <typename T> struct QuantizationDetailsTraits
+{
+ static const QuantizationDetails enum_value = QuantizationDetails_NONE;
+};
+
+template <> struct QuantizationDetailsTraits<CustomQuantization>
+{
+ static const QuantizationDetails enum_value = QuantizationDetails_CustomQuantization;
+};
+
+bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj,
+ QuantizationDetails type);
+bool VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types);
+
+enum DimensionType
+{
+ DimensionType_DENSE = 0,
+ DimensionType_SPARSE_CSR = 1,
+ DimensionType_MIN = DimensionType_DENSE,
+ DimensionType_MAX = DimensionType_SPARSE_CSR
+};
+
+inline const DimensionType (&EnumValuesDimensionType())[2]
+{
+ static const DimensionType values[] = {DimensionType_DENSE, DimensionType_SPARSE_CSR};
+ return values;
+}
+
+inline const char *const *EnumNamesDimensionType()
+{
+ static const char *const names[] = {"DENSE", "SPARSE_CSR", nullptr};
+ return names;
+}
+
+inline const char *EnumNameDimensionType(DimensionType e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesDimensionType()[index];
+}
+
+enum SparseIndexVector
+{
+ SparseIndexVector_NONE = 0,
+ SparseIndexVector_Int32Vector = 1,
+ SparseIndexVector_Uint16Vector = 2,
+ SparseIndexVector_Uint8Vector = 3,
+ SparseIndexVector_MIN = SparseIndexVector_NONE,
+ SparseIndexVector_MAX = SparseIndexVector_Uint8Vector
+};
+
+inline const SparseIndexVector (&EnumValuesSparseIndexVector())[4]
+{
+ static const SparseIndexVector values[] = {SparseIndexVector_NONE, SparseIndexVector_Int32Vector,
+ SparseIndexVector_Uint16Vector,
+ SparseIndexVector_Uint8Vector};
+ return values;
+}
+
+inline const char *const *EnumNamesSparseIndexVector()
+{
+ static const char *const names[] = {"NONE", "Int32Vector", "Uint16Vector", "Uint8Vector",
+ nullptr};
+ return names;
+}
+
+inline const char *EnumNameSparseIndexVector(SparseIndexVector e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesSparseIndexVector()[index];
+}
+
+template <typename T> struct SparseIndexVectorTraits
+{
+ static const SparseIndexVector enum_value = SparseIndexVector_NONE;
+};
+
+template <> struct SparseIndexVectorTraits<Int32Vector>
+{
+ static const SparseIndexVector enum_value = SparseIndexVector_Int32Vector;
+};
+
+template <> struct SparseIndexVectorTraits<Uint16Vector>
+{
+ static const SparseIndexVector enum_value = SparseIndexVector_Uint16Vector;
+};
+
+template <> struct SparseIndexVectorTraits<Uint8Vector>
+{
+ static const SparseIndexVector enum_value = SparseIndexVector_Uint8Vector;
+};
+
+bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj,
+ SparseIndexVector type);
+bool VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types);
+
+enum BuiltinOperator
+{
+ BuiltinOperator_ADD = 0,
+ BuiltinOperator_AVERAGE_POOL_2D = 1,
+ BuiltinOperator_CONCATENATION = 2,
+ BuiltinOperator_CONV_2D = 3,
+ BuiltinOperator_DEPTHWISE_CONV_2D = 4,
+ BuiltinOperator_DEPTH_TO_SPACE = 5,
+ BuiltinOperator_DEQUANTIZE = 6,
+ BuiltinOperator_EMBEDDING_LOOKUP = 7,
+ BuiltinOperator_FLOOR = 8,
+ BuiltinOperator_FULLY_CONNECTED = 9,
+ BuiltinOperator_HASHTABLE_LOOKUP = 10,
+ BuiltinOperator_L2_NORMALIZATION = 11,
+ BuiltinOperator_L2_POOL_2D = 12,
+ BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION = 13,
+ BuiltinOperator_LOGISTIC = 14,
+ BuiltinOperator_LSH_PROJECTION = 15,
+ BuiltinOperator_LSTM = 16,
+ BuiltinOperator_MAX_POOL_2D = 17,
+ BuiltinOperator_MUL = 18,
+ BuiltinOperator_RELU = 19,
+ BuiltinOperator_RELU_N1_TO_1 = 20,
+ BuiltinOperator_RELU6 = 21,
+ BuiltinOperator_RESHAPE = 22,
+ BuiltinOperator_RESIZE_BILINEAR = 23,
+ BuiltinOperator_RNN = 24,
+ BuiltinOperator_SOFTMAX = 25,
+ BuiltinOperator_SPACE_TO_DEPTH = 26,
+ BuiltinOperator_SVDF = 27,
+ BuiltinOperator_TANH = 28,
+ BuiltinOperator_CONCAT_EMBEDDINGS = 29,
+ BuiltinOperator_SKIP_GRAM = 30,
+ BuiltinOperator_CALL = 31,
+ BuiltinOperator_CUSTOM = 32,
+ BuiltinOperator_EMBEDDING_LOOKUP_SPARSE = 33,
+ BuiltinOperator_PAD = 34,
+ BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN = 35,
+ BuiltinOperator_GATHER = 36,
+ BuiltinOperator_BATCH_TO_SPACE_ND = 37,
+ BuiltinOperator_SPACE_TO_BATCH_ND = 38,
+ BuiltinOperator_TRANSPOSE = 39,
+ BuiltinOperator_MEAN = 40,
+ BuiltinOperator_SUB = 41,
+ BuiltinOperator_DIV = 42,
+ BuiltinOperator_SQUEEZE = 43,
+ BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44,
+ BuiltinOperator_STRIDED_SLICE = 45,
+ BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN = 46,
+ BuiltinOperator_EXP = 47,
+ BuiltinOperator_TOPK_V2 = 48,
+ BuiltinOperator_SPLIT = 49,
+ BuiltinOperator_LOG_SOFTMAX = 50,
+ BuiltinOperator_DELEGATE = 51,
+ BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM = 52,
+ BuiltinOperator_CAST = 53,
+ BuiltinOperator_PRELU = 54,
+ BuiltinOperator_MAXIMUM = 55,
+ BuiltinOperator_ARG_MAX = 56,
+ BuiltinOperator_MINIMUM = 57,
+ BuiltinOperator_LESS = 58,
+ BuiltinOperator_NEG = 59,
+ BuiltinOperator_PADV2 = 60,
+ BuiltinOperator_GREATER = 61,
+ BuiltinOperator_GREATER_EQUAL = 62,
+ BuiltinOperator_LESS_EQUAL = 63,
+ BuiltinOperator_SELECT = 64,
+ BuiltinOperator_SLICE = 65,
+ BuiltinOperator_SIN = 66,
+ BuiltinOperator_TRANSPOSE_CONV = 67,
+ BuiltinOperator_SPARSE_TO_DENSE = 68,
+ BuiltinOperator_TILE = 69,
+ BuiltinOperator_EXPAND_DIMS = 70,
+ BuiltinOperator_EQUAL = 71,
+ BuiltinOperator_NOT_EQUAL = 72,
+ BuiltinOperator_LOG = 73,
+ BuiltinOperator_SUM = 74,
+ BuiltinOperator_SQRT = 75,
+ BuiltinOperator_RSQRT = 76,
+ BuiltinOperator_SHAPE = 77,
+ BuiltinOperator_POW = 78,
+ BuiltinOperator_ARG_MIN = 79,
+ BuiltinOperator_FAKE_QUANT = 80,
+ BuiltinOperator_REDUCE_PROD = 81,
+ BuiltinOperator_REDUCE_MAX = 82,
+ BuiltinOperator_PACK = 83,
+ BuiltinOperator_LOGICAL_OR = 84,
+ BuiltinOperator_ONE_HOT = 85,
+ BuiltinOperator_LOGICAL_AND = 86,
+ BuiltinOperator_LOGICAL_NOT = 87,
+ BuiltinOperator_UNPACK = 88,
+ BuiltinOperator_REDUCE_MIN = 89,
+ BuiltinOperator_FLOOR_DIV = 90,
+ BuiltinOperator_REDUCE_ANY = 91,
+ BuiltinOperator_SQUARE = 92,
+ BuiltinOperator_ZEROS_LIKE = 93,
+ BuiltinOperator_FILL = 94,
+ BuiltinOperator_FLOOR_MOD = 95,
+ BuiltinOperator_RANGE = 96,
+ BuiltinOperator_RESIZE_NEAREST_NEIGHBOR = 97,
+ BuiltinOperator_LEAKY_RELU = 98,
+ BuiltinOperator_SQUARED_DIFFERENCE = 99,
+ BuiltinOperator_MIRROR_PAD = 100,
+ BuiltinOperator_ABS = 101,
+ BuiltinOperator_SPLIT_V = 102,
+ BuiltinOperator_UNIQUE = 103,
+ BuiltinOperator_CEIL = 104,
+ BuiltinOperator_REVERSE_V2 = 105,
+ BuiltinOperator_ADD_N = 106,
+ BuiltinOperator_GATHER_ND = 107,
+ BuiltinOperator_COS = 108,
+ BuiltinOperator_WHERE = 109,
+ BuiltinOperator_RANK = 110,
+ BuiltinOperator_ELU = 111,
+ BuiltinOperator_REVERSE_SEQUENCE = 112,
+ BuiltinOperator_MATRIX_DIAG = 113,
+ BuiltinOperator_QUANTIZE = 114,
+ BuiltinOperator_MATRIX_SET_DIAG = 115,
+ BuiltinOperator_ROUND = 116,
+ BuiltinOperator_HARD_SWISH = 117,
+ BuiltinOperator_IF = 118,
+ BuiltinOperator_WHILE = 119,
+ BuiltinOperator_NON_MAX_SUPPRESSION_V4 = 120,
+ BuiltinOperator_NON_MAX_SUPPRESSION_V5 = 121,
+ BuiltinOperator_SCATTER_ND = 122,
+ BuiltinOperator_SELECT_V2 = 123,
+ BuiltinOperator_DENSIFY = 124,
+ BuiltinOperator_SEGMENT_SUM = 125,
+ BuiltinOperator_BATCH_MATMUL = 126,
+ BuiltinOperator_MIN = BuiltinOperator_ADD,
+ BuiltinOperator_MAX = BuiltinOperator_BATCH_MATMUL
+};
+
+inline const BuiltinOperator (&EnumValuesBuiltinOperator())[127]
+{
+ static const BuiltinOperator values[] = {BuiltinOperator_ADD,
+ BuiltinOperator_AVERAGE_POOL_2D,
+ BuiltinOperator_CONCATENATION,
+ BuiltinOperator_CONV_2D,
+ BuiltinOperator_DEPTHWISE_CONV_2D,
+ BuiltinOperator_DEPTH_TO_SPACE,
+ BuiltinOperator_DEQUANTIZE,
+ BuiltinOperator_EMBEDDING_LOOKUP,
+ BuiltinOperator_FLOOR,
+ BuiltinOperator_FULLY_CONNECTED,
+ BuiltinOperator_HASHTABLE_LOOKUP,
+ BuiltinOperator_L2_NORMALIZATION,
+ BuiltinOperator_L2_POOL_2D,
+ BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION,
+ BuiltinOperator_LOGISTIC,
+ BuiltinOperator_LSH_PROJECTION,
+ BuiltinOperator_LSTM,
+ BuiltinOperator_MAX_POOL_2D,
+ BuiltinOperator_MUL,
+ BuiltinOperator_RELU,
+ BuiltinOperator_RELU_N1_TO_1,
+ BuiltinOperator_RELU6,
+ BuiltinOperator_RESHAPE,
+ BuiltinOperator_RESIZE_BILINEAR,
+ BuiltinOperator_RNN,
+ BuiltinOperator_SOFTMAX,
+ BuiltinOperator_SPACE_TO_DEPTH,
+ BuiltinOperator_SVDF,
+ BuiltinOperator_TANH,
+ BuiltinOperator_CONCAT_EMBEDDINGS,
+ BuiltinOperator_SKIP_GRAM,
+ BuiltinOperator_CALL,
+ BuiltinOperator_CUSTOM,
+ BuiltinOperator_EMBEDDING_LOOKUP_SPARSE,
+ BuiltinOperator_PAD,
+ BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN,
+ BuiltinOperator_GATHER,
+ BuiltinOperator_BATCH_TO_SPACE_ND,
+ BuiltinOperator_SPACE_TO_BATCH_ND,
+ BuiltinOperator_TRANSPOSE,
+ BuiltinOperator_MEAN,
+ BuiltinOperator_SUB,
+ BuiltinOperator_DIV,
+ BuiltinOperator_SQUEEZE,
+ BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM,
+ BuiltinOperator_STRIDED_SLICE,
+ BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN,
+ BuiltinOperator_EXP,
+ BuiltinOperator_TOPK_V2,
+ BuiltinOperator_SPLIT,
+ BuiltinOperator_LOG_SOFTMAX,
+ BuiltinOperator_DELEGATE,
+ BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM,
+ BuiltinOperator_CAST,
+ BuiltinOperator_PRELU,
+ BuiltinOperator_MAXIMUM,
+ BuiltinOperator_ARG_MAX,
+ BuiltinOperator_MINIMUM,
+ BuiltinOperator_LESS,
+ BuiltinOperator_NEG,
+ BuiltinOperator_PADV2,
+ BuiltinOperator_GREATER,
+ BuiltinOperator_GREATER_EQUAL,
+ BuiltinOperator_LESS_EQUAL,
+ BuiltinOperator_SELECT,
+ BuiltinOperator_SLICE,
+ BuiltinOperator_SIN,
+ BuiltinOperator_TRANSPOSE_CONV,
+ BuiltinOperator_SPARSE_TO_DENSE,
+ BuiltinOperator_TILE,
+ BuiltinOperator_EXPAND_DIMS,
+ BuiltinOperator_EQUAL,
+ BuiltinOperator_NOT_EQUAL,
+ BuiltinOperator_LOG,
+ BuiltinOperator_SUM,
+ BuiltinOperator_SQRT,
+ BuiltinOperator_RSQRT,
+ BuiltinOperator_SHAPE,
+ BuiltinOperator_POW,
+ BuiltinOperator_ARG_MIN,
+ BuiltinOperator_FAKE_QUANT,
+ BuiltinOperator_REDUCE_PROD,
+ BuiltinOperator_REDUCE_MAX,
+ BuiltinOperator_PACK,
+ BuiltinOperator_LOGICAL_OR,
+ BuiltinOperator_ONE_HOT,
+ BuiltinOperator_LOGICAL_AND,
+ BuiltinOperator_LOGICAL_NOT,
+ BuiltinOperator_UNPACK,
+ BuiltinOperator_REDUCE_MIN,
+ BuiltinOperator_FLOOR_DIV,
+ BuiltinOperator_REDUCE_ANY,
+ BuiltinOperator_SQUARE,
+ BuiltinOperator_ZEROS_LIKE,
+ BuiltinOperator_FILL,
+ BuiltinOperator_FLOOR_MOD,
+ BuiltinOperator_RANGE,
+ BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
+ BuiltinOperator_LEAKY_RELU,
+ BuiltinOperator_SQUARED_DIFFERENCE,
+ BuiltinOperator_MIRROR_PAD,
+ BuiltinOperator_ABS,
+ BuiltinOperator_SPLIT_V,
+ BuiltinOperator_UNIQUE,
+ BuiltinOperator_CEIL,
+ BuiltinOperator_REVERSE_V2,
+ BuiltinOperator_ADD_N,
+ BuiltinOperator_GATHER_ND,
+ BuiltinOperator_COS,
+ BuiltinOperator_WHERE,
+ BuiltinOperator_RANK,
+ BuiltinOperator_ELU,
+ BuiltinOperator_REVERSE_SEQUENCE,
+ BuiltinOperator_MATRIX_DIAG,
+ BuiltinOperator_QUANTIZE,
+ BuiltinOperator_MATRIX_SET_DIAG,
+ BuiltinOperator_ROUND,
+ BuiltinOperator_HARD_SWISH,
+ BuiltinOperator_IF,
+ BuiltinOperator_WHILE,
+ BuiltinOperator_NON_MAX_SUPPRESSION_V4,
+ BuiltinOperator_NON_MAX_SUPPRESSION_V5,
+ BuiltinOperator_SCATTER_ND,
+ BuiltinOperator_SELECT_V2,
+ BuiltinOperator_DENSIFY,
+ BuiltinOperator_SEGMENT_SUM,
+ BuiltinOperator_BATCH_MATMUL};
+ return values;
+}
+
+inline const char *const *EnumNamesBuiltinOperator()
+{
+ static const char *const names[] = {"ADD",
+ "AVERAGE_POOL_2D",
+ "CONCATENATION",
+ "CONV_2D",
+ "DEPTHWISE_CONV_2D",
+ "DEPTH_TO_SPACE",
+ "DEQUANTIZE",
+ "EMBEDDING_LOOKUP",
+ "FLOOR",
+ "FULLY_CONNECTED",
+ "HASHTABLE_LOOKUP",
+ "L2_NORMALIZATION",
+ "L2_POOL_2D",
+ "LOCAL_RESPONSE_NORMALIZATION",
+ "LOGISTIC",
+ "LSH_PROJECTION",
+ "LSTM",
+ "MAX_POOL_2D",
+ "MUL",
+ "RELU",
+ "RELU_N1_TO_1",
+ "RELU6",
+ "RESHAPE",
+ "RESIZE_BILINEAR",
+ "RNN",
+ "SOFTMAX",
+ "SPACE_TO_DEPTH",
+ "SVDF",
+ "TANH",
+ "CONCAT_EMBEDDINGS",
+ "SKIP_GRAM",
+ "CALL",
+ "CUSTOM",
+ "EMBEDDING_LOOKUP_SPARSE",
+ "PAD",
+ "UNIDIRECTIONAL_SEQUENCE_RNN",
+ "GATHER",
+ "BATCH_TO_SPACE_ND",
+ "SPACE_TO_BATCH_ND",
+ "TRANSPOSE",
+ "MEAN",
+ "SUB",
+ "DIV",
+ "SQUEEZE",
+ "UNIDIRECTIONAL_SEQUENCE_LSTM",
+ "STRIDED_SLICE",
+ "BIDIRECTIONAL_SEQUENCE_RNN",
+ "EXP",
+ "TOPK_V2",
+ "SPLIT",
+ "LOG_SOFTMAX",
+ "DELEGATE",
+ "BIDIRECTIONAL_SEQUENCE_LSTM",
+ "CAST",
+ "PRELU",
+ "MAXIMUM",
+ "ARG_MAX",
+ "MINIMUM",
+ "LESS",
+ "NEG",
+ "PADV2",
+ "GREATER",
+ "GREATER_EQUAL",
+ "LESS_EQUAL",
+ "SELECT",
+ "SLICE",
+ "SIN",
+ "TRANSPOSE_CONV",
+ "SPARSE_TO_DENSE",
+ "TILE",
+ "EXPAND_DIMS",
+ "EQUAL",
+ "NOT_EQUAL",
+ "LOG",
+ "SUM",
+ "SQRT",
+ "RSQRT",
+ "SHAPE",
+ "POW",
+ "ARG_MIN",
+ "FAKE_QUANT",
+ "REDUCE_PROD",
+ "REDUCE_MAX",
+ "PACK",
+ "LOGICAL_OR",
+ "ONE_HOT",
+ "LOGICAL_AND",
+ "LOGICAL_NOT",
+ "UNPACK",
+ "REDUCE_MIN",
+ "FLOOR_DIV",
+ "REDUCE_ANY",
+ "SQUARE",
+ "ZEROS_LIKE",
+ "FILL",
+ "FLOOR_MOD",
+ "RANGE",
+ "RESIZE_NEAREST_NEIGHBOR",
+ "LEAKY_RELU",
+ "SQUARED_DIFFERENCE",
+ "MIRROR_PAD",
+ "ABS",
+ "SPLIT_V",
+ "UNIQUE",
+ "CEIL",
+ "REVERSE_V2",
+ "ADD_N",
+ "GATHER_ND",
+ "COS",
+ "WHERE",
+ "RANK",
+ "ELU",
+ "REVERSE_SEQUENCE",
+ "MATRIX_DIAG",
+ "QUANTIZE",
+ "MATRIX_SET_DIAG",
+ "ROUND",
+ "HARD_SWISH",
+ "IF",
+ "WHILE",
+ "NON_MAX_SUPPRESSION_V4",
+ "NON_MAX_SUPPRESSION_V5",
+ "SCATTER_ND",
+ "SELECT_V2",
+ "DENSIFY",
+ "SEGMENT_SUM",
+ "BATCH_MATMUL",
+ nullptr};
+ return names;
+}
+
+inline const char *EnumNameBuiltinOperator(BuiltinOperator e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesBuiltinOperator()[index];
+}
+
+enum BuiltinOptions
+{
+ BuiltinOptions_NONE = 0,
+ BuiltinOptions_Conv2DOptions = 1,
+ BuiltinOptions_DepthwiseConv2DOptions = 2,
+ BuiltinOptions_ConcatEmbeddingsOptions = 3,
+ BuiltinOptions_LSHProjectionOptions = 4,
+ BuiltinOptions_Pool2DOptions = 5,
+ BuiltinOptions_SVDFOptions = 6,
+ BuiltinOptions_RNNOptions = 7,
+ BuiltinOptions_FullyConnectedOptions = 8,
+ BuiltinOptions_SoftmaxOptions = 9,
+ BuiltinOptions_ConcatenationOptions = 10,
+ BuiltinOptions_AddOptions = 11,
+ BuiltinOptions_L2NormOptions = 12,
+ BuiltinOptions_LocalResponseNormalizationOptions = 13,
+ BuiltinOptions_LSTMOptions = 14,
+ BuiltinOptions_ResizeBilinearOptions = 15,
+ BuiltinOptions_CallOptions = 16,
+ BuiltinOptions_ReshapeOptions = 17,
+ BuiltinOptions_SkipGramOptions = 18,
+ BuiltinOptions_SpaceToDepthOptions = 19,
+ BuiltinOptions_EmbeddingLookupSparseOptions = 20,
+ BuiltinOptions_MulOptions = 21,
+ BuiltinOptions_PadOptions = 22,
+ BuiltinOptions_GatherOptions = 23,
+ BuiltinOptions_BatchToSpaceNDOptions = 24,
+ BuiltinOptions_SpaceToBatchNDOptions = 25,
+ BuiltinOptions_TransposeOptions = 26,
+ BuiltinOptions_ReducerOptions = 27,
+ BuiltinOptions_SubOptions = 28,
+ BuiltinOptions_DivOptions = 29,
+ BuiltinOptions_SqueezeOptions = 30,
+ BuiltinOptions_SequenceRNNOptions = 31,
+ BuiltinOptions_StridedSliceOptions = 32,
+ BuiltinOptions_ExpOptions = 33,
+ BuiltinOptions_TopKV2Options = 34,
+ BuiltinOptions_SplitOptions = 35,
+ BuiltinOptions_LogSoftmaxOptions = 36,
+ BuiltinOptions_CastOptions = 37,
+ BuiltinOptions_DequantizeOptions = 38,
+ BuiltinOptions_MaximumMinimumOptions = 39,
+ BuiltinOptions_ArgMaxOptions = 40,
+ BuiltinOptions_LessOptions = 41,
+ BuiltinOptions_NegOptions = 42,
+ BuiltinOptions_PadV2Options = 43,
+ BuiltinOptions_GreaterOptions = 44,
+ BuiltinOptions_GreaterEqualOptions = 45,
+ BuiltinOptions_LessEqualOptions = 46,
+ BuiltinOptions_SelectOptions = 47,
+ BuiltinOptions_SliceOptions = 48,
+ BuiltinOptions_TransposeConvOptions = 49,
+ BuiltinOptions_SparseToDenseOptions = 50,
+ BuiltinOptions_TileOptions = 51,
+ BuiltinOptions_ExpandDimsOptions = 52,
+ BuiltinOptions_EqualOptions = 53,
+ BuiltinOptions_NotEqualOptions = 54,
+ BuiltinOptions_ShapeOptions = 55,
+ BuiltinOptions_PowOptions = 56,
+ BuiltinOptions_ArgMinOptions = 57,
+ BuiltinOptions_FakeQuantOptions = 58,
+ BuiltinOptions_PackOptions = 59,
+ BuiltinOptions_LogicalOrOptions = 60,
+ BuiltinOptions_OneHotOptions = 61,
+ BuiltinOptions_LogicalAndOptions = 62,
+ BuiltinOptions_LogicalNotOptions = 63,
+ BuiltinOptions_UnpackOptions = 64,
+ BuiltinOptions_FloorDivOptions = 65,
+ BuiltinOptions_SquareOptions = 66,
+ BuiltinOptions_ZerosLikeOptions = 67,
+ BuiltinOptions_FillOptions = 68,
+ BuiltinOptions_BidirectionalSequenceLSTMOptions = 69,
+ BuiltinOptions_BidirectionalSequenceRNNOptions = 70,
+ BuiltinOptions_UnidirectionalSequenceLSTMOptions = 71,
+ BuiltinOptions_FloorModOptions = 72,
+ BuiltinOptions_RangeOptions = 73,
+ BuiltinOptions_ResizeNearestNeighborOptions = 74,
+ BuiltinOptions_LeakyReluOptions = 75,
+ BuiltinOptions_SquaredDifferenceOptions = 76,
+ BuiltinOptions_MirrorPadOptions = 77,
+ BuiltinOptions_AbsOptions = 78,
+ BuiltinOptions_SplitVOptions = 79,
+ BuiltinOptions_UniqueOptions = 80,
+ BuiltinOptions_ReverseV2Options = 81,
+ BuiltinOptions_AddNOptions = 82,
+ BuiltinOptions_GatherNdOptions = 83,
+ BuiltinOptions_CosOptions = 84,
+ BuiltinOptions_WhereOptions = 85,
+ BuiltinOptions_RankOptions = 86,
+ BuiltinOptions_ReverseSequenceOptions = 87,
+ BuiltinOptions_MatrixDiagOptions = 88,
+ BuiltinOptions_QuantizeOptions = 89,
+ BuiltinOptions_MatrixSetDiagOptions = 90,
+ BuiltinOptions_HardSwishOptions = 91,
+ BuiltinOptions_IfOptions = 92,
+ BuiltinOptions_WhileOptions = 93,
+ BuiltinOptions_DepthToSpaceOptions = 94,
+ BuiltinOptions_NonMaxSuppressionV4Options = 95,
+ BuiltinOptions_NonMaxSuppressionV5Options = 96,
+ BuiltinOptions_ScatterNdOptions = 97,
+ BuiltinOptions_SelectV2Options = 98,
+ BuiltinOptions_DensifyOptions = 99,
+ BuiltinOptions_SegmentSumOptions = 100,
+ BuiltinOptions_BatchMatMulOptions = 101,
+ BuiltinOptions_MIN = BuiltinOptions_NONE,
+ BuiltinOptions_MAX = BuiltinOptions_BatchMatMulOptions
+};
+
+inline const BuiltinOptions (&EnumValuesBuiltinOptions())[102]
+{
+ static const BuiltinOptions values[] = {BuiltinOptions_NONE,
+ BuiltinOptions_Conv2DOptions,
+ BuiltinOptions_DepthwiseConv2DOptions,
+ BuiltinOptions_ConcatEmbeddingsOptions,
+ BuiltinOptions_LSHProjectionOptions,
+ BuiltinOptions_Pool2DOptions,
+ BuiltinOptions_SVDFOptions,
+ BuiltinOptions_RNNOptions,
+ BuiltinOptions_FullyConnectedOptions,
+ BuiltinOptions_SoftmaxOptions,
+ BuiltinOptions_ConcatenationOptions,
+ BuiltinOptions_AddOptions,
+ BuiltinOptions_L2NormOptions,
+ BuiltinOptions_LocalResponseNormalizationOptions,
+ BuiltinOptions_LSTMOptions,
+ BuiltinOptions_ResizeBilinearOptions,
+ BuiltinOptions_CallOptions,
+ BuiltinOptions_ReshapeOptions,
+ BuiltinOptions_SkipGramOptions,
+ BuiltinOptions_SpaceToDepthOptions,
+ BuiltinOptions_EmbeddingLookupSparseOptions,
+ BuiltinOptions_MulOptions,
+ BuiltinOptions_PadOptions,
+ BuiltinOptions_GatherOptions,
+ BuiltinOptions_BatchToSpaceNDOptions,
+ BuiltinOptions_SpaceToBatchNDOptions,
+ BuiltinOptions_TransposeOptions,
+ BuiltinOptions_ReducerOptions,
+ BuiltinOptions_SubOptions,
+ BuiltinOptions_DivOptions,
+ BuiltinOptions_SqueezeOptions,
+ BuiltinOptions_SequenceRNNOptions,
+ BuiltinOptions_StridedSliceOptions,
+ BuiltinOptions_ExpOptions,
+ BuiltinOptions_TopKV2Options,
+ BuiltinOptions_SplitOptions,
+ BuiltinOptions_LogSoftmaxOptions,
+ BuiltinOptions_CastOptions,
+ BuiltinOptions_DequantizeOptions,
+ BuiltinOptions_MaximumMinimumOptions,
+ BuiltinOptions_ArgMaxOptions,
+ BuiltinOptions_LessOptions,
+ BuiltinOptions_NegOptions,
+ BuiltinOptions_PadV2Options,
+ BuiltinOptions_GreaterOptions,
+ BuiltinOptions_GreaterEqualOptions,
+ BuiltinOptions_LessEqualOptions,
+ BuiltinOptions_SelectOptions,
+ BuiltinOptions_SliceOptions,
+ BuiltinOptions_TransposeConvOptions,
+ BuiltinOptions_SparseToDenseOptions,
+ BuiltinOptions_TileOptions,
+ BuiltinOptions_ExpandDimsOptions,
+ BuiltinOptions_EqualOptions,
+ BuiltinOptions_NotEqualOptions,
+ BuiltinOptions_ShapeOptions,
+ BuiltinOptions_PowOptions,
+ BuiltinOptions_ArgMinOptions,
+ BuiltinOptions_FakeQuantOptions,
+ BuiltinOptions_PackOptions,
+ BuiltinOptions_LogicalOrOptions,
+ BuiltinOptions_OneHotOptions,
+ BuiltinOptions_LogicalAndOptions,
+ BuiltinOptions_LogicalNotOptions,
+ BuiltinOptions_UnpackOptions,
+ BuiltinOptions_FloorDivOptions,
+ BuiltinOptions_SquareOptions,
+ BuiltinOptions_ZerosLikeOptions,
+ BuiltinOptions_FillOptions,
+ BuiltinOptions_BidirectionalSequenceLSTMOptions,
+ BuiltinOptions_BidirectionalSequenceRNNOptions,
+ BuiltinOptions_UnidirectionalSequenceLSTMOptions,
+ BuiltinOptions_FloorModOptions,
+ BuiltinOptions_RangeOptions,
+ BuiltinOptions_ResizeNearestNeighborOptions,
+ BuiltinOptions_LeakyReluOptions,
+ BuiltinOptions_SquaredDifferenceOptions,
+ BuiltinOptions_MirrorPadOptions,
+ BuiltinOptions_AbsOptions,
+ BuiltinOptions_SplitVOptions,
+ BuiltinOptions_UniqueOptions,
+ BuiltinOptions_ReverseV2Options,
+ BuiltinOptions_AddNOptions,
+ BuiltinOptions_GatherNdOptions,
+ BuiltinOptions_CosOptions,
+ BuiltinOptions_WhereOptions,
+ BuiltinOptions_RankOptions,
+ BuiltinOptions_ReverseSequenceOptions,
+ BuiltinOptions_MatrixDiagOptions,
+ BuiltinOptions_QuantizeOptions,
+ BuiltinOptions_MatrixSetDiagOptions,
+ BuiltinOptions_HardSwishOptions,
+ BuiltinOptions_IfOptions,
+ BuiltinOptions_WhileOptions,
+ BuiltinOptions_DepthToSpaceOptions,
+ BuiltinOptions_NonMaxSuppressionV4Options,
+ BuiltinOptions_NonMaxSuppressionV5Options,
+ BuiltinOptions_ScatterNdOptions,
+ BuiltinOptions_SelectV2Options,
+ BuiltinOptions_DensifyOptions,
+ BuiltinOptions_SegmentSumOptions,
+ BuiltinOptions_BatchMatMulOptions};
+ return values;
+}
+
+inline const char *const *EnumNamesBuiltinOptions()
+{
+ static const char *const names[] = {"NONE",
+ "Conv2DOptions",
+ "DepthwiseConv2DOptions",
+ "ConcatEmbeddingsOptions",
+ "LSHProjectionOptions",
+ "Pool2DOptions",
+ "SVDFOptions",
+ "RNNOptions",
+ "FullyConnectedOptions",
+ "SoftmaxOptions",
+ "ConcatenationOptions",
+ "AddOptions",
+ "L2NormOptions",
+ "LocalResponseNormalizationOptions",
+ "LSTMOptions",
+ "ResizeBilinearOptions",
+ "CallOptions",
+ "ReshapeOptions",
+ "SkipGramOptions",
+ "SpaceToDepthOptions",
+ "EmbeddingLookupSparseOptions",
+ "MulOptions",
+ "PadOptions",
+ "GatherOptions",
+ "BatchToSpaceNDOptions",
+ "SpaceToBatchNDOptions",
+ "TransposeOptions",
+ "ReducerOptions",
+ "SubOptions",
+ "DivOptions",
+ "SqueezeOptions",
+ "SequenceRNNOptions",
+ "StridedSliceOptions",
+ "ExpOptions",
+ "TopKV2Options",
+ "SplitOptions",
+ "LogSoftmaxOptions",
+ "CastOptions",
+ "DequantizeOptions",
+ "MaximumMinimumOptions",
+ "ArgMaxOptions",
+ "LessOptions",
+ "NegOptions",
+ "PadV2Options",
+ "GreaterOptions",
+ "GreaterEqualOptions",
+ "LessEqualOptions",
+ "SelectOptions",
+ "SliceOptions",
+ "TransposeConvOptions",
+ "SparseToDenseOptions",
+ "TileOptions",
+ "ExpandDimsOptions",
+ "EqualOptions",
+ "NotEqualOptions",
+ "ShapeOptions",
+ "PowOptions",
+ "ArgMinOptions",
+ "FakeQuantOptions",
+ "PackOptions",
+ "LogicalOrOptions",
+ "OneHotOptions",
+ "LogicalAndOptions",
+ "LogicalNotOptions",
+ "UnpackOptions",
+ "FloorDivOptions",
+ "SquareOptions",
+ "ZerosLikeOptions",
+ "FillOptions",
+ "BidirectionalSequenceLSTMOptions",
+ "BidirectionalSequenceRNNOptions",
+ "UnidirectionalSequenceLSTMOptions",
+ "FloorModOptions",
+ "RangeOptions",
+ "ResizeNearestNeighborOptions",
+ "LeakyReluOptions",
+ "SquaredDifferenceOptions",
+ "MirrorPadOptions",
+ "AbsOptions",
+ "SplitVOptions",
+ "UniqueOptions",
+ "ReverseV2Options",
+ "AddNOptions",
+ "GatherNdOptions",
+ "CosOptions",
+ "WhereOptions",
+ "RankOptions",
+ "ReverseSequenceOptions",
+ "MatrixDiagOptions",
+ "QuantizeOptions",
+ "MatrixSetDiagOptions",
+ "HardSwishOptions",
+ "IfOptions",
+ "WhileOptions",
+ "DepthToSpaceOptions",
+ "NonMaxSuppressionV4Options",
+ "NonMaxSuppressionV5Options",
+ "ScatterNdOptions",
+ "SelectV2Options",
+ "DensifyOptions",
+ "SegmentSumOptions",
+ "BatchMatMulOptions",
+ nullptr};
+ return names;
+}
+
+inline const char *EnumNameBuiltinOptions(BuiltinOptions e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesBuiltinOptions()[index];
+}
+
+template <typename T> struct BuiltinOptionsTraits
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NONE;
+};
+
+template <> struct BuiltinOptionsTraits<Conv2DOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_Conv2DOptions;
+};
+
+template <> struct BuiltinOptionsTraits<DepthwiseConv2DOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DepthwiseConv2DOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ConcatEmbeddingsOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ConcatEmbeddingsOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LSHProjectionOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LSHProjectionOptions;
+};
+
+template <> struct BuiltinOptionsTraits<Pool2DOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_Pool2DOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SVDFOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SVDFOptions;
+};
+
+template <> struct BuiltinOptionsTraits<RNNOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_RNNOptions;
+};
+
+template <> struct BuiltinOptionsTraits<FullyConnectedOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FullyConnectedOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SoftmaxOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SoftmaxOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ConcatenationOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ConcatenationOptions;
+};
+
+template <> struct BuiltinOptionsTraits<AddOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_AddOptions;
+};
+
+template <> struct BuiltinOptionsTraits<L2NormOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_L2NormOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LocalResponseNormalizationOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LocalResponseNormalizationOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LSTMOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LSTMOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ResizeBilinearOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ResizeBilinearOptions;
+};
+
+template <> struct BuiltinOptionsTraits<CallOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_CallOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ReshapeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ReshapeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SkipGramOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SkipGramOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SpaceToDepthOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SpaceToDepthOptions;
+};
+
+template <> struct BuiltinOptionsTraits<EmbeddingLookupSparseOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_EmbeddingLookupSparseOptions;
+};
+
+template <> struct BuiltinOptionsTraits<MulOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MulOptions;
+};
+
+template <> struct BuiltinOptionsTraits<PadOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_PadOptions;
+};
+
+template <> struct BuiltinOptionsTraits<GatherOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_GatherOptions;
+};
+
+template <> struct BuiltinOptionsTraits<BatchToSpaceNDOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BatchToSpaceNDOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SpaceToBatchNDOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SpaceToBatchNDOptions;
+};
+
+template <> struct BuiltinOptionsTraits<TransposeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_TransposeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ReducerOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ReducerOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SubOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SubOptions;
+};
+
+template <> struct BuiltinOptionsTraits<DivOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DivOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SqueezeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SqueezeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SequenceRNNOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SequenceRNNOptions;
+};
+
+template <> struct BuiltinOptionsTraits<StridedSliceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_StridedSliceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ExpOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ExpOptions;
+};
+
+template <> struct BuiltinOptionsTraits<TopKV2Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_TopKV2Options;
+};
+
+template <> struct BuiltinOptionsTraits<SplitOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SplitOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LogSoftmaxOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LogSoftmaxOptions;
+};
+
+template <> struct BuiltinOptionsTraits<CastOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_CastOptions;
+};
+
+template <> struct BuiltinOptionsTraits<DequantizeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DequantizeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<MaximumMinimumOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MaximumMinimumOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ArgMaxOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ArgMaxOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LessOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LessOptions;
+};
+
+template <> struct BuiltinOptionsTraits<NegOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NegOptions;
+};
+
+template <> struct BuiltinOptionsTraits<PadV2Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_PadV2Options;
+};
+
+template <> struct BuiltinOptionsTraits<GreaterOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_GreaterOptions;
+};
+
+template <> struct BuiltinOptionsTraits<GreaterEqualOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_GreaterEqualOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LessEqualOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LessEqualOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SelectOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SelectOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SliceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SliceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<TransposeConvOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_TransposeConvOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SparseToDenseOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SparseToDenseOptions;
+};
+
+template <> struct BuiltinOptionsTraits<TileOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_TileOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ExpandDimsOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ExpandDimsOptions;
+};
+
+template <> struct BuiltinOptionsTraits<EqualOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_EqualOptions;
+};
+
+template <> struct BuiltinOptionsTraits<NotEqualOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NotEqualOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ShapeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ShapeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<PowOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_PowOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ArgMinOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ArgMinOptions;
+};
+
+template <> struct BuiltinOptionsTraits<FakeQuantOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FakeQuantOptions;
+};
+
+template <> struct BuiltinOptionsTraits<PackOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_PackOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LogicalOrOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LogicalOrOptions;
+};
+
+template <> struct BuiltinOptionsTraits<OneHotOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_OneHotOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LogicalAndOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LogicalAndOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LogicalNotOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LogicalNotOptions;
+};
+
+template <> struct BuiltinOptionsTraits<UnpackOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_UnpackOptions;
+};
+
+template <> struct BuiltinOptionsTraits<FloorDivOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FloorDivOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SquareOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SquareOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ZerosLikeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ZerosLikeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<FillOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FillOptions;
+};
+
+template <> struct BuiltinOptionsTraits<BidirectionalSequenceLSTMOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceLSTMOptions;
+};
+
+template <> struct BuiltinOptionsTraits<BidirectionalSequenceRNNOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceRNNOptions;
+};
+
+template <> struct BuiltinOptionsTraits<UnidirectionalSequenceLSTMOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_UnidirectionalSequenceLSTMOptions;
+};
+
+template <> struct BuiltinOptionsTraits<FloorModOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_FloorModOptions;
+};
+
+template <> struct BuiltinOptionsTraits<RangeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_RangeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ResizeNearestNeighborOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ResizeNearestNeighborOptions;
+};
+
+template <> struct BuiltinOptionsTraits<LeakyReluOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_LeakyReluOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SquaredDifferenceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SquaredDifferenceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<MirrorPadOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MirrorPadOptions;
+};
+
+template <> struct BuiltinOptionsTraits<AbsOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_AbsOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SplitVOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SplitVOptions;
+};
+
+template <> struct BuiltinOptionsTraits<UniqueOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_UniqueOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ReverseV2Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ReverseV2Options;
+};
+
+template <> struct BuiltinOptionsTraits<AddNOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_AddNOptions;
+};
+
+template <> struct BuiltinOptionsTraits<GatherNdOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_GatherNdOptions;
+};
+
+template <> struct BuiltinOptionsTraits<CosOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_CosOptions;
+};
+
+template <> struct BuiltinOptionsTraits<WhereOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_WhereOptions;
+};
+
+template <> struct BuiltinOptionsTraits<RankOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_RankOptions;
+};
+
+template <> struct BuiltinOptionsTraits<ReverseSequenceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ReverseSequenceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<MatrixDiagOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MatrixDiagOptions;
+};
+
+template <> struct BuiltinOptionsTraits<QuantizeOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_QuantizeOptions;
+};
+
+template <> struct BuiltinOptionsTraits<MatrixSetDiagOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_MatrixSetDiagOptions;
+};
+
+template <> struct BuiltinOptionsTraits<HardSwishOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_HardSwishOptions;
+};
+
+template <> struct BuiltinOptionsTraits<IfOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_IfOptions;
+};
+
+template <> struct BuiltinOptionsTraits<WhileOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_WhileOptions;
+};
+
+template <> struct BuiltinOptionsTraits<DepthToSpaceOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DepthToSpaceOptions;
+};
+
+template <> struct BuiltinOptionsTraits<NonMaxSuppressionV4Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV4Options;
+};
+
+template <> struct BuiltinOptionsTraits<NonMaxSuppressionV5Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV5Options;
+};
+
+template <> struct BuiltinOptionsTraits<ScatterNdOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_ScatterNdOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SelectV2Options>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SelectV2Options;
+};
+
+template <> struct BuiltinOptionsTraits<DensifyOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_DensifyOptions;
+};
+
+template <> struct BuiltinOptionsTraits<SegmentSumOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_SegmentSumOptions;
+};
+
+template <> struct BuiltinOptionsTraits<BatchMatMulOptions>
+{
+ static const BuiltinOptions enum_value = BuiltinOptions_BatchMatMulOptions;
+};
+
+bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type);
+bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types);
+
+enum Padding
+{
+ Padding_SAME = 0,
+ Padding_VALID = 1,
+ Padding_MIN = Padding_SAME,
+ Padding_MAX = Padding_VALID
+};
+
+inline const Padding (&EnumValuesPadding())[2]
+{
+ static const Padding values[] = {Padding_SAME, Padding_VALID};
+ return values;
+}
+
+inline const char *const *EnumNamesPadding()
+{
+ static const char *const names[] = {"SAME", "VALID", nullptr};
+ return names;
+}
+
+inline const char *EnumNamePadding(Padding e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesPadding()[index];
+}
+
+enum ActivationFunctionType
+{
+ ActivationFunctionType_NONE = 0,
+ ActivationFunctionType_RELU = 1,
+ ActivationFunctionType_RELU_N1_TO_1 = 2,
+ ActivationFunctionType_RELU6 = 3,
+ ActivationFunctionType_TANH = 4,
+ ActivationFunctionType_SIGN_BIT = 5,
+ ActivationFunctionType_MIN = ActivationFunctionType_NONE,
+ ActivationFunctionType_MAX = ActivationFunctionType_SIGN_BIT
+};
+
+inline const ActivationFunctionType (&EnumValuesActivationFunctionType())[6]
+{
+ static const ActivationFunctionType values[] = {
+ ActivationFunctionType_NONE, ActivationFunctionType_RELU,
+ ActivationFunctionType_RELU_N1_TO_1, ActivationFunctionType_RELU6,
+ ActivationFunctionType_TANH, ActivationFunctionType_SIGN_BIT};
+ return values;
+}
+
+inline const char *const *EnumNamesActivationFunctionType()
+{
+ static const char *const names[] = {"NONE", "RELU", "RELU_N1_TO_1", "RELU6",
+ "TANH", "SIGN_BIT", nullptr};
+ return names;
+}
+
+inline const char *EnumNameActivationFunctionType(ActivationFunctionType e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesActivationFunctionType()[index];
+}
+
+enum LSHProjectionType
+{
+ LSHProjectionType_UNKNOWN = 0,
+ LSHProjectionType_SPARSE = 1,
+ LSHProjectionType_DENSE = 2,
+ LSHProjectionType_MIN = LSHProjectionType_UNKNOWN,
+ LSHProjectionType_MAX = LSHProjectionType_DENSE
+};
+
+inline const LSHProjectionType (&EnumValuesLSHProjectionType())[3]
+{
+ static const LSHProjectionType values[] = {LSHProjectionType_UNKNOWN, LSHProjectionType_SPARSE,
+ LSHProjectionType_DENSE};
+ return values;
+}
+
+inline const char *const *EnumNamesLSHProjectionType()
+{
+ static const char *const names[] = {"UNKNOWN", "SPARSE", "DENSE", nullptr};
+ return names;
+}
+
+inline const char *EnumNameLSHProjectionType(LSHProjectionType e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesLSHProjectionType()[index];
+}
+
+enum FullyConnectedOptionsWeightsFormat
+{
+ FullyConnectedOptionsWeightsFormat_DEFAULT = 0,
+ FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 = 1,
+ FullyConnectedOptionsWeightsFormat_MIN = FullyConnectedOptionsWeightsFormat_DEFAULT,
+ FullyConnectedOptionsWeightsFormat_MAX = FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8
+};
+
+inline const FullyConnectedOptionsWeightsFormat (&EnumValuesFullyConnectedOptionsWeightsFormat())[2]
+{
+ static const FullyConnectedOptionsWeightsFormat values[] = {
+ FullyConnectedOptionsWeightsFormat_DEFAULT,
+ FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8};
+ return values;
+}
+
+inline const char *const *EnumNamesFullyConnectedOptionsWeightsFormat()
+{
+ static const char *const names[] = {"DEFAULT", "SHUFFLED4x16INT8", nullptr};
+ return names;
+}
+
+inline const char *EnumNameFullyConnectedOptionsWeightsFormat(FullyConnectedOptionsWeightsFormat e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesFullyConnectedOptionsWeightsFormat()[index];
+}
+
+enum LSTMKernelType
+{
+ LSTMKernelType_FULL = 0,
+ LSTMKernelType_BASIC = 1,
+ LSTMKernelType_MIN = LSTMKernelType_FULL,
+ LSTMKernelType_MAX = LSTMKernelType_BASIC
+};
+
+inline const LSTMKernelType (&EnumValuesLSTMKernelType())[2]
+{
+ static const LSTMKernelType values[] = {LSTMKernelType_FULL, LSTMKernelType_BASIC};
+ return values;
+}
+
+inline const char *const *EnumNamesLSTMKernelType()
+{
+ static const char *const names[] = {"FULL", "BASIC", nullptr};
+ return names;
+}
+
+inline const char *EnumNameLSTMKernelType(LSTMKernelType e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesLSTMKernelType()[index];
+}
+
+enum CombinerType
+{
+ CombinerType_SUM = 0,
+ CombinerType_MEAN = 1,
+ CombinerType_SQRTN = 2,
+ CombinerType_MIN = CombinerType_SUM,
+ CombinerType_MAX = CombinerType_SQRTN
+};
+
+inline const CombinerType (&EnumValuesCombinerType())[3]
+{
+ static const CombinerType values[] = {CombinerType_SUM, CombinerType_MEAN, CombinerType_SQRTN};
+ return values;
+}
+
+inline const char *const *EnumNamesCombinerType()
+{
+ static const char *const names[] = {"SUM", "MEAN", "SQRTN", nullptr};
+ return names;
+}
+
+inline const char *EnumNameCombinerType(CombinerType e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesCombinerType()[index];
+}
+
+enum MirrorPadMode
+{
+ MirrorPadMode_REFLECT = 0,
+ MirrorPadMode_SYMMETRIC = 1,
+ MirrorPadMode_MIN = MirrorPadMode_REFLECT,
+ MirrorPadMode_MAX = MirrorPadMode_SYMMETRIC
+};
+
+inline const MirrorPadMode (&EnumValuesMirrorPadMode())[2]
+{
+ static const MirrorPadMode values[] = {MirrorPadMode_REFLECT, MirrorPadMode_SYMMETRIC};
+ return values;
+}
+
+inline const char *const *EnumNamesMirrorPadMode()
+{
+ static const char *const names[] = {"REFLECT", "SYMMETRIC", nullptr};
+ return names;
+}
+
+inline const char *EnumNameMirrorPadMode(MirrorPadMode e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesMirrorPadMode()[index];
+}
+
+enum CustomOptionsFormat
+{
+ CustomOptionsFormat_FLEXBUFFERS = 0,
+ CustomOptionsFormat_MIN = CustomOptionsFormat_FLEXBUFFERS,
+ CustomOptionsFormat_MAX = CustomOptionsFormat_FLEXBUFFERS
+};
+
+inline const CustomOptionsFormat (&EnumValuesCustomOptionsFormat())[1]
+{
+ static const CustomOptionsFormat values[] = {CustomOptionsFormat_FLEXBUFFERS};
+ return values;
+}
+
+inline const char *const *EnumNamesCustomOptionsFormat()
+{
+ static const char *const names[] = {"FLEXBUFFERS", nullptr};
+ return names;
+}
+
+inline const char *EnumNameCustomOptionsFormat(CustomOptionsFormat e)
+{
+ const size_t index = static_cast<int>(e);
+ return EnumNamesCustomOptionsFormat()[index];
+}
+
+struct CustomQuantization FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_CUSTOM = 4
+ };
+ const flatbuffers::Vector<uint8_t> *custom() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_CUSTOM);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_CUSTOM) &&
+ verifier.VerifyVector(custom()) && verifier.EndTable();
+ }
+};
+
+struct CustomQuantizationBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_custom(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> custom)
+ {
+ fbb_.AddOffset(CustomQuantization::VT_CUSTOM, custom);
+ }
+ explicit CustomQuantizationBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ CustomQuantizationBuilder &operator=(const CustomQuantizationBuilder &);
+ flatbuffers::Offset<CustomQuantization> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CustomQuantization>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CustomQuantization>
+CreateCustomQuantization(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> custom = 0)
+{
+ CustomQuantizationBuilder builder_(_fbb);
+ builder_.add_custom(custom);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<CustomQuantization>
+CreateCustomQuantizationDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<uint8_t> *custom = nullptr)
+{
+ return onert_tflite::CreateCustomQuantization(_fbb,
+ custom ? _fbb.CreateVector<uint8_t>(*custom) : 0);
+}
+
+struct QuantizationParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_MIN = 4,
+ VT_MAX = 6,
+ VT_SCALE = 8,
+ VT_ZERO_POINT = 10,
+ VT_DETAILS_TYPE = 12,
+ VT_DETAILS = 14,
+ VT_QUANTIZED_DIMENSION = 16
+ };
+ const flatbuffers::Vector<float> *min() const
+ {
+ return GetPointer<const flatbuffers::Vector<float> *>(VT_MIN);
+ }
+ const flatbuffers::Vector<float> *max() const
+ {
+ return GetPointer<const flatbuffers::Vector<float> *>(VT_MAX);
+ }
+ const flatbuffers::Vector<float> *scale() const
+ {
+ return GetPointer<const flatbuffers::Vector<float> *>(VT_SCALE);
+ }
+ const flatbuffers::Vector<int64_t> *zero_point() const
+ {
+ return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_ZERO_POINT);
+ }
+ QuantizationDetails details_type() const
+ {
+ return static_cast<QuantizationDetails>(GetField<uint8_t>(VT_DETAILS_TYPE, 0));
+ }
+ const void *details() const { return GetPointer<const void *>(VT_DETAILS); }
+ template <typename T> const T *details_as() const;
+ const CustomQuantization *details_as_CustomQuantization() const
+ {
+ return details_type() == QuantizationDetails_CustomQuantization
+ ? static_cast<const CustomQuantization *>(details())
+ : nullptr;
+ }
+ int32_t quantized_dimension() const { return GetField<int32_t>(VT_QUANTIZED_DIMENSION, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_MIN) &&
+ verifier.VerifyVector(min()) && VerifyOffset(verifier, VT_MAX) &&
+ verifier.VerifyVector(max()) && VerifyOffset(verifier, VT_SCALE) &&
+ verifier.VerifyVector(scale()) && VerifyOffset(verifier, VT_ZERO_POINT) &&
+ verifier.VerifyVector(zero_point()) && VerifyField<uint8_t>(verifier, VT_DETAILS_TYPE) &&
+ VerifyOffset(verifier, VT_DETAILS) &&
+ VerifyQuantizationDetails(verifier, details(), details_type()) &&
+ VerifyField<int32_t>(verifier, VT_QUANTIZED_DIMENSION) && verifier.EndTable();
+ }
+};
+
+template <>
+inline const CustomQuantization *QuantizationParameters::details_as<CustomQuantization>() const
+{
+ return details_as_CustomQuantization();
+}
+
+struct QuantizationParametersBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_min(flatbuffers::Offset<flatbuffers::Vector<float>> min)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_MIN, min);
+ }
+ void add_max(flatbuffers::Offset<flatbuffers::Vector<float>> max)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_MAX, max);
+ }
+ void add_scale(flatbuffers::Offset<flatbuffers::Vector<float>> scale)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_SCALE, scale);
+ }
+ void add_zero_point(flatbuffers::Offset<flatbuffers::Vector<int64_t>> zero_point)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_ZERO_POINT, zero_point);
+ }
+ void add_details_type(QuantizationDetails details_type)
+ {
+ fbb_.AddElement<uint8_t>(QuantizationParameters::VT_DETAILS_TYPE,
+ static_cast<uint8_t>(details_type), 0);
+ }
+ void add_details(flatbuffers::Offset<void> details)
+ {
+ fbb_.AddOffset(QuantizationParameters::VT_DETAILS, details);
+ }
+ void add_quantized_dimension(int32_t quantized_dimension)
+ {
+ fbb_.AddElement<int32_t>(QuantizationParameters::VT_QUANTIZED_DIMENSION, quantized_dimension,
+ 0);
+ }
+ explicit QuantizationParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ QuantizationParametersBuilder &operator=(const QuantizationParametersBuilder &);
+ flatbuffers::Offset<QuantizationParameters> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<QuantizationParameters>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<QuantizationParameters>
+CreateQuantizationParameters(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<float>> min = 0,
+ flatbuffers::Offset<flatbuffers::Vector<float>> max = 0,
+ flatbuffers::Offset<flatbuffers::Vector<float>> scale = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int64_t>> zero_point = 0,
+ QuantizationDetails details_type = QuantizationDetails_NONE,
+ flatbuffers::Offset<void> details = 0, int32_t quantized_dimension = 0)
+{
+ QuantizationParametersBuilder builder_(_fbb);
+ builder_.add_quantized_dimension(quantized_dimension);
+ builder_.add_details(details);
+ builder_.add_zero_point(zero_point);
+ builder_.add_scale(scale);
+ builder_.add_max(max);
+ builder_.add_min(min);
+ builder_.add_details_type(details_type);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<QuantizationParameters> CreateQuantizationParametersDirect(
+ flatbuffers::FlatBufferBuilder &_fbb, const std::vector<float> *min = nullptr,
+ const std::vector<float> *max = nullptr, const std::vector<float> *scale = nullptr,
+ const std::vector<int64_t> *zero_point = nullptr,
+ QuantizationDetails details_type = QuantizationDetails_NONE,
+ flatbuffers::Offset<void> details = 0, int32_t quantized_dimension = 0)
+{
+ return onert_tflite::CreateQuantizationParameters(
+ _fbb, min ? _fbb.CreateVector<float>(*min) : 0, max ? _fbb.CreateVector<float>(*max) : 0,
+ scale ? _fbb.CreateVector<float>(*scale) : 0,
+ zero_point ? _fbb.CreateVector<int64_t>(*zero_point) : 0, details_type, details,
+ quantized_dimension);
+}
+
+struct Int32Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_VALUES = 4
+ };
+ const flatbuffers::Vector<int32_t> *values() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_VALUES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) &&
+ verifier.VerifyVector(values()) && verifier.EndTable();
+ }
+};
+
+struct Int32VectorBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_values(flatbuffers::Offset<flatbuffers::Vector<int32_t>> values)
+ {
+ fbb_.AddOffset(Int32Vector::VT_VALUES, values);
+ }
+ explicit Int32VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Int32VectorBuilder &operator=(const Int32VectorBuilder &);
+ flatbuffers::Offset<Int32Vector> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Int32Vector>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Int32Vector>
+CreateInt32Vector(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> values = 0)
+{
+ Int32VectorBuilder builder_(_fbb);
+ builder_.add_values(values);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Int32Vector>
+CreateInt32VectorDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<int32_t> *values = nullptr)
+{
+ return onert_tflite::CreateInt32Vector(_fbb, values ? _fbb.CreateVector<int32_t>(*values) : 0);
+}
+
+struct Uint16Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_VALUES = 4
+ };
+ const flatbuffers::Vector<uint16_t> *values() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint16_t> *>(VT_VALUES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) &&
+ verifier.VerifyVector(values()) && verifier.EndTable();
+ }
+};
+
+struct Uint16VectorBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_values(flatbuffers::Offset<flatbuffers::Vector<uint16_t>> values)
+ {
+ fbb_.AddOffset(Uint16Vector::VT_VALUES, values);
+ }
+ explicit Uint16VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Uint16VectorBuilder &operator=(const Uint16VectorBuilder &);
+ flatbuffers::Offset<Uint16Vector> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Uint16Vector>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Uint16Vector>
+CreateUint16Vector(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<uint16_t>> values = 0)
+{
+ Uint16VectorBuilder builder_(_fbb);
+ builder_.add_values(values);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Uint16Vector>
+CreateUint16VectorDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<uint16_t> *values = nullptr)
+{
+ return onert_tflite::CreateUint16Vector(_fbb, values ? _fbb.CreateVector<uint16_t>(*values) : 0);
+}
+
+struct Uint8Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_VALUES = 4
+ };
+ const flatbuffers::Vector<uint8_t> *values() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_VALUES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) &&
+ verifier.VerifyVector(values()) && verifier.EndTable();
+ }
+};
+
+struct Uint8VectorBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_values(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> values)
+ {
+ fbb_.AddOffset(Uint8Vector::VT_VALUES, values);
+ }
+ explicit Uint8VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Uint8VectorBuilder &operator=(const Uint8VectorBuilder &);
+ flatbuffers::Offset<Uint8Vector> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Uint8Vector>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Uint8Vector>
+CreateUint8Vector(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> values = 0)
+{
+ Uint8VectorBuilder builder_(_fbb);
+ builder_.add_values(values);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Uint8Vector>
+CreateUint8VectorDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<uint8_t> *values = nullptr)
+{
+ return onert_tflite::CreateUint8Vector(_fbb, values ? _fbb.CreateVector<uint8_t>(*values) : 0);
+}
+
+struct DimensionMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FORMAT = 4,
+ VT_DENSE_SIZE = 6,
+ VT_ARRAY_SEGMENTS_TYPE = 8,
+ VT_ARRAY_SEGMENTS = 10,
+ VT_ARRAY_INDICES_TYPE = 12,
+ VT_ARRAY_INDICES = 14
+ };
+ DimensionType format() const
+ {
+ return static_cast<DimensionType>(GetField<int8_t>(VT_FORMAT, 0));
+ }
+ int32_t dense_size() const { return GetField<int32_t>(VT_DENSE_SIZE, 0); }
+ SparseIndexVector array_segments_type() const
+ {
+ return static_cast<SparseIndexVector>(GetField<uint8_t>(VT_ARRAY_SEGMENTS_TYPE, 0));
+ }
+ const void *array_segments() const { return GetPointer<const void *>(VT_ARRAY_SEGMENTS); }
+ template <typename T> const T *array_segments_as() const;
+ const Int32Vector *array_segments_as_Int32Vector() const
+ {
+ return array_segments_type() == SparseIndexVector_Int32Vector
+ ? static_cast<const Int32Vector *>(array_segments())
+ : nullptr;
+ }
+ const Uint16Vector *array_segments_as_Uint16Vector() const
+ {
+ return array_segments_type() == SparseIndexVector_Uint16Vector
+ ? static_cast<const Uint16Vector *>(array_segments())
+ : nullptr;
+ }
+ const Uint8Vector *array_segments_as_Uint8Vector() const
+ {
+ return array_segments_type() == SparseIndexVector_Uint8Vector
+ ? static_cast<const Uint8Vector *>(array_segments())
+ : nullptr;
+ }
+ SparseIndexVector array_indices_type() const
+ {
+ return static_cast<SparseIndexVector>(GetField<uint8_t>(VT_ARRAY_INDICES_TYPE, 0));
+ }
+ const void *array_indices() const { return GetPointer<const void *>(VT_ARRAY_INDICES); }
+ template <typename T> const T *array_indices_as() const;
+ const Int32Vector *array_indices_as_Int32Vector() const
+ {
+ return array_indices_type() == SparseIndexVector_Int32Vector
+ ? static_cast<const Int32Vector *>(array_indices())
+ : nullptr;
+ }
+ const Uint16Vector *array_indices_as_Uint16Vector() const
+ {
+ return array_indices_type() == SparseIndexVector_Uint16Vector
+ ? static_cast<const Uint16Vector *>(array_indices())
+ : nullptr;
+ }
+ const Uint8Vector *array_indices_as_Uint8Vector() const
+ {
+ return array_indices_type() == SparseIndexVector_Uint8Vector
+ ? static_cast<const Uint8Vector *>(array_indices())
+ : nullptr;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_FORMAT) &&
+ VerifyField<int32_t>(verifier, VT_DENSE_SIZE) &&
+ VerifyField<uint8_t>(verifier, VT_ARRAY_SEGMENTS_TYPE) &&
+ VerifyOffset(verifier, VT_ARRAY_SEGMENTS) &&
+ VerifySparseIndexVector(verifier, array_segments(), array_segments_type()) &&
+ VerifyField<uint8_t>(verifier, VT_ARRAY_INDICES_TYPE) &&
+ VerifyOffset(verifier, VT_ARRAY_INDICES) &&
+ VerifySparseIndexVector(verifier, array_indices(), array_indices_type()) &&
+ verifier.EndTable();
+ }
+};
+
+template <> inline const Int32Vector *DimensionMetadata::array_segments_as<Int32Vector>() const
+{
+ return array_segments_as_Int32Vector();
+}
+
+template <> inline const Uint16Vector *DimensionMetadata::array_segments_as<Uint16Vector>() const
+{
+ return array_segments_as_Uint16Vector();
+}
+
+template <> inline const Uint8Vector *DimensionMetadata::array_segments_as<Uint8Vector>() const
+{
+ return array_segments_as_Uint8Vector();
+}
+
+template <> inline const Int32Vector *DimensionMetadata::array_indices_as<Int32Vector>() const
+{
+ return array_indices_as_Int32Vector();
+}
+
+template <> inline const Uint16Vector *DimensionMetadata::array_indices_as<Uint16Vector>() const
+{
+ return array_indices_as_Uint16Vector();
+}
+
+template <> inline const Uint8Vector *DimensionMetadata::array_indices_as<Uint8Vector>() const
+{
+ return array_indices_as_Uint8Vector();
+}
+
+struct DimensionMetadataBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_format(DimensionType format)
+ {
+ fbb_.AddElement<int8_t>(DimensionMetadata::VT_FORMAT, static_cast<int8_t>(format), 0);
+ }
+ void add_dense_size(int32_t dense_size)
+ {
+ fbb_.AddElement<int32_t>(DimensionMetadata::VT_DENSE_SIZE, dense_size, 0);
+ }
+ void add_array_segments_type(SparseIndexVector array_segments_type)
+ {
+ fbb_.AddElement<uint8_t>(DimensionMetadata::VT_ARRAY_SEGMENTS_TYPE,
+ static_cast<uint8_t>(array_segments_type), 0);
+ }
+ void add_array_segments(flatbuffers::Offset<void> array_segments)
+ {
+ fbb_.AddOffset(DimensionMetadata::VT_ARRAY_SEGMENTS, array_segments);
+ }
+ void add_array_indices_type(SparseIndexVector array_indices_type)
+ {
+ fbb_.AddElement<uint8_t>(DimensionMetadata::VT_ARRAY_INDICES_TYPE,
+ static_cast<uint8_t>(array_indices_type), 0);
+ }
+ void add_array_indices(flatbuffers::Offset<void> array_indices)
+ {
+ fbb_.AddOffset(DimensionMetadata::VT_ARRAY_INDICES, array_indices);
+ }
+ explicit DimensionMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DimensionMetadataBuilder &operator=(const DimensionMetadataBuilder &);
+ flatbuffers::Offset<DimensionMetadata> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DimensionMetadata>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DimensionMetadata>
+CreateDimensionMetadata(flatbuffers::FlatBufferBuilder &_fbb,
+ DimensionType format = DimensionType_DENSE, int32_t dense_size = 0,
+ SparseIndexVector array_segments_type = SparseIndexVector_NONE,
+ flatbuffers::Offset<void> array_segments = 0,
+ SparseIndexVector array_indices_type = SparseIndexVector_NONE,
+ flatbuffers::Offset<void> array_indices = 0)
+{
+ DimensionMetadataBuilder builder_(_fbb);
+ builder_.add_array_indices(array_indices);
+ builder_.add_array_segments(array_segments);
+ builder_.add_dense_size(dense_size);
+ builder_.add_array_indices_type(array_indices_type);
+ builder_.add_array_segments_type(array_segments_type);
+ builder_.add_format(format);
+ return builder_.Finish();
+}
+
+struct SparsityParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_TRAVERSAL_ORDER = 4,
+ VT_BLOCK_MAP = 6,
+ VT_DIM_METADATA = 8
+ };
+ const flatbuffers::Vector<int32_t> *traversal_order() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_TRAVERSAL_ORDER);
+ }
+ const flatbuffers::Vector<int32_t> *block_map() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_BLOCK_MAP);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<DimensionMetadata>> *dim_metadata() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<DimensionMetadata>> *>(
+ VT_DIM_METADATA);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TRAVERSAL_ORDER) &&
+ verifier.VerifyVector(traversal_order()) && VerifyOffset(verifier, VT_BLOCK_MAP) &&
+ verifier.VerifyVector(block_map()) && VerifyOffset(verifier, VT_DIM_METADATA) &&
+ verifier.VerifyVector(dim_metadata()) && verifier.VerifyVectorOfTables(dim_metadata()) &&
+ verifier.EndTable();
+ }
+};
+
+struct SparsityParametersBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_traversal_order(flatbuffers::Offset<flatbuffers::Vector<int32_t>> traversal_order)
+ {
+ fbb_.AddOffset(SparsityParameters::VT_TRAVERSAL_ORDER, traversal_order);
+ }
+ void add_block_map(flatbuffers::Offset<flatbuffers::Vector<int32_t>> block_map)
+ {
+ fbb_.AddOffset(SparsityParameters::VT_BLOCK_MAP, block_map);
+ }
+ void add_dim_metadata(
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<DimensionMetadata>>> dim_metadata)
+ {
+ fbb_.AddOffset(SparsityParameters::VT_DIM_METADATA, dim_metadata);
+ }
+ explicit SparsityParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SparsityParametersBuilder &operator=(const SparsityParametersBuilder &);
+ flatbuffers::Offset<SparsityParameters> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SparsityParameters>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SparsityParameters> CreateSparsityParameters(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> traversal_order = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> block_map = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<DimensionMetadata>>> dim_metadata =
+ 0)
+{
+ SparsityParametersBuilder builder_(_fbb);
+ builder_.add_dim_metadata(dim_metadata);
+ builder_.add_block_map(block_map);
+ builder_.add_traversal_order(traversal_order);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<SparsityParameters> CreateSparsityParametersDirect(
+ flatbuffers::FlatBufferBuilder &_fbb, const std::vector<int32_t> *traversal_order = nullptr,
+ const std::vector<int32_t> *block_map = nullptr,
+ const std::vector<flatbuffers::Offset<DimensionMetadata>> *dim_metadata = nullptr)
+{
+ return onert_tflite::CreateSparsityParameters(
+ _fbb, traversal_order ? _fbb.CreateVector<int32_t>(*traversal_order) : 0,
+ block_map ? _fbb.CreateVector<int32_t>(*block_map) : 0,
+ dim_metadata ? _fbb.CreateVector<flatbuffers::Offset<DimensionMetadata>>(*dim_metadata) : 0);
+}
+
+struct Tensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_SHAPE = 4,
+ VT_TYPE = 6,
+ VT_BUFFER = 8,
+ VT_NAME = 10,
+ VT_QUANTIZATION = 12,
+ VT_IS_VARIABLE = 14,
+ VT_SPARSITY = 16,
+ VT_SHAPE_SIGNATURE = 18
+ };
+ const flatbuffers::Vector<int32_t> *shape() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_SHAPE);
+ }
+ TensorType type() const { return static_cast<TensorType>(GetField<int8_t>(VT_TYPE, 0)); }
+ uint32_t buffer() const { return GetField<uint32_t>(VT_BUFFER, 0); }
+ const flatbuffers::String *name() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ const QuantizationParameters *quantization() const
+ {
+ return GetPointer<const QuantizationParameters *>(VT_QUANTIZATION);
+ }
+ bool is_variable() const { return GetField<uint8_t>(VT_IS_VARIABLE, 0) != 0; }
+ const SparsityParameters *sparsity() const
+ {
+ return GetPointer<const SparsityParameters *>(VT_SPARSITY);
+ }
+ const flatbuffers::Vector<int32_t> *shape_signature() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_SHAPE_SIGNATURE);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SHAPE) &&
+ verifier.VerifyVector(shape()) && VerifyField<int8_t>(verifier, VT_TYPE) &&
+ VerifyField<uint32_t>(verifier, VT_BUFFER) && VerifyOffset(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) && VerifyOffset(verifier, VT_QUANTIZATION) &&
+ verifier.VerifyTable(quantization()) && VerifyField<uint8_t>(verifier, VT_IS_VARIABLE) &&
+ VerifyOffset(verifier, VT_SPARSITY) && verifier.VerifyTable(sparsity()) &&
+ VerifyOffset(verifier, VT_SHAPE_SIGNATURE) && verifier.VerifyVector(shape_signature()) &&
+ verifier.EndTable();
+ }
+};
+
+struct TensorBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_shape(flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape)
+ {
+ fbb_.AddOffset(Tensor::VT_SHAPE, shape);
+ }
+ void add_type(TensorType type)
+ {
+ fbb_.AddElement<int8_t>(Tensor::VT_TYPE, static_cast<int8_t>(type), 0);
+ }
+ void add_buffer(uint32_t buffer) { fbb_.AddElement<uint32_t>(Tensor::VT_BUFFER, buffer, 0); }
+ void add_name(flatbuffers::Offset<flatbuffers::String> name)
+ {
+ fbb_.AddOffset(Tensor::VT_NAME, name);
+ }
+ void add_quantization(flatbuffers::Offset<QuantizationParameters> quantization)
+ {
+ fbb_.AddOffset(Tensor::VT_QUANTIZATION, quantization);
+ }
+ void add_is_variable(bool is_variable)
+ {
+ fbb_.AddElement<uint8_t>(Tensor::VT_IS_VARIABLE, static_cast<uint8_t>(is_variable), 0);
+ }
+ void add_sparsity(flatbuffers::Offset<SparsityParameters> sparsity)
+ {
+ fbb_.AddOffset(Tensor::VT_SPARSITY, sparsity);
+ }
+ void add_shape_signature(flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape_signature)
+ {
+ fbb_.AddOffset(Tensor::VT_SHAPE_SIGNATURE, shape_signature);
+ }
+ explicit TensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TensorBuilder &operator=(const TensorBuilder &);
+ flatbuffers::Offset<Tensor> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Tensor>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Tensor>
+CreateTensor(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape = 0,
+ TensorType type = TensorType_FLOAT32, uint32_t buffer = 0,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<QuantizationParameters> quantization = 0, bool is_variable = false,
+ flatbuffers::Offset<SparsityParameters> sparsity = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape_signature = 0)
+{
+ TensorBuilder builder_(_fbb);
+ builder_.add_shape_signature(shape_signature);
+ builder_.add_sparsity(sparsity);
+ builder_.add_quantization(quantization);
+ builder_.add_name(name);
+ builder_.add_buffer(buffer);
+ builder_.add_shape(shape);
+ builder_.add_is_variable(is_variable);
+ builder_.add_type(type);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Tensor> CreateTensorDirect(
+ flatbuffers::FlatBufferBuilder &_fbb, const std::vector<int32_t> *shape = nullptr,
+ TensorType type = TensorType_FLOAT32, uint32_t buffer = 0, const char *name = nullptr,
+ flatbuffers::Offset<QuantizationParameters> quantization = 0, bool is_variable = false,
+ flatbuffers::Offset<SparsityParameters> sparsity = 0,
+ const std::vector<int32_t> *shape_signature = nullptr)
+{
+ return onert_tflite::CreateTensor(
+ _fbb, shape ? _fbb.CreateVector<int32_t>(*shape) : 0, type, buffer,
+ name ? _fbb.CreateString(name) : 0, quantization, is_variable, sparsity,
+ shape_signature ? _fbb.CreateVector<int32_t>(*shape_signature) : 0);
+}
+
+struct Conv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_PADDING = 4,
+ VT_STRIDE_W = 6,
+ VT_STRIDE_H = 8,
+ VT_FUSED_ACTIVATION_FUNCTION = 10,
+ VT_DILATION_W_FACTOR = 12,
+ VT_DILATION_H_FACTOR = 14
+ };
+ Padding padding() const { return static_cast<Padding>(GetField<int8_t>(VT_PADDING, 0)); }
+ int32_t stride_w() const { return GetField<int32_t>(VT_STRIDE_W, 0); }
+ int32_t stride_h() const { return GetField<int32_t>(VT_STRIDE_H, 0); }
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ int32_t dilation_w_factor() const { return GetField<int32_t>(VT_DILATION_W_FACTOR, 1); }
+ int32_t dilation_h_factor() const { return GetField<int32_t>(VT_DILATION_H_FACTOR, 1); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_PADDING) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_W) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_H) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<int32_t>(verifier, VT_DILATION_W_FACTOR) &&
+ VerifyField<int32_t>(verifier, VT_DILATION_H_FACTOR) && verifier.EndTable();
+ }
+};
+
+struct Conv2DOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_padding(Padding padding)
+ {
+ fbb_.AddElement<int8_t>(Conv2DOptions::VT_PADDING, static_cast<int8_t>(padding), 0);
+ }
+ void add_stride_w(int32_t stride_w)
+ {
+ fbb_.AddElement<int32_t>(Conv2DOptions::VT_STRIDE_W, stride_w, 0);
+ }
+ void add_stride_h(int32_t stride_h)
+ {
+ fbb_.AddElement<int32_t>(Conv2DOptions::VT_STRIDE_H, stride_h, 0);
+ }
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(Conv2DOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_dilation_w_factor(int32_t dilation_w_factor)
+ {
+ fbb_.AddElement<int32_t>(Conv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1);
+ }
+ void add_dilation_h_factor(int32_t dilation_h_factor)
+ {
+ fbb_.AddElement<int32_t>(Conv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1);
+ }
+ explicit Conv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Conv2DOptionsBuilder &operator=(const Conv2DOptionsBuilder &);
+ flatbuffers::Offset<Conv2DOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Conv2DOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Conv2DOptions>
+CreateConv2DOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME,
+ int32_t stride_w = 0, int32_t stride_h = 0,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ int32_t dilation_w_factor = 1, int32_t dilation_h_factor = 1)
+{
+ Conv2DOptionsBuilder builder_(_fbb);
+ builder_.add_dilation_h_factor(dilation_h_factor);
+ builder_.add_dilation_w_factor(dilation_w_factor);
+ builder_.add_stride_h(stride_h);
+ builder_.add_stride_w(stride_w);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_padding(padding);
+ return builder_.Finish();
+}
+
+struct Pool2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_PADDING = 4,
+ VT_STRIDE_W = 6,
+ VT_STRIDE_H = 8,
+ VT_FILTER_WIDTH = 10,
+ VT_FILTER_HEIGHT = 12,
+ VT_FUSED_ACTIVATION_FUNCTION = 14
+ };
+ Padding padding() const { return static_cast<Padding>(GetField<int8_t>(VT_PADDING, 0)); }
+ int32_t stride_w() const { return GetField<int32_t>(VT_STRIDE_W, 0); }
+ int32_t stride_h() const { return GetField<int32_t>(VT_STRIDE_H, 0); }
+ int32_t filter_width() const { return GetField<int32_t>(VT_FILTER_WIDTH, 0); }
+ int32_t filter_height() const { return GetField<int32_t>(VT_FILTER_HEIGHT, 0); }
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_PADDING) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_W) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_H) &&
+ VerifyField<int32_t>(verifier, VT_FILTER_WIDTH) &&
+ VerifyField<int32_t>(verifier, VT_FILTER_HEIGHT) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct Pool2DOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_padding(Padding padding)
+ {
+ fbb_.AddElement<int8_t>(Pool2DOptions::VT_PADDING, static_cast<int8_t>(padding), 0);
+ }
+ void add_stride_w(int32_t stride_w)
+ {
+ fbb_.AddElement<int32_t>(Pool2DOptions::VT_STRIDE_W, stride_w, 0);
+ }
+ void add_stride_h(int32_t stride_h)
+ {
+ fbb_.AddElement<int32_t>(Pool2DOptions::VT_STRIDE_H, stride_h, 0);
+ }
+ void add_filter_width(int32_t filter_width)
+ {
+ fbb_.AddElement<int32_t>(Pool2DOptions::VT_FILTER_WIDTH, filter_width, 0);
+ }
+ void add_filter_height(int32_t filter_height)
+ {
+ fbb_.AddElement<int32_t>(Pool2DOptions::VT_FILTER_HEIGHT, filter_height, 0);
+ }
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(Pool2DOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit Pool2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ Pool2DOptionsBuilder &operator=(const Pool2DOptionsBuilder &);
+ flatbuffers::Offset<Pool2DOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Pool2DOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Pool2DOptions>
+CreatePool2DOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME,
+ int32_t stride_w = 0, int32_t stride_h = 0, int32_t filter_width = 0,
+ int32_t filter_height = 0,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE)
+{
+ Pool2DOptionsBuilder builder_(_fbb);
+ builder_.add_filter_height(filter_height);
+ builder_.add_filter_width(filter_width);
+ builder_.add_stride_h(stride_h);
+ builder_.add_stride_w(stride_w);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_padding(padding);
+ return builder_.Finish();
+}
+
+struct DepthwiseConv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_PADDING = 4,
+ VT_STRIDE_W = 6,
+ VT_STRIDE_H = 8,
+ VT_DEPTH_MULTIPLIER = 10,
+ VT_FUSED_ACTIVATION_FUNCTION = 12,
+ VT_DILATION_W_FACTOR = 14,
+ VT_DILATION_H_FACTOR = 16
+ };
+ Padding padding() const { return static_cast<Padding>(GetField<int8_t>(VT_PADDING, 0)); }
+ int32_t stride_w() const { return GetField<int32_t>(VT_STRIDE_W, 0); }
+ int32_t stride_h() const { return GetField<int32_t>(VT_STRIDE_H, 0); }
+ int32_t depth_multiplier() const { return GetField<int32_t>(VT_DEPTH_MULTIPLIER, 0); }
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ int32_t dilation_w_factor() const { return GetField<int32_t>(VT_DILATION_W_FACTOR, 1); }
+ int32_t dilation_h_factor() const { return GetField<int32_t>(VT_DILATION_H_FACTOR, 1); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_PADDING) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_W) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_H) &&
+ VerifyField<int32_t>(verifier, VT_DEPTH_MULTIPLIER) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<int32_t>(verifier, VT_DILATION_W_FACTOR) &&
+ VerifyField<int32_t>(verifier, VT_DILATION_H_FACTOR) && verifier.EndTable();
+ }
+};
+
+struct DepthwiseConv2DOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_padding(Padding padding)
+ {
+ fbb_.AddElement<int8_t>(DepthwiseConv2DOptions::VT_PADDING, static_cast<int8_t>(padding), 0);
+ }
+ void add_stride_w(int32_t stride_w)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_STRIDE_W, stride_w, 0);
+ }
+ void add_stride_h(int32_t stride_h)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_STRIDE_H, stride_h, 0);
+ }
+ void add_depth_multiplier(int32_t depth_multiplier)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_DEPTH_MULTIPLIER, depth_multiplier, 0);
+ }
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(DepthwiseConv2DOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_dilation_w_factor(int32_t dilation_w_factor)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1);
+ }
+ void add_dilation_h_factor(int32_t dilation_h_factor)
+ {
+ fbb_.AddElement<int32_t>(DepthwiseConv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1);
+ }
+ explicit DepthwiseConv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DepthwiseConv2DOptionsBuilder &operator=(const DepthwiseConv2DOptionsBuilder &);
+ flatbuffers::Offset<DepthwiseConv2DOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DepthwiseConv2DOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DepthwiseConv2DOptions> CreateDepthwiseConv2DOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, int32_t stride_w = 0,
+ int32_t stride_h = 0, int32_t depth_multiplier = 0,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ int32_t dilation_w_factor = 1, int32_t dilation_h_factor = 1)
+{
+ DepthwiseConv2DOptionsBuilder builder_(_fbb);
+ builder_.add_dilation_h_factor(dilation_h_factor);
+ builder_.add_dilation_w_factor(dilation_w_factor);
+ builder_.add_depth_multiplier(depth_multiplier);
+ builder_.add_stride_h(stride_h);
+ builder_.add_stride_w(stride_w);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_padding(padding);
+ return builder_.Finish();
+}
+
+struct ConcatEmbeddingsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_NUM_CHANNELS = 4,
+ VT_NUM_COLUMNS_PER_CHANNEL = 6,
+ VT_EMBEDDING_DIM_PER_CHANNEL = 8
+ };
+ int32_t num_channels() const { return GetField<int32_t>(VT_NUM_CHANNELS, 0); }
+ const flatbuffers::Vector<int32_t> *num_columns_per_channel() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_NUM_COLUMNS_PER_CHANNEL);
+ }
+ const flatbuffers::Vector<int32_t> *embedding_dim_per_channel() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_EMBEDDING_DIM_PER_CHANNEL);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NUM_CHANNELS) &&
+ VerifyOffset(verifier, VT_NUM_COLUMNS_PER_CHANNEL) &&
+ verifier.VerifyVector(num_columns_per_channel()) &&
+ VerifyOffset(verifier, VT_EMBEDDING_DIM_PER_CHANNEL) &&
+ verifier.VerifyVector(embedding_dim_per_channel()) && verifier.EndTable();
+ }
+};
+
+struct ConcatEmbeddingsOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_num_channels(int32_t num_channels)
+ {
+ fbb_.AddElement<int32_t>(ConcatEmbeddingsOptions::VT_NUM_CHANNELS, num_channels, 0);
+ }
+ void add_num_columns_per_channel(
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> num_columns_per_channel)
+ {
+ fbb_.AddOffset(ConcatEmbeddingsOptions::VT_NUM_COLUMNS_PER_CHANNEL, num_columns_per_channel);
+ }
+ void add_embedding_dim_per_channel(
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> embedding_dim_per_channel)
+ {
+ fbb_.AddOffset(ConcatEmbeddingsOptions::VT_EMBEDDING_DIM_PER_CHANNEL,
+ embedding_dim_per_channel);
+ }
+ explicit ConcatEmbeddingsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ConcatEmbeddingsOptionsBuilder &operator=(const ConcatEmbeddingsOptionsBuilder &);
+ flatbuffers::Offset<ConcatEmbeddingsOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ConcatEmbeddingsOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ConcatEmbeddingsOptions> CreateConcatEmbeddingsOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, int32_t num_channels = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> num_columns_per_channel = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> embedding_dim_per_channel = 0)
+{
+ ConcatEmbeddingsOptionsBuilder builder_(_fbb);
+ builder_.add_embedding_dim_per_channel(embedding_dim_per_channel);
+ builder_.add_num_columns_per_channel(num_columns_per_channel);
+ builder_.add_num_channels(num_channels);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<ConcatEmbeddingsOptions>
+CreateConcatEmbeddingsOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb, int32_t num_channels = 0,
+ const std::vector<int32_t> *num_columns_per_channel = nullptr,
+ const std::vector<int32_t> *embedding_dim_per_channel = nullptr)
+{
+ return onert_tflite::CreateConcatEmbeddingsOptions(
+ _fbb, num_channels,
+ num_columns_per_channel ? _fbb.CreateVector<int32_t>(*num_columns_per_channel) : 0,
+ embedding_dim_per_channel ? _fbb.CreateVector<int32_t>(*embedding_dim_per_channel) : 0);
+}
+
+struct LSHProjectionOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_TYPE = 4
+ };
+ LSHProjectionType type() const
+ {
+ return static_cast<LSHProjectionType>(GetField<int8_t>(VT_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct LSHProjectionOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_type(LSHProjectionType type)
+ {
+ fbb_.AddElement<int8_t>(LSHProjectionOptions::VT_TYPE, static_cast<int8_t>(type), 0);
+ }
+ explicit LSHProjectionOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LSHProjectionOptionsBuilder &operator=(const LSHProjectionOptionsBuilder &);
+ flatbuffers::Offset<LSHProjectionOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LSHProjectionOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LSHProjectionOptions>
+CreateLSHProjectionOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ LSHProjectionType type = LSHProjectionType_UNKNOWN)
+{
+ LSHProjectionOptionsBuilder builder_(_fbb);
+ builder_.add_type(type);
+ return builder_.Finish();
+}
+
+struct SVDFOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_RANK = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 8
+ };
+ int32_t rank() const { return GetField<int32_t>(VT_RANK, 0); }
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_RANK) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct SVDFOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_rank(int32_t rank) { fbb_.AddElement<int32_t>(SVDFOptions::VT_RANK, rank, 0); }
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(SVDFOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(SVDFOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit SVDFOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SVDFOptionsBuilder &operator=(const SVDFOptionsBuilder &);
+ flatbuffers::Offset<SVDFOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SVDFOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SVDFOptions>
+CreateSVDFOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t rank = 0,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ bool asymmetric_quantize_inputs = false)
+{
+ SVDFOptionsBuilder builder_(_fbb);
+ builder_.add_rank(rank);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct RNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 6
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct RNNOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(RNNOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(RNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit RNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ RNNOptionsBuilder &operator=(const RNNOptionsBuilder &);
+ flatbuffers::Offset<RNNOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<RNNOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<RNNOptions>
+CreateRNNOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ bool asymmetric_quantize_inputs = false)
+{
+ RNNOptionsBuilder builder_(_fbb);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct SequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_TIME_MAJOR = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 8
+ };
+ bool time_major() const { return GetField<uint8_t>(VT_TIME_MAJOR, 0) != 0; }
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_TIME_MAJOR) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct SequenceRNNOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_time_major(bool time_major)
+ {
+ fbb_.AddElement<uint8_t>(SequenceRNNOptions::VT_TIME_MAJOR, static_cast<uint8_t>(time_major),
+ 0);
+ }
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(SequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(SequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit SequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SequenceRNNOptionsBuilder &operator=(const SequenceRNNOptionsBuilder &);
+ flatbuffers::Offset<SequenceRNNOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SequenceRNNOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SequenceRNNOptions> CreateSequenceRNNOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, bool time_major = false,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ bool asymmetric_quantize_inputs = false)
+{
+ SequenceRNNOptionsBuilder builder_(_fbb);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_time_major(time_major);
+ return builder_.Finish();
+}
+
+struct BidirectionalSequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_TIME_MAJOR = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6,
+ VT_MERGE_OUTPUTS = 8,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 10
+ };
+ bool time_major() const { return GetField<uint8_t>(VT_TIME_MAJOR, 0) != 0; }
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool merge_outputs() const { return GetField<uint8_t>(VT_MERGE_OUTPUTS, 0) != 0; }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_TIME_MAJOR) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<uint8_t>(verifier, VT_MERGE_OUTPUTS) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct BidirectionalSequenceRNNOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_time_major(bool time_major)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceRNNOptions::VT_TIME_MAJOR,
+ static_cast<uint8_t>(time_major), 0);
+ }
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(BidirectionalSequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_merge_outputs(bool merge_outputs)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceRNNOptions::VT_MERGE_OUTPUTS,
+ static_cast<uint8_t>(merge_outputs), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit BidirectionalSequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BidirectionalSequenceRNNOptionsBuilder &operator=(const BidirectionalSequenceRNNOptionsBuilder &);
+ flatbuffers::Offset<BidirectionalSequenceRNNOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BidirectionalSequenceRNNOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BidirectionalSequenceRNNOptions> CreateBidirectionalSequenceRNNOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, bool time_major = false,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ bool merge_outputs = false, bool asymmetric_quantize_inputs = false)
+{
+ BidirectionalSequenceRNNOptionsBuilder builder_(_fbb);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_merge_outputs(merge_outputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ builder_.add_time_major(time_major);
+ return builder_.Finish();
+}
+
+struct FullyConnectedOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_WEIGHTS_FORMAT = 6,
+ VT_KEEP_NUM_DIMS = 8,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 10
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ FullyConnectedOptionsWeightsFormat weights_format() const
+ {
+ return static_cast<FullyConnectedOptionsWeightsFormat>(GetField<int8_t>(VT_WEIGHTS_FORMAT, 0));
+ }
+ bool keep_num_dims() const { return GetField<uint8_t>(VT_KEEP_NUM_DIMS, 0) != 0; }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<int8_t>(verifier, VT_WEIGHTS_FORMAT) &&
+ VerifyField<uint8_t>(verifier, VT_KEEP_NUM_DIMS) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct FullyConnectedOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(FullyConnectedOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_weights_format(FullyConnectedOptionsWeightsFormat weights_format)
+ {
+ fbb_.AddElement<int8_t>(FullyConnectedOptions::VT_WEIGHTS_FORMAT,
+ static_cast<int8_t>(weights_format), 0);
+ }
+ void add_keep_num_dims(bool keep_num_dims)
+ {
+ fbb_.AddElement<uint8_t>(FullyConnectedOptions::VT_KEEP_NUM_DIMS,
+ static_cast<uint8_t>(keep_num_dims), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(FullyConnectedOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit FullyConnectedOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FullyConnectedOptionsBuilder &operator=(const FullyConnectedOptionsBuilder &);
+ flatbuffers::Offset<FullyConnectedOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FullyConnectedOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FullyConnectedOptions> CreateFullyConnectedOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ FullyConnectedOptionsWeightsFormat weights_format = FullyConnectedOptionsWeightsFormat_DEFAULT,
+ bool keep_num_dims = false, bool asymmetric_quantize_inputs = false)
+{
+ FullyConnectedOptionsBuilder builder_(_fbb);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_keep_num_dims(keep_num_dims);
+ builder_.add_weights_format(weights_format);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct SoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_BETA = 4
+ };
+ float beta() const { return GetField<float>(VT_BETA, 0.0f); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<float>(verifier, VT_BETA) &&
+ verifier.EndTable();
+ }
+};
+
+struct SoftmaxOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_beta(float beta) { fbb_.AddElement<float>(SoftmaxOptions::VT_BETA, beta, 0.0f); }
+ explicit SoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SoftmaxOptionsBuilder &operator=(const SoftmaxOptionsBuilder &);
+ flatbuffers::Offset<SoftmaxOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SoftmaxOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SoftmaxOptions>
+CreateSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb, float beta = 0.0f)
+{
+ SoftmaxOptionsBuilder builder_(_fbb);
+ builder_.add_beta(beta);
+ return builder_.Finish();
+}
+
+struct ConcatenationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_AXIS = 4,
+ VT_FUSED_ACTIVATION_FUNCTION = 6
+ };
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_AXIS) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct ConcatenationOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(ConcatenationOptions::VT_AXIS, axis, 0); }
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(ConcatenationOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit ConcatenationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ConcatenationOptionsBuilder &operator=(const ConcatenationOptionsBuilder &);
+ flatbuffers::Offset<ConcatenationOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ConcatenationOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ConcatenationOptions> CreateConcatenationOptions(
+ flatbuffers::FlatBufferBuilder &_fbb, int32_t axis = 0,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE)
+{
+ ConcatenationOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct AddOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct AddOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(AddOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit AddOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ AddOptionsBuilder &operator=(const AddOptionsBuilder &);
+ flatbuffers::Offset<AddOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<AddOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<AddOptions>
+CreateAddOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE)
+{
+ AddOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct MulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct MulOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(MulOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit MulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MulOptionsBuilder &operator=(const MulOptionsBuilder &);
+ flatbuffers::Offset<MulOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MulOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MulOptions>
+CreateMulOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE)
+{
+ MulOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct L2NormOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct L2NormOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(L2NormOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit L2NormOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ L2NormOptionsBuilder &operator=(const L2NormOptionsBuilder &);
+ flatbuffers::Offset<L2NormOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<L2NormOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<L2NormOptions>
+CreateL2NormOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE)
+{
+ L2NormOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct LocalResponseNormalizationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_RADIUS = 4,
+ VT_BIAS = 6,
+ VT_ALPHA = 8,
+ VT_BETA = 10
+ };
+ int32_t radius() const { return GetField<int32_t>(VT_RADIUS, 0); }
+ float bias() const { return GetField<float>(VT_BIAS, 0.0f); }
+ float alpha() const { return GetField<float>(VT_ALPHA, 0.0f); }
+ float beta() const { return GetField<float>(VT_BETA, 0.0f); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_RADIUS) &&
+ VerifyField<float>(verifier, VT_BIAS) && VerifyField<float>(verifier, VT_ALPHA) &&
+ VerifyField<float>(verifier, VT_BETA) && verifier.EndTable();
+ }
+};
+
+struct LocalResponseNormalizationOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_radius(int32_t radius)
+ {
+ fbb_.AddElement<int32_t>(LocalResponseNormalizationOptions::VT_RADIUS, radius, 0);
+ }
+ void add_bias(float bias)
+ {
+ fbb_.AddElement<float>(LocalResponseNormalizationOptions::VT_BIAS, bias, 0.0f);
+ }
+ void add_alpha(float alpha)
+ {
+ fbb_.AddElement<float>(LocalResponseNormalizationOptions::VT_ALPHA, alpha, 0.0f);
+ }
+ void add_beta(float beta)
+ {
+ fbb_.AddElement<float>(LocalResponseNormalizationOptions::VT_BETA, beta, 0.0f);
+ }
+ explicit LocalResponseNormalizationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LocalResponseNormalizationOptionsBuilder &
+ operator=(const LocalResponseNormalizationOptionsBuilder &);
+ flatbuffers::Offset<LocalResponseNormalizationOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LocalResponseNormalizationOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LocalResponseNormalizationOptions>
+CreateLocalResponseNormalizationOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t radius = 0,
+ float bias = 0.0f, float alpha = 0.0f, float beta = 0.0f)
+{
+ LocalResponseNormalizationOptionsBuilder builder_(_fbb);
+ builder_.add_beta(beta);
+ builder_.add_alpha(alpha);
+ builder_.add_bias(bias);
+ builder_.add_radius(radius);
+ return builder_.Finish();
+}
+
+struct LSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_CELL_CLIP = 6,
+ VT_PROJ_CLIP = 8,
+ VT_KERNEL_TYPE = 10,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 12
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ float cell_clip() const { return GetField<float>(VT_CELL_CLIP, 0.0f); }
+ float proj_clip() const { return GetField<float>(VT_PROJ_CLIP, 0.0f); }
+ LSTMKernelType kernel_type() const
+ {
+ return static_cast<LSTMKernelType>(GetField<int8_t>(VT_KERNEL_TYPE, 0));
+ }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<float>(verifier, VT_CELL_CLIP) &&
+ VerifyField<float>(verifier, VT_PROJ_CLIP) &&
+ VerifyField<int8_t>(verifier, VT_KERNEL_TYPE) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct LSTMOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(LSTMOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_cell_clip(float cell_clip)
+ {
+ fbb_.AddElement<float>(LSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f);
+ }
+ void add_proj_clip(float proj_clip)
+ {
+ fbb_.AddElement<float>(LSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f);
+ }
+ void add_kernel_type(LSTMKernelType kernel_type)
+ {
+ fbb_.AddElement<int8_t>(LSTMOptions::VT_KERNEL_TYPE, static_cast<int8_t>(kernel_type), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(LSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit LSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LSTMOptionsBuilder &operator=(const LSTMOptionsBuilder &);
+ flatbuffers::Offset<LSTMOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LSTMOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LSTMOptions>
+CreateLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ float cell_clip = 0.0f, float proj_clip = 0.0f,
+ LSTMKernelType kernel_type = LSTMKernelType_FULL,
+ bool asymmetric_quantize_inputs = false)
+{
+ LSTMOptionsBuilder builder_(_fbb);
+ builder_.add_proj_clip(proj_clip);
+ builder_.add_cell_clip(cell_clip);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_kernel_type(kernel_type);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct UnidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_CELL_CLIP = 6,
+ VT_PROJ_CLIP = 8,
+ VT_TIME_MAJOR = 10,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 12
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ float cell_clip() const { return GetField<float>(VT_CELL_CLIP, 0.0f); }
+ float proj_clip() const { return GetField<float>(VT_PROJ_CLIP, 0.0f); }
+ bool time_major() const { return GetField<uint8_t>(VT_TIME_MAJOR, 0) != 0; }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<float>(verifier, VT_CELL_CLIP) &&
+ VerifyField<float>(verifier, VT_PROJ_CLIP) &&
+ VerifyField<uint8_t>(verifier, VT_TIME_MAJOR) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct UnidirectionalSequenceLSTMOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(UnidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_cell_clip(float cell_clip)
+ {
+ fbb_.AddElement<float>(UnidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f);
+ }
+ void add_proj_clip(float proj_clip)
+ {
+ fbb_.AddElement<float>(UnidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f);
+ }
+ void add_time_major(bool time_major)
+ {
+ fbb_.AddElement<uint8_t>(UnidirectionalSequenceLSTMOptions::VT_TIME_MAJOR,
+ static_cast<uint8_t>(time_major), 0);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(UnidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit UnidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ UnidirectionalSequenceLSTMOptionsBuilder &
+ operator=(const UnidirectionalSequenceLSTMOptionsBuilder &);
+ flatbuffers::Offset<UnidirectionalSequenceLSTMOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<UnidirectionalSequenceLSTMOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<UnidirectionalSequenceLSTMOptions>
+CreateUnidirectionalSequenceLSTMOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ float cell_clip = 0.0f, float proj_clip = 0.0f, bool time_major = false,
+ bool asymmetric_quantize_inputs = false)
+{
+ UnidirectionalSequenceLSTMOptionsBuilder builder_(_fbb);
+ builder_.add_proj_clip(proj_clip);
+ builder_.add_cell_clip(cell_clip);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_time_major(time_major);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct BidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4,
+ VT_CELL_CLIP = 6,
+ VT_PROJ_CLIP = 8,
+ VT_MERGE_OUTPUTS = 10,
+ VT_TIME_MAJOR = 12,
+ VT_ASYMMETRIC_QUANTIZE_INPUTS = 14
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ float cell_clip() const { return GetField<float>(VT_CELL_CLIP, 0.0f); }
+ float proj_clip() const { return GetField<float>(VT_PROJ_CLIP, 0.0f); }
+ bool merge_outputs() const { return GetField<uint8_t>(VT_MERGE_OUTPUTS, 0) != 0; }
+ bool time_major() const { return GetField<uint8_t>(VT_TIME_MAJOR, 1) != 0; }
+ bool asymmetric_quantize_inputs() const
+ {
+ return GetField<uint8_t>(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) &&
+ VerifyField<float>(verifier, VT_CELL_CLIP) &&
+ VerifyField<float>(verifier, VT_PROJ_CLIP) &&
+ VerifyField<uint8_t>(verifier, VT_MERGE_OUTPUTS) &&
+ VerifyField<uint8_t>(verifier, VT_TIME_MAJOR) &&
+ VerifyField<uint8_t>(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable();
+ }
+};
+
+struct BidirectionalSequenceLSTMOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(BidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ void add_cell_clip(float cell_clip)
+ {
+ fbb_.AddElement<float>(BidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f);
+ }
+ void add_proj_clip(float proj_clip)
+ {
+ fbb_.AddElement<float>(BidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f);
+ }
+ void add_merge_outputs(bool merge_outputs)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceLSTMOptions::VT_MERGE_OUTPUTS,
+ static_cast<uint8_t>(merge_outputs), 0);
+ }
+ void add_time_major(bool time_major)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceLSTMOptions::VT_TIME_MAJOR,
+ static_cast<uint8_t>(time_major), 1);
+ }
+ void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs)
+ {
+ fbb_.AddElement<uint8_t>(BidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS,
+ static_cast<uint8_t>(asymmetric_quantize_inputs), 0);
+ }
+ explicit BidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BidirectionalSequenceLSTMOptionsBuilder &
+ operator=(const BidirectionalSequenceLSTMOptionsBuilder &);
+ flatbuffers::Offset<BidirectionalSequenceLSTMOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BidirectionalSequenceLSTMOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BidirectionalSequenceLSTMOptions> CreateBidirectionalSequenceLSTMOptions(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE,
+ float cell_clip = 0.0f, float proj_clip = 0.0f, bool merge_outputs = false,
+ bool time_major = true, bool asymmetric_quantize_inputs = false)
+{
+ BidirectionalSequenceLSTMOptionsBuilder builder_(_fbb);
+ builder_.add_proj_clip(proj_clip);
+ builder_.add_cell_clip(cell_clip);
+ builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs);
+ builder_.add_time_major(time_major);
+ builder_.add_merge_outputs(merge_outputs);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct ResizeBilinearOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_ALIGN_CORNERS = 8,
+ VT_HALF_PIXEL_CENTERS = 10
+ };
+ bool align_corners() const { return GetField<uint8_t>(VT_ALIGN_CORNERS, 0) != 0; }
+ bool half_pixel_centers() const { return GetField<uint8_t>(VT_HALF_PIXEL_CENTERS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_ALIGN_CORNERS) &&
+ VerifyField<uint8_t>(verifier, VT_HALF_PIXEL_CENTERS) && verifier.EndTable();
+ }
+};
+
+struct ResizeBilinearOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_align_corners(bool align_corners)
+ {
+ fbb_.AddElement<uint8_t>(ResizeBilinearOptions::VT_ALIGN_CORNERS,
+ static_cast<uint8_t>(align_corners), 0);
+ }
+ void add_half_pixel_centers(bool half_pixel_centers)
+ {
+ fbb_.AddElement<uint8_t>(ResizeBilinearOptions::VT_HALF_PIXEL_CENTERS,
+ static_cast<uint8_t>(half_pixel_centers), 0);
+ }
+ explicit ResizeBilinearOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ResizeBilinearOptionsBuilder &operator=(const ResizeBilinearOptionsBuilder &);
+ flatbuffers::Offset<ResizeBilinearOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ResizeBilinearOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ResizeBilinearOptions>
+CreateResizeBilinearOptions(flatbuffers::FlatBufferBuilder &_fbb, bool align_corners = false,
+ bool half_pixel_centers = false)
+{
+ ResizeBilinearOptionsBuilder builder_(_fbb);
+ builder_.add_half_pixel_centers(half_pixel_centers);
+ builder_.add_align_corners(align_corners);
+ return builder_.Finish();
+}
+
+struct ResizeNearestNeighborOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_ALIGN_CORNERS = 4
+ };
+ bool align_corners() const { return GetField<uint8_t>(VT_ALIGN_CORNERS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_ALIGN_CORNERS) &&
+ verifier.EndTable();
+ }
+};
+
+struct ResizeNearestNeighborOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_align_corners(bool align_corners)
+ {
+ fbb_.AddElement<uint8_t>(ResizeNearestNeighborOptions::VT_ALIGN_CORNERS,
+ static_cast<uint8_t>(align_corners), 0);
+ }
+ explicit ResizeNearestNeighborOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ResizeNearestNeighborOptionsBuilder &operator=(const ResizeNearestNeighborOptionsBuilder &);
+ flatbuffers::Offset<ResizeNearestNeighborOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ResizeNearestNeighborOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ResizeNearestNeighborOptions>
+CreateResizeNearestNeighborOptions(flatbuffers::FlatBufferBuilder &_fbb, bool align_corners = false)
+{
+ ResizeNearestNeighborOptionsBuilder builder_(_fbb);
+ builder_.add_align_corners(align_corners);
+ return builder_.Finish();
+}
+
+struct CallOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_SUBGRAPH = 4
+ };
+ uint32_t subgraph() const { return GetField<uint32_t>(VT_SUBGRAPH, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint32_t>(verifier, VT_SUBGRAPH) &&
+ verifier.EndTable();
+ }
+};
+
+struct CallOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_subgraph(uint32_t subgraph)
+ {
+ fbb_.AddElement<uint32_t>(CallOptions::VT_SUBGRAPH, subgraph, 0);
+ }
+ explicit CallOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ CallOptionsBuilder &operator=(const CallOptionsBuilder &);
+ flatbuffers::Offset<CallOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CallOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CallOptions> CreateCallOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t subgraph = 0)
+{
+ CallOptionsBuilder builder_(_fbb);
+ builder_.add_subgraph(subgraph);
+ return builder_.Finish();
+}
+
+struct PadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct PadOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ PadOptionsBuilder &operator=(const PadOptionsBuilder &);
+ flatbuffers::Offset<PadOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PadOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PadOptions> CreatePadOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ PadOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct PadV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct PadV2OptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PadV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ PadV2OptionsBuilder &operator=(const PadV2OptionsBuilder &);
+ flatbuffers::Offset<PadV2Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PadV2Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PadV2Options> CreatePadV2Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ PadV2OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ReshapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_NEW_SHAPE = 4
+ };
+ const flatbuffers::Vector<int32_t> *new_shape() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_NEW_SHAPE);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NEW_SHAPE) &&
+ verifier.VerifyVector(new_shape()) && verifier.EndTable();
+ }
+};
+
+struct ReshapeOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_new_shape(flatbuffers::Offset<flatbuffers::Vector<int32_t>> new_shape)
+ {
+ fbb_.AddOffset(ReshapeOptions::VT_NEW_SHAPE, new_shape);
+ }
+ explicit ReshapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ReshapeOptionsBuilder &operator=(const ReshapeOptionsBuilder &);
+ flatbuffers::Offset<ReshapeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ReshapeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ReshapeOptions>
+CreateReshapeOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> new_shape = 0)
+{
+ ReshapeOptionsBuilder builder_(_fbb);
+ builder_.add_new_shape(new_shape);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<ReshapeOptions>
+CreateReshapeOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<int32_t> *new_shape = nullptr)
+{
+ return onert_tflite::CreateReshapeOptions(_fbb,
+ new_shape ? _fbb.CreateVector<int32_t>(*new_shape) : 0);
+}
+
+struct SpaceToBatchNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SpaceToBatchNDOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SpaceToBatchNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SpaceToBatchNDOptionsBuilder &operator=(const SpaceToBatchNDOptionsBuilder &);
+ flatbuffers::Offset<SpaceToBatchNDOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SpaceToBatchNDOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SpaceToBatchNDOptions>
+CreateSpaceToBatchNDOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SpaceToBatchNDOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct BatchToSpaceNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct BatchToSpaceNDOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit BatchToSpaceNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BatchToSpaceNDOptionsBuilder &operator=(const BatchToSpaceNDOptionsBuilder &);
+ flatbuffers::Offset<BatchToSpaceNDOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BatchToSpaceNDOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BatchToSpaceNDOptions>
+CreateBatchToSpaceNDOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ BatchToSpaceNDOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SkipGramOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_NGRAM_SIZE = 4,
+ VT_MAX_SKIP_SIZE = 6,
+ VT_INCLUDE_ALL_NGRAMS = 8
+ };
+ int32_t ngram_size() const { return GetField<int32_t>(VT_NGRAM_SIZE, 0); }
+ int32_t max_skip_size() const { return GetField<int32_t>(VT_MAX_SKIP_SIZE, 0); }
+ bool include_all_ngrams() const { return GetField<uint8_t>(VT_INCLUDE_ALL_NGRAMS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NGRAM_SIZE) &&
+ VerifyField<int32_t>(verifier, VT_MAX_SKIP_SIZE) &&
+ VerifyField<uint8_t>(verifier, VT_INCLUDE_ALL_NGRAMS) && verifier.EndTable();
+ }
+};
+
+struct SkipGramOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_ngram_size(int32_t ngram_size)
+ {
+ fbb_.AddElement<int32_t>(SkipGramOptions::VT_NGRAM_SIZE, ngram_size, 0);
+ }
+ void add_max_skip_size(int32_t max_skip_size)
+ {
+ fbb_.AddElement<int32_t>(SkipGramOptions::VT_MAX_SKIP_SIZE, max_skip_size, 0);
+ }
+ void add_include_all_ngrams(bool include_all_ngrams)
+ {
+ fbb_.AddElement<uint8_t>(SkipGramOptions::VT_INCLUDE_ALL_NGRAMS,
+ static_cast<uint8_t>(include_all_ngrams), 0);
+ }
+ explicit SkipGramOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SkipGramOptionsBuilder &operator=(const SkipGramOptionsBuilder &);
+ flatbuffers::Offset<SkipGramOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SkipGramOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SkipGramOptions>
+CreateSkipGramOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t ngram_size = 0,
+ int32_t max_skip_size = 0, bool include_all_ngrams = false)
+{
+ SkipGramOptionsBuilder builder_(_fbb);
+ builder_.add_max_skip_size(max_skip_size);
+ builder_.add_ngram_size(ngram_size);
+ builder_.add_include_all_ngrams(include_all_ngrams);
+ return builder_.Finish();
+}
+
+struct SpaceToDepthOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_BLOCK_SIZE = 4
+ };
+ int32_t block_size() const { return GetField<int32_t>(VT_BLOCK_SIZE, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_BLOCK_SIZE) &&
+ verifier.EndTable();
+ }
+};
+
+struct SpaceToDepthOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_block_size(int32_t block_size)
+ {
+ fbb_.AddElement<int32_t>(SpaceToDepthOptions::VT_BLOCK_SIZE, block_size, 0);
+ }
+ explicit SpaceToDepthOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SpaceToDepthOptionsBuilder &operator=(const SpaceToDepthOptionsBuilder &);
+ flatbuffers::Offset<SpaceToDepthOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SpaceToDepthOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SpaceToDepthOptions>
+CreateSpaceToDepthOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t block_size = 0)
+{
+ SpaceToDepthOptionsBuilder builder_(_fbb);
+ builder_.add_block_size(block_size);
+ return builder_.Finish();
+}
+
+struct DepthToSpaceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_BLOCK_SIZE = 4
+ };
+ int32_t block_size() const { return GetField<int32_t>(VT_BLOCK_SIZE, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_BLOCK_SIZE) &&
+ verifier.EndTable();
+ }
+};
+
+struct DepthToSpaceOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_block_size(int32_t block_size)
+ {
+ fbb_.AddElement<int32_t>(DepthToSpaceOptions::VT_BLOCK_SIZE, block_size, 0);
+ }
+ explicit DepthToSpaceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DepthToSpaceOptionsBuilder &operator=(const DepthToSpaceOptionsBuilder &);
+ flatbuffers::Offset<DepthToSpaceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DepthToSpaceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DepthToSpaceOptions>
+CreateDepthToSpaceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t block_size = 0)
+{
+ DepthToSpaceOptionsBuilder builder_(_fbb);
+ builder_.add_block_size(block_size);
+ return builder_.Finish();
+}
+
+struct SubOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct SubOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(SubOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit SubOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SubOptionsBuilder &operator=(const SubOptionsBuilder &);
+ flatbuffers::Offset<SubOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SubOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SubOptions>
+CreateSubOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE)
+{
+ SubOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct DivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_FUSED_ACTIVATION_FUNCTION = 4
+ };
+ ActivationFunctionType fused_activation_function() const
+ {
+ return static_cast<ActivationFunctionType>(GetField<int8_t>(VT_FUSED_ACTIVATION_FUNCTION, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable();
+ }
+};
+
+struct DivOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_fused_activation_function(ActivationFunctionType fused_activation_function)
+ {
+ fbb_.AddElement<int8_t>(DivOptions::VT_FUSED_ACTIVATION_FUNCTION,
+ static_cast<int8_t>(fused_activation_function), 0);
+ }
+ explicit DivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DivOptionsBuilder &operator=(const DivOptionsBuilder &);
+ flatbuffers::Offset<DivOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DivOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DivOptions>
+CreateDivOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE)
+{
+ DivOptionsBuilder builder_(_fbb);
+ builder_.add_fused_activation_function(fused_activation_function);
+ return builder_.Finish();
+}
+
+struct TopKV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct TopKV2OptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit TopKV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TopKV2OptionsBuilder &operator=(const TopKV2OptionsBuilder &);
+ flatbuffers::Offset<TopKV2Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TopKV2Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TopKV2Options> CreateTopKV2Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ TopKV2OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct EmbeddingLookupSparseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_COMBINER = 4
+ };
+ CombinerType combiner() const
+ {
+ return static_cast<CombinerType>(GetField<int8_t>(VT_COMBINER, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_COMBINER) &&
+ verifier.EndTable();
+ }
+};
+
+struct EmbeddingLookupSparseOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_combiner(CombinerType combiner)
+ {
+ fbb_.AddElement<int8_t>(EmbeddingLookupSparseOptions::VT_COMBINER,
+ static_cast<int8_t>(combiner), 0);
+ }
+ explicit EmbeddingLookupSparseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ EmbeddingLookupSparseOptionsBuilder &operator=(const EmbeddingLookupSparseOptionsBuilder &);
+ flatbuffers::Offset<EmbeddingLookupSparseOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<EmbeddingLookupSparseOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<EmbeddingLookupSparseOptions>
+CreateEmbeddingLookupSparseOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ CombinerType combiner = CombinerType_SUM)
+{
+ EmbeddingLookupSparseOptionsBuilder builder_(_fbb);
+ builder_.add_combiner(combiner);
+ return builder_.Finish();
+}
+
+struct GatherOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_AXIS = 4
+ };
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_AXIS) &&
+ verifier.EndTable();
+ }
+};
+
+struct GatherOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(GatherOptions::VT_AXIS, axis, 0); }
+ explicit GatherOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ GatherOptionsBuilder &operator=(const GatherOptionsBuilder &);
+ flatbuffers::Offset<GatherOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<GatherOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<GatherOptions> CreateGatherOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t axis = 0)
+{
+ GatherOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ return builder_.Finish();
+}
+
+struct TransposeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct TransposeOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit TransposeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TransposeOptionsBuilder &operator=(const TransposeOptionsBuilder &);
+ flatbuffers::Offset<TransposeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TransposeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TransposeOptions>
+CreateTransposeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ TransposeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ExpOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ExpOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ExpOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ExpOptionsBuilder &operator=(const ExpOptionsBuilder &);
+ flatbuffers::Offset<ExpOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ExpOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ExpOptions> CreateExpOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ExpOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct CosOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct CosOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit CosOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ CosOptionsBuilder &operator=(const CosOptionsBuilder &);
+ flatbuffers::Offset<CosOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CosOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CosOptions> CreateCosOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ CosOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ReducerOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_KEEP_DIMS = 4
+ };
+ bool keep_dims() const { return GetField<uint8_t>(VT_KEEP_DIMS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_KEEP_DIMS) &&
+ verifier.EndTable();
+ }
+};
+
+struct ReducerOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_keep_dims(bool keep_dims)
+ {
+ fbb_.AddElement<uint8_t>(ReducerOptions::VT_KEEP_DIMS, static_cast<uint8_t>(keep_dims), 0);
+ }
+ explicit ReducerOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ReducerOptionsBuilder &operator=(const ReducerOptionsBuilder &);
+ flatbuffers::Offset<ReducerOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ReducerOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ReducerOptions>
+CreateReducerOptions(flatbuffers::FlatBufferBuilder &_fbb, bool keep_dims = false)
+{
+ ReducerOptionsBuilder builder_(_fbb);
+ builder_.add_keep_dims(keep_dims);
+ return builder_.Finish();
+}
+
+struct SqueezeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_SQUEEZE_DIMS = 4
+ };
+ const flatbuffers::Vector<int32_t> *squeeze_dims() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_SQUEEZE_DIMS);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SQUEEZE_DIMS) &&
+ verifier.VerifyVector(squeeze_dims()) && verifier.EndTable();
+ }
+};
+
+struct SqueezeOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_squeeze_dims(flatbuffers::Offset<flatbuffers::Vector<int32_t>> squeeze_dims)
+ {
+ fbb_.AddOffset(SqueezeOptions::VT_SQUEEZE_DIMS, squeeze_dims);
+ }
+ explicit SqueezeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SqueezeOptionsBuilder &operator=(const SqueezeOptionsBuilder &);
+ flatbuffers::Offset<SqueezeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SqueezeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SqueezeOptions>
+CreateSqueezeOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> squeeze_dims = 0)
+{
+ SqueezeOptionsBuilder builder_(_fbb);
+ builder_.add_squeeze_dims(squeeze_dims);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<SqueezeOptions>
+CreateSqueezeOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<int32_t> *squeeze_dims = nullptr)
+{
+ return onert_tflite::CreateSqueezeOptions(
+ _fbb, squeeze_dims ? _fbb.CreateVector<int32_t>(*squeeze_dims) : 0);
+}
+
+struct SplitOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_NUM_SPLITS = 4
+ };
+ int32_t num_splits() const { return GetField<int32_t>(VT_NUM_SPLITS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NUM_SPLITS) &&
+ verifier.EndTable();
+ }
+};
+
+struct SplitOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_num_splits(int32_t num_splits)
+ {
+ fbb_.AddElement<int32_t>(SplitOptions::VT_NUM_SPLITS, num_splits, 0);
+ }
+ explicit SplitOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SplitOptionsBuilder &operator=(const SplitOptionsBuilder &);
+ flatbuffers::Offset<SplitOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SplitOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SplitOptions> CreateSplitOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t num_splits = 0)
+{
+ SplitOptionsBuilder builder_(_fbb);
+ builder_.add_num_splits(num_splits);
+ return builder_.Finish();
+}
+
+struct SplitVOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_NUM_SPLITS = 4
+ };
+ int32_t num_splits() const { return GetField<int32_t>(VT_NUM_SPLITS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NUM_SPLITS) &&
+ verifier.EndTable();
+ }
+};
+
+struct SplitVOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_num_splits(int32_t num_splits)
+ {
+ fbb_.AddElement<int32_t>(SplitVOptions::VT_NUM_SPLITS, num_splits, 0);
+ }
+ explicit SplitVOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SplitVOptionsBuilder &operator=(const SplitVOptionsBuilder &);
+ flatbuffers::Offset<SplitVOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SplitVOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SplitVOptions> CreateSplitVOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t num_splits = 0)
+{
+ SplitVOptionsBuilder builder_(_fbb);
+ builder_.add_num_splits(num_splits);
+ return builder_.Finish();
+}
+
+struct StridedSliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_BEGIN_MASK = 4,
+ VT_END_MASK = 6,
+ VT_ELLIPSIS_MASK = 8,
+ VT_NEW_AXIS_MASK = 10,
+ VT_SHRINK_AXIS_MASK = 12
+ };
+ int32_t begin_mask() const { return GetField<int32_t>(VT_BEGIN_MASK, 0); }
+ int32_t end_mask() const { return GetField<int32_t>(VT_END_MASK, 0); }
+ int32_t ellipsis_mask() const { return GetField<int32_t>(VT_ELLIPSIS_MASK, 0); }
+ int32_t new_axis_mask() const { return GetField<int32_t>(VT_NEW_AXIS_MASK, 0); }
+ int32_t shrink_axis_mask() const { return GetField<int32_t>(VT_SHRINK_AXIS_MASK, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_BEGIN_MASK) &&
+ VerifyField<int32_t>(verifier, VT_END_MASK) &&
+ VerifyField<int32_t>(verifier, VT_ELLIPSIS_MASK) &&
+ VerifyField<int32_t>(verifier, VT_NEW_AXIS_MASK) &&
+ VerifyField<int32_t>(verifier, VT_SHRINK_AXIS_MASK) && verifier.EndTable();
+ }
+};
+
+struct StridedSliceOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_begin_mask(int32_t begin_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_BEGIN_MASK, begin_mask, 0);
+ }
+ void add_end_mask(int32_t end_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_END_MASK, end_mask, 0);
+ }
+ void add_ellipsis_mask(int32_t ellipsis_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_ELLIPSIS_MASK, ellipsis_mask, 0);
+ }
+ void add_new_axis_mask(int32_t new_axis_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_NEW_AXIS_MASK, new_axis_mask, 0);
+ }
+ void add_shrink_axis_mask(int32_t shrink_axis_mask)
+ {
+ fbb_.AddElement<int32_t>(StridedSliceOptions::VT_SHRINK_AXIS_MASK, shrink_axis_mask, 0);
+ }
+ explicit StridedSliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ StridedSliceOptionsBuilder &operator=(const StridedSliceOptionsBuilder &);
+ flatbuffers::Offset<StridedSliceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<StridedSliceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<StridedSliceOptions>
+CreateStridedSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t begin_mask = 0,
+ int32_t end_mask = 0, int32_t ellipsis_mask = 0,
+ int32_t new_axis_mask = 0, int32_t shrink_axis_mask = 0)
+{
+ StridedSliceOptionsBuilder builder_(_fbb);
+ builder_.add_shrink_axis_mask(shrink_axis_mask);
+ builder_.add_new_axis_mask(new_axis_mask);
+ builder_.add_ellipsis_mask(ellipsis_mask);
+ builder_.add_end_mask(end_mask);
+ builder_.add_begin_mask(begin_mask);
+ return builder_.Finish();
+}
+
+struct LogSoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LogSoftmaxOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LogSoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LogSoftmaxOptionsBuilder &operator=(const LogSoftmaxOptionsBuilder &);
+ flatbuffers::Offset<LogSoftmaxOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LogSoftmaxOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LogSoftmaxOptions>
+CreateLogSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LogSoftmaxOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct CastOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_IN_DATA_TYPE = 4,
+ VT_OUT_DATA_TYPE = 6
+ };
+ TensorType in_data_type() const
+ {
+ return static_cast<TensorType>(GetField<int8_t>(VT_IN_DATA_TYPE, 0));
+ }
+ TensorType out_data_type() const
+ {
+ return static_cast<TensorType>(GetField<int8_t>(VT_OUT_DATA_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_IN_DATA_TYPE) &&
+ VerifyField<int8_t>(verifier, VT_OUT_DATA_TYPE) && verifier.EndTable();
+ }
+};
+
+struct CastOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_in_data_type(TensorType in_data_type)
+ {
+ fbb_.AddElement<int8_t>(CastOptions::VT_IN_DATA_TYPE, static_cast<int8_t>(in_data_type), 0);
+ }
+ void add_out_data_type(TensorType out_data_type)
+ {
+ fbb_.AddElement<int8_t>(CastOptions::VT_OUT_DATA_TYPE, static_cast<int8_t>(out_data_type), 0);
+ }
+ explicit CastOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ CastOptionsBuilder &operator=(const CastOptionsBuilder &);
+ flatbuffers::Offset<CastOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CastOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CastOptions>
+CreateCastOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ TensorType in_data_type = TensorType_FLOAT32,
+ TensorType out_data_type = TensorType_FLOAT32)
+{
+ CastOptionsBuilder builder_(_fbb);
+ builder_.add_out_data_type(out_data_type);
+ builder_.add_in_data_type(in_data_type);
+ return builder_.Finish();
+}
+
+struct DequantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct DequantizeOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit DequantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DequantizeOptionsBuilder &operator=(const DequantizeOptionsBuilder &);
+ flatbuffers::Offset<DequantizeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DequantizeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DequantizeOptions>
+CreateDequantizeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ DequantizeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct MaximumMinimumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct MaximumMinimumOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit MaximumMinimumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MaximumMinimumOptionsBuilder &operator=(const MaximumMinimumOptionsBuilder &);
+ flatbuffers::Offset<MaximumMinimumOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MaximumMinimumOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MaximumMinimumOptions>
+CreateMaximumMinimumOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ MaximumMinimumOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct TileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct TileOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit TileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TileOptionsBuilder &operator=(const TileOptionsBuilder &);
+ flatbuffers::Offset<TileOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TileOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TileOptions> CreateTileOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ TileOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ArgMaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_OUTPUT_TYPE = 4
+ };
+ TensorType output_type() const
+ {
+ return static_cast<TensorType>(GetField<int8_t>(VT_OUTPUT_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_OUTPUT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct ArgMaxOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_output_type(TensorType output_type)
+ {
+ fbb_.AddElement<int8_t>(ArgMaxOptions::VT_OUTPUT_TYPE, static_cast<int8_t>(output_type), 0);
+ }
+ explicit ArgMaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ArgMaxOptionsBuilder &operator=(const ArgMaxOptionsBuilder &);
+ flatbuffers::Offset<ArgMaxOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ArgMaxOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ArgMaxOptions>
+CreateArgMaxOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ TensorType output_type = TensorType_FLOAT32)
+{
+ ArgMaxOptionsBuilder builder_(_fbb);
+ builder_.add_output_type(output_type);
+ return builder_.Finish();
+}
+
+struct ArgMinOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_OUTPUT_TYPE = 4
+ };
+ TensorType output_type() const
+ {
+ return static_cast<TensorType>(GetField<int8_t>(VT_OUTPUT_TYPE, 0));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_OUTPUT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct ArgMinOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_output_type(TensorType output_type)
+ {
+ fbb_.AddElement<int8_t>(ArgMinOptions::VT_OUTPUT_TYPE, static_cast<int8_t>(output_type), 0);
+ }
+ explicit ArgMinOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ArgMinOptionsBuilder &operator=(const ArgMinOptionsBuilder &);
+ flatbuffers::Offset<ArgMinOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ArgMinOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ArgMinOptions>
+CreateArgMinOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ TensorType output_type = TensorType_FLOAT32)
+{
+ ArgMinOptionsBuilder builder_(_fbb);
+ builder_.add_output_type(output_type);
+ return builder_.Finish();
+}
+
+struct GreaterOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct GreaterOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit GreaterOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ GreaterOptionsBuilder &operator=(const GreaterOptionsBuilder &);
+ flatbuffers::Offset<GreaterOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<GreaterOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<GreaterOptions>
+CreateGreaterOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ GreaterOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct GreaterEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct GreaterEqualOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit GreaterEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ GreaterEqualOptionsBuilder &operator=(const GreaterEqualOptionsBuilder &);
+ flatbuffers::Offset<GreaterEqualOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<GreaterEqualOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<GreaterEqualOptions>
+CreateGreaterEqualOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ GreaterEqualOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LessOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LessOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LessOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LessOptionsBuilder &operator=(const LessOptionsBuilder &);
+ flatbuffers::Offset<LessOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LessOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LessOptions> CreateLessOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LessOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LessEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LessEqualOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LessEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LessEqualOptionsBuilder &operator=(const LessEqualOptionsBuilder &);
+ flatbuffers::Offset<LessEqualOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LessEqualOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LessEqualOptions>
+CreateLessEqualOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LessEqualOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct NegOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct NegOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit NegOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ NegOptionsBuilder &operator=(const NegOptionsBuilder &);
+ flatbuffers::Offset<NegOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NegOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NegOptions> CreateNegOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ NegOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SelectOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SelectOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SelectOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SelectOptionsBuilder &operator=(const SelectOptionsBuilder &);
+ flatbuffers::Offset<SelectOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SelectOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SelectOptions> CreateSelectOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SelectOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SliceOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SliceOptionsBuilder &operator=(const SliceOptionsBuilder &);
+ flatbuffers::Offset<SliceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SliceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SliceOptions> CreateSliceOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SliceOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct TransposeConvOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_PADDING = 4,
+ VT_STRIDE_W = 6,
+ VT_STRIDE_H = 8
+ };
+ Padding padding() const { return static_cast<Padding>(GetField<int8_t>(VT_PADDING, 0)); }
+ int32_t stride_w() const { return GetField<int32_t>(VT_STRIDE_W, 0); }
+ int32_t stride_h() const { return GetField<int32_t>(VT_STRIDE_H, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_PADDING) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_W) &&
+ VerifyField<int32_t>(verifier, VT_STRIDE_H) && verifier.EndTable();
+ }
+};
+
+struct TransposeConvOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_padding(Padding padding)
+ {
+ fbb_.AddElement<int8_t>(TransposeConvOptions::VT_PADDING, static_cast<int8_t>(padding), 0);
+ }
+ void add_stride_w(int32_t stride_w)
+ {
+ fbb_.AddElement<int32_t>(TransposeConvOptions::VT_STRIDE_W, stride_w, 0);
+ }
+ void add_stride_h(int32_t stride_h)
+ {
+ fbb_.AddElement<int32_t>(TransposeConvOptions::VT_STRIDE_H, stride_h, 0);
+ }
+ explicit TransposeConvOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ TransposeConvOptionsBuilder &operator=(const TransposeConvOptionsBuilder &);
+ flatbuffers::Offset<TransposeConvOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TransposeConvOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TransposeConvOptions>
+CreateTransposeConvOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME,
+ int32_t stride_w = 0, int32_t stride_h = 0)
+{
+ TransposeConvOptionsBuilder builder_(_fbb);
+ builder_.add_stride_h(stride_h);
+ builder_.add_stride_w(stride_w);
+ builder_.add_padding(padding);
+ return builder_.Finish();
+}
+
+struct ExpandDimsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ExpandDimsOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ExpandDimsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ExpandDimsOptionsBuilder &operator=(const ExpandDimsOptionsBuilder &);
+ flatbuffers::Offset<ExpandDimsOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ExpandDimsOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ExpandDimsOptions>
+CreateExpandDimsOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ExpandDimsOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SparseToDenseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_VALIDATE_INDICES = 4
+ };
+ bool validate_indices() const { return GetField<uint8_t>(VT_VALIDATE_INDICES, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_VALIDATE_INDICES) &&
+ verifier.EndTable();
+ }
+};
+
+struct SparseToDenseOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_validate_indices(bool validate_indices)
+ {
+ fbb_.AddElement<uint8_t>(SparseToDenseOptions::VT_VALIDATE_INDICES,
+ static_cast<uint8_t>(validate_indices), 0);
+ }
+ explicit SparseToDenseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SparseToDenseOptionsBuilder &operator=(const SparseToDenseOptionsBuilder &);
+ flatbuffers::Offset<SparseToDenseOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SparseToDenseOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SparseToDenseOptions>
+CreateSparseToDenseOptions(flatbuffers::FlatBufferBuilder &_fbb, bool validate_indices = false)
+{
+ SparseToDenseOptionsBuilder builder_(_fbb);
+ builder_.add_validate_indices(validate_indices);
+ return builder_.Finish();
+}
+
+struct EqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct EqualOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit EqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ EqualOptionsBuilder &operator=(const EqualOptionsBuilder &);
+ flatbuffers::Offset<EqualOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<EqualOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<EqualOptions> CreateEqualOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ EqualOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct NotEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct NotEqualOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit NotEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ NotEqualOptionsBuilder &operator=(const NotEqualOptionsBuilder &);
+ flatbuffers::Offset<NotEqualOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NotEqualOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NotEqualOptions>
+CreateNotEqualOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ NotEqualOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ShapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_OUT_TYPE = 4
+ };
+ TensorType out_type() const { return static_cast<TensorType>(GetField<int8_t>(VT_OUT_TYPE, 0)); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_OUT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct ShapeOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_out_type(TensorType out_type)
+ {
+ fbb_.AddElement<int8_t>(ShapeOptions::VT_OUT_TYPE, static_cast<int8_t>(out_type), 0);
+ }
+ explicit ShapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ShapeOptionsBuilder &operator=(const ShapeOptionsBuilder &);
+ flatbuffers::Offset<ShapeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ShapeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ShapeOptions>
+CreateShapeOptions(flatbuffers::FlatBufferBuilder &_fbb, TensorType out_type = TensorType_FLOAT32)
+{
+ ShapeOptionsBuilder builder_(_fbb);
+ builder_.add_out_type(out_type);
+ return builder_.Finish();
+}
+
+struct RankOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct RankOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit RankOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ RankOptionsBuilder &operator=(const RankOptionsBuilder &);
+ flatbuffers::Offset<RankOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<RankOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<RankOptions> CreateRankOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ RankOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct PowOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct PowOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit PowOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ PowOptionsBuilder &operator=(const PowOptionsBuilder &);
+ flatbuffers::Offset<PowOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PowOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PowOptions> CreatePowOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ PowOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct FakeQuantOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_MIN = 4,
+ VT_MAX = 6,
+ VT_NUM_BITS = 8,
+ VT_NARROW_RANGE = 10
+ };
+ float min() const { return GetField<float>(VT_MIN, 0.0f); }
+ float max() const { return GetField<float>(VT_MAX, 0.0f); }
+ int32_t num_bits() const { return GetField<int32_t>(VT_NUM_BITS, 0); }
+ bool narrow_range() const { return GetField<uint8_t>(VT_NARROW_RANGE, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<float>(verifier, VT_MIN) &&
+ VerifyField<float>(verifier, VT_MAX) && VerifyField<int32_t>(verifier, VT_NUM_BITS) &&
+ VerifyField<uint8_t>(verifier, VT_NARROW_RANGE) && verifier.EndTable();
+ }
+};
+
+struct FakeQuantOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_min(float min) { fbb_.AddElement<float>(FakeQuantOptions::VT_MIN, min, 0.0f); }
+ void add_max(float max) { fbb_.AddElement<float>(FakeQuantOptions::VT_MAX, max, 0.0f); }
+ void add_num_bits(int32_t num_bits)
+ {
+ fbb_.AddElement<int32_t>(FakeQuantOptions::VT_NUM_BITS, num_bits, 0);
+ }
+ void add_narrow_range(bool narrow_range)
+ {
+ fbb_.AddElement<uint8_t>(FakeQuantOptions::VT_NARROW_RANGE, static_cast<uint8_t>(narrow_range),
+ 0);
+ }
+ explicit FakeQuantOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FakeQuantOptionsBuilder &operator=(const FakeQuantOptionsBuilder &);
+ flatbuffers::Offset<FakeQuantOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FakeQuantOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FakeQuantOptions>
+CreateFakeQuantOptions(flatbuffers::FlatBufferBuilder &_fbb, float min = 0.0f, float max = 0.0f,
+ int32_t num_bits = 0, bool narrow_range = false)
+{
+ FakeQuantOptionsBuilder builder_(_fbb);
+ builder_.add_num_bits(num_bits);
+ builder_.add_max(max);
+ builder_.add_min(min);
+ builder_.add_narrow_range(narrow_range);
+ return builder_.Finish();
+}
+
+struct PackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_VALUES_COUNT = 4,
+ VT_AXIS = 6
+ };
+ int32_t values_count() const { return GetField<int32_t>(VT_VALUES_COUNT, 0); }
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_VALUES_COUNT) &&
+ VerifyField<int32_t>(verifier, VT_AXIS) && verifier.EndTable();
+ }
+};
+
+struct PackOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_values_count(int32_t values_count)
+ {
+ fbb_.AddElement<int32_t>(PackOptions::VT_VALUES_COUNT, values_count, 0);
+ }
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(PackOptions::VT_AXIS, axis, 0); }
+ explicit PackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ PackOptionsBuilder &operator=(const PackOptionsBuilder &);
+ flatbuffers::Offset<PackOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<PackOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<PackOptions>
+CreatePackOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t values_count = 0, int32_t axis = 0)
+{
+ PackOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ builder_.add_values_count(values_count);
+ return builder_.Finish();
+}
+
+struct LogicalOrOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LogicalOrOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LogicalOrOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LogicalOrOptionsBuilder &operator=(const LogicalOrOptionsBuilder &);
+ flatbuffers::Offset<LogicalOrOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LogicalOrOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LogicalOrOptions>
+CreateLogicalOrOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LogicalOrOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct OneHotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_AXIS = 4
+ };
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_AXIS) &&
+ verifier.EndTable();
+ }
+};
+
+struct OneHotOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(OneHotOptions::VT_AXIS, axis, 0); }
+ explicit OneHotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ OneHotOptionsBuilder &operator=(const OneHotOptionsBuilder &);
+ flatbuffers::Offset<OneHotOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<OneHotOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<OneHotOptions> CreateOneHotOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t axis = 0)
+{
+ OneHotOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ return builder_.Finish();
+}
+
+struct AbsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct AbsOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit AbsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ AbsOptionsBuilder &operator=(const AbsOptionsBuilder &);
+ flatbuffers::Offset<AbsOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<AbsOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<AbsOptions> CreateAbsOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ AbsOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct HardSwishOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct HardSwishOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit HardSwishOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ HardSwishOptionsBuilder &operator=(const HardSwishOptionsBuilder &);
+ flatbuffers::Offset<HardSwishOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<HardSwishOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<HardSwishOptions>
+CreateHardSwishOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ HardSwishOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LogicalAndOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LogicalAndOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LogicalAndOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LogicalAndOptionsBuilder &operator=(const LogicalAndOptionsBuilder &);
+ flatbuffers::Offset<LogicalAndOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LogicalAndOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LogicalAndOptions>
+CreateLogicalAndOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LogicalAndOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LogicalNotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct LogicalNotOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit LogicalNotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LogicalNotOptionsBuilder &operator=(const LogicalNotOptionsBuilder &);
+ flatbuffers::Offset<LogicalNotOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LogicalNotOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LogicalNotOptions>
+CreateLogicalNotOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ LogicalNotOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct UnpackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_NUM = 4,
+ VT_AXIS = 6
+ };
+ int32_t num() const { return GetField<int32_t>(VT_NUM, 0); }
+ int32_t axis() const { return GetField<int32_t>(VT_AXIS, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_NUM) &&
+ VerifyField<int32_t>(verifier, VT_AXIS) && verifier.EndTable();
+ }
+};
+
+struct UnpackOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_num(int32_t num) { fbb_.AddElement<int32_t>(UnpackOptions::VT_NUM, num, 0); }
+ void add_axis(int32_t axis) { fbb_.AddElement<int32_t>(UnpackOptions::VT_AXIS, axis, 0); }
+ explicit UnpackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ UnpackOptionsBuilder &operator=(const UnpackOptionsBuilder &);
+ flatbuffers::Offset<UnpackOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<UnpackOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<UnpackOptions> CreateUnpackOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t num = 0, int32_t axis = 0)
+{
+ UnpackOptionsBuilder builder_(_fbb);
+ builder_.add_axis(axis);
+ builder_.add_num(num);
+ return builder_.Finish();
+}
+
+struct FloorDivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct FloorDivOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit FloorDivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FloorDivOptionsBuilder &operator=(const FloorDivOptionsBuilder &);
+ flatbuffers::Offset<FloorDivOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FloorDivOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FloorDivOptions>
+CreateFloorDivOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ FloorDivOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SquareOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SquareOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SquareOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SquareOptionsBuilder &operator=(const SquareOptionsBuilder &);
+ flatbuffers::Offset<SquareOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SquareOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SquareOptions> CreateSquareOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SquareOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ZerosLikeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ZerosLikeOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ZerosLikeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ZerosLikeOptionsBuilder &operator=(const ZerosLikeOptionsBuilder &);
+ flatbuffers::Offset<ZerosLikeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ZerosLikeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ZerosLikeOptions>
+CreateZerosLikeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ZerosLikeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct FillOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct FillOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit FillOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FillOptionsBuilder &operator=(const FillOptionsBuilder &);
+ flatbuffers::Offset<FillOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FillOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FillOptions> CreateFillOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ FillOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct FloorModOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct FloorModOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit FloorModOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ FloorModOptionsBuilder &operator=(const FloorModOptionsBuilder &);
+ flatbuffers::Offset<FloorModOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<FloorModOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<FloorModOptions>
+CreateFloorModOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ FloorModOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct RangeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct RangeOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit RangeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ RangeOptionsBuilder &operator=(const RangeOptionsBuilder &);
+ flatbuffers::Offset<RangeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<RangeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<RangeOptions> CreateRangeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ RangeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct LeakyReluOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_ALPHA = 4
+ };
+ float alpha() const { return GetField<float>(VT_ALPHA, 0.0f); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<float>(verifier, VT_ALPHA) &&
+ verifier.EndTable();
+ }
+};
+
+struct LeakyReluOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_alpha(float alpha) { fbb_.AddElement<float>(LeakyReluOptions::VT_ALPHA, alpha, 0.0f); }
+ explicit LeakyReluOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ LeakyReluOptionsBuilder &operator=(const LeakyReluOptionsBuilder &);
+ flatbuffers::Offset<LeakyReluOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<LeakyReluOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LeakyReluOptions>
+CreateLeakyReluOptions(flatbuffers::FlatBufferBuilder &_fbb, float alpha = 0.0f)
+{
+ LeakyReluOptionsBuilder builder_(_fbb);
+ builder_.add_alpha(alpha);
+ return builder_.Finish();
+}
+
+struct SquaredDifferenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SquaredDifferenceOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SquaredDifferenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SquaredDifferenceOptionsBuilder &operator=(const SquaredDifferenceOptionsBuilder &);
+ flatbuffers::Offset<SquaredDifferenceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SquaredDifferenceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SquaredDifferenceOptions>
+CreateSquaredDifferenceOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SquaredDifferenceOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct MirrorPadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_MODE = 4
+ };
+ MirrorPadMode mode() const { return static_cast<MirrorPadMode>(GetField<int8_t>(VT_MODE, 0)); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_MODE) &&
+ verifier.EndTable();
+ }
+};
+
+struct MirrorPadOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_mode(MirrorPadMode mode)
+ {
+ fbb_.AddElement<int8_t>(MirrorPadOptions::VT_MODE, static_cast<int8_t>(mode), 0);
+ }
+ explicit MirrorPadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MirrorPadOptionsBuilder &operator=(const MirrorPadOptionsBuilder &);
+ flatbuffers::Offset<MirrorPadOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MirrorPadOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MirrorPadOptions>
+CreateMirrorPadOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ MirrorPadMode mode = MirrorPadMode_REFLECT)
+{
+ MirrorPadOptionsBuilder builder_(_fbb);
+ builder_.add_mode(mode);
+ return builder_.Finish();
+}
+
+struct UniqueOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_IDX_OUT_TYPE = 4
+ };
+ TensorType idx_out_type() const
+ {
+ return static_cast<TensorType>(GetField<int8_t>(VT_IDX_OUT_TYPE, 2));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_IDX_OUT_TYPE) &&
+ verifier.EndTable();
+ }
+};
+
+struct UniqueOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_idx_out_type(TensorType idx_out_type)
+ {
+ fbb_.AddElement<int8_t>(UniqueOptions::VT_IDX_OUT_TYPE, static_cast<int8_t>(idx_out_type), 2);
+ }
+ explicit UniqueOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ UniqueOptionsBuilder &operator=(const UniqueOptionsBuilder &);
+ flatbuffers::Offset<UniqueOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<UniqueOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<UniqueOptions>
+CreateUniqueOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ TensorType idx_out_type = TensorType_INT32)
+{
+ UniqueOptionsBuilder builder_(_fbb);
+ builder_.add_idx_out_type(idx_out_type);
+ return builder_.Finish();
+}
+
+struct ReverseV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ReverseV2OptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ReverseV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ReverseV2OptionsBuilder &operator=(const ReverseV2OptionsBuilder &);
+ flatbuffers::Offset<ReverseV2Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ReverseV2Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ReverseV2Options>
+CreateReverseV2Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ReverseV2OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct AddNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct AddNOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit AddNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ AddNOptionsBuilder &operator=(const AddNOptionsBuilder &);
+ flatbuffers::Offset<AddNOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<AddNOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<AddNOptions> CreateAddNOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ AddNOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct GatherNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct GatherNdOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit GatherNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ GatherNdOptionsBuilder &operator=(const GatherNdOptionsBuilder &);
+ flatbuffers::Offset<GatherNdOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<GatherNdOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<GatherNdOptions>
+CreateGatherNdOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ GatherNdOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct WhereOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct WhereOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit WhereOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ WhereOptionsBuilder &operator=(const WhereOptionsBuilder &);
+ flatbuffers::Offset<WhereOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<WhereOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<WhereOptions> CreateWhereOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ WhereOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ReverseSequenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_SEQ_DIM = 4,
+ VT_BATCH_DIM = 6
+ };
+ int32_t seq_dim() const { return GetField<int32_t>(VT_SEQ_DIM, 0); }
+ int32_t batch_dim() const { return GetField<int32_t>(VT_BATCH_DIM, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_SEQ_DIM) &&
+ VerifyField<int32_t>(verifier, VT_BATCH_DIM) && verifier.EndTable();
+ }
+};
+
+struct ReverseSequenceOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_seq_dim(int32_t seq_dim)
+ {
+ fbb_.AddElement<int32_t>(ReverseSequenceOptions::VT_SEQ_DIM, seq_dim, 0);
+ }
+ void add_batch_dim(int32_t batch_dim)
+ {
+ fbb_.AddElement<int32_t>(ReverseSequenceOptions::VT_BATCH_DIM, batch_dim, 0);
+ }
+ explicit ReverseSequenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ReverseSequenceOptionsBuilder &operator=(const ReverseSequenceOptionsBuilder &);
+ flatbuffers::Offset<ReverseSequenceOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ReverseSequenceOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ReverseSequenceOptions>
+CreateReverseSequenceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t seq_dim = 0,
+ int32_t batch_dim = 0)
+{
+ ReverseSequenceOptionsBuilder builder_(_fbb);
+ builder_.add_batch_dim(batch_dim);
+ builder_.add_seq_dim(seq_dim);
+ return builder_.Finish();
+}
+
+struct MatrixDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct MatrixDiagOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit MatrixDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MatrixDiagOptionsBuilder &operator=(const MatrixDiagOptionsBuilder &);
+ flatbuffers::Offset<MatrixDiagOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MatrixDiagOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MatrixDiagOptions>
+CreateMatrixDiagOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ MatrixDiagOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct QuantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct QuantizeOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit QuantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ QuantizeOptionsBuilder &operator=(const QuantizeOptionsBuilder &);
+ flatbuffers::Offset<QuantizeOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<QuantizeOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<QuantizeOptions>
+CreateQuantizeOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ QuantizeOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct MatrixSetDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct MatrixSetDiagOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit MatrixSetDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MatrixSetDiagOptionsBuilder &operator=(const MatrixSetDiagOptionsBuilder &);
+ flatbuffers::Offset<MatrixSetDiagOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MatrixSetDiagOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MatrixSetDiagOptions>
+CreateMatrixSetDiagOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ MatrixSetDiagOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct IfOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_THEN_SUBGRAPH_INDEX = 4,
+ VT_ELSE_SUBGRAPH_INDEX = 6
+ };
+ int32_t then_subgraph_index() const { return GetField<int32_t>(VT_THEN_SUBGRAPH_INDEX, 0); }
+ int32_t else_subgraph_index() const { return GetField<int32_t>(VT_ELSE_SUBGRAPH_INDEX, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_THEN_SUBGRAPH_INDEX) &&
+ VerifyField<int32_t>(verifier, VT_ELSE_SUBGRAPH_INDEX) && verifier.EndTable();
+ }
+};
+
+struct IfOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_then_subgraph_index(int32_t then_subgraph_index)
+ {
+ fbb_.AddElement<int32_t>(IfOptions::VT_THEN_SUBGRAPH_INDEX, then_subgraph_index, 0);
+ }
+ void add_else_subgraph_index(int32_t else_subgraph_index)
+ {
+ fbb_.AddElement<int32_t>(IfOptions::VT_ELSE_SUBGRAPH_INDEX, else_subgraph_index, 0);
+ }
+ explicit IfOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ IfOptionsBuilder &operator=(const IfOptionsBuilder &);
+ flatbuffers::Offset<IfOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<IfOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<IfOptions> CreateIfOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t then_subgraph_index = 0,
+ int32_t else_subgraph_index = 0)
+{
+ IfOptionsBuilder builder_(_fbb);
+ builder_.add_else_subgraph_index(else_subgraph_index);
+ builder_.add_then_subgraph_index(then_subgraph_index);
+ return builder_.Finish();
+}
+
+struct WhileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_COND_SUBGRAPH_INDEX = 4,
+ VT_BODY_SUBGRAPH_INDEX = 6
+ };
+ int32_t cond_subgraph_index() const { return GetField<int32_t>(VT_COND_SUBGRAPH_INDEX, 0); }
+ int32_t body_subgraph_index() const { return GetField<int32_t>(VT_BODY_SUBGRAPH_INDEX, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_COND_SUBGRAPH_INDEX) &&
+ VerifyField<int32_t>(verifier, VT_BODY_SUBGRAPH_INDEX) && verifier.EndTable();
+ }
+};
+
+struct WhileOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_cond_subgraph_index(int32_t cond_subgraph_index)
+ {
+ fbb_.AddElement<int32_t>(WhileOptions::VT_COND_SUBGRAPH_INDEX, cond_subgraph_index, 0);
+ }
+ void add_body_subgraph_index(int32_t body_subgraph_index)
+ {
+ fbb_.AddElement<int32_t>(WhileOptions::VT_BODY_SUBGRAPH_INDEX, body_subgraph_index, 0);
+ }
+ explicit WhileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ WhileOptionsBuilder &operator=(const WhileOptionsBuilder &);
+ flatbuffers::Offset<WhileOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<WhileOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<WhileOptions> CreateWhileOptions(flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t cond_subgraph_index = 0,
+ int32_t body_subgraph_index = 0)
+{
+ WhileOptionsBuilder builder_(_fbb);
+ builder_.add_body_subgraph_index(body_subgraph_index);
+ builder_.add_cond_subgraph_index(cond_subgraph_index);
+ return builder_.Finish();
+}
+
+struct NonMaxSuppressionV4Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct NonMaxSuppressionV4OptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit NonMaxSuppressionV4OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ NonMaxSuppressionV4OptionsBuilder &operator=(const NonMaxSuppressionV4OptionsBuilder &);
+ flatbuffers::Offset<NonMaxSuppressionV4Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NonMaxSuppressionV4Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NonMaxSuppressionV4Options>
+CreateNonMaxSuppressionV4Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ NonMaxSuppressionV4OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct NonMaxSuppressionV5Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct NonMaxSuppressionV5OptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit NonMaxSuppressionV5OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ NonMaxSuppressionV5OptionsBuilder &operator=(const NonMaxSuppressionV5OptionsBuilder &);
+ flatbuffers::Offset<NonMaxSuppressionV5Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<NonMaxSuppressionV5Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<NonMaxSuppressionV5Options>
+CreateNonMaxSuppressionV5Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ NonMaxSuppressionV5OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct ScatterNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct ScatterNdOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit ScatterNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ScatterNdOptionsBuilder &operator=(const ScatterNdOptionsBuilder &);
+ flatbuffers::Offset<ScatterNdOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ScatterNdOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ScatterNdOptions>
+CreateScatterNdOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ ScatterNdOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SelectV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SelectV2OptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SelectV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SelectV2OptionsBuilder &operator=(const SelectV2OptionsBuilder &);
+ flatbuffers::Offset<SelectV2Options> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SelectV2Options>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SelectV2Options>
+CreateSelectV2Options(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SelectV2OptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct DensifyOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct DensifyOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit DensifyOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ DensifyOptionsBuilder &operator=(const DensifyOptionsBuilder &);
+ flatbuffers::Offset<DensifyOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<DensifyOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<DensifyOptions>
+CreateDensifyOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ DensifyOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct SegmentSumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && verifier.EndTable();
+ }
+};
+
+struct SegmentSumOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit SegmentSumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SegmentSumOptionsBuilder &operator=(const SegmentSumOptionsBuilder &);
+ flatbuffers::Offset<SegmentSumOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SegmentSumOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SegmentSumOptions>
+CreateSegmentSumOptions(flatbuffers::FlatBufferBuilder &_fbb)
+{
+ SegmentSumOptionsBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+struct BatchMatMulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_ADJOINT_LHS = 4,
+ VT_ADJOINT_RHS = 6
+ };
+ bool adjoint_lhs() const { return GetField<uint8_t>(VT_ADJOINT_LHS, 0) != 0; }
+ bool adjoint_rhs() const { return GetField<uint8_t>(VT_ADJOINT_RHS, 0) != 0; }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint8_t>(verifier, VT_ADJOINT_LHS) &&
+ VerifyField<uint8_t>(verifier, VT_ADJOINT_RHS) && verifier.EndTable();
+ }
+};
+
+struct BatchMatMulOptionsBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_adjoint_lhs(bool adjoint_lhs)
+ {
+ fbb_.AddElement<uint8_t>(BatchMatMulOptions::VT_ADJOINT_LHS, static_cast<uint8_t>(adjoint_lhs),
+ 0);
+ }
+ void add_adjoint_rhs(bool adjoint_rhs)
+ {
+ fbb_.AddElement<uint8_t>(BatchMatMulOptions::VT_ADJOINT_RHS, static_cast<uint8_t>(adjoint_rhs),
+ 0);
+ }
+ explicit BatchMatMulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BatchMatMulOptionsBuilder &operator=(const BatchMatMulOptionsBuilder &);
+ flatbuffers::Offset<BatchMatMulOptions> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<BatchMatMulOptions>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<BatchMatMulOptions>
+CreateBatchMatMulOptions(flatbuffers::FlatBufferBuilder &_fbb, bool adjoint_lhs = false,
+ bool adjoint_rhs = false)
+{
+ BatchMatMulOptionsBuilder builder_(_fbb);
+ builder_.add_adjoint_rhs(adjoint_rhs);
+ builder_.add_adjoint_lhs(adjoint_lhs);
+ return builder_.Finish();
+}
+
+struct OperatorCode FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_BUILTIN_CODE = 4,
+ VT_CUSTOM_CODE = 6,
+ VT_VERSION = 8
+ };
+ BuiltinOperator builtin_code() const
+ {
+ return static_cast<BuiltinOperator>(GetField<int8_t>(VT_BUILTIN_CODE, 0));
+ }
+ const flatbuffers::String *custom_code() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_CUSTOM_CODE);
+ }
+ int32_t version() const { return GetField<int32_t>(VT_VERSION, 1); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<int8_t>(verifier, VT_BUILTIN_CODE) &&
+ VerifyOffset(verifier, VT_CUSTOM_CODE) && verifier.VerifyString(custom_code()) &&
+ VerifyField<int32_t>(verifier, VT_VERSION) && verifier.EndTable();
+ }
+};
+
+struct OperatorCodeBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_builtin_code(BuiltinOperator builtin_code)
+ {
+ fbb_.AddElement<int8_t>(OperatorCode::VT_BUILTIN_CODE, static_cast<int8_t>(builtin_code), 0);
+ }
+ void add_custom_code(flatbuffers::Offset<flatbuffers::String> custom_code)
+ {
+ fbb_.AddOffset(OperatorCode::VT_CUSTOM_CODE, custom_code);
+ }
+ void add_version(int32_t version)
+ {
+ fbb_.AddElement<int32_t>(OperatorCode::VT_VERSION, version, 1);
+ }
+ explicit OperatorCodeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ OperatorCodeBuilder &operator=(const OperatorCodeBuilder &);
+ flatbuffers::Offset<OperatorCode> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<OperatorCode>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<OperatorCode>
+CreateOperatorCode(flatbuffers::FlatBufferBuilder &_fbb,
+ BuiltinOperator builtin_code = BuiltinOperator_ADD,
+ flatbuffers::Offset<flatbuffers::String> custom_code = 0, int32_t version = 1)
+{
+ OperatorCodeBuilder builder_(_fbb);
+ builder_.add_version(version);
+ builder_.add_custom_code(custom_code);
+ builder_.add_builtin_code(builtin_code);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<OperatorCode>
+CreateOperatorCodeDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ BuiltinOperator builtin_code = BuiltinOperator_ADD,
+ const char *custom_code = nullptr, int32_t version = 1)
+{
+ return onert_tflite::CreateOperatorCode(
+ _fbb, builtin_code, custom_code ? _fbb.CreateString(custom_code) : 0, version);
+}
+
+struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_OPCODE_INDEX = 4,
+ VT_INPUTS = 6,
+ VT_OUTPUTS = 8,
+ VT_BUILTIN_OPTIONS_TYPE = 10,
+ VT_BUILTIN_OPTIONS = 12,
+ VT_CUSTOM_OPTIONS = 14,
+ VT_CUSTOM_OPTIONS_FORMAT = 16,
+ VT_MUTATING_VARIABLE_INPUTS = 18,
+ VT_INTERMEDIATES = 20
+ };
+ uint32_t opcode_index() const { return GetField<uint32_t>(VT_OPCODE_INDEX, 0); }
+ const flatbuffers::Vector<int32_t> *inputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_INPUTS);
+ }
+ const flatbuffers::Vector<int32_t> *outputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_OUTPUTS);
+ }
+ BuiltinOptions builtin_options_type() const
+ {
+ return static_cast<BuiltinOptions>(GetField<uint8_t>(VT_BUILTIN_OPTIONS_TYPE, 0));
+ }
+ const void *builtin_options() const { return GetPointer<const void *>(VT_BUILTIN_OPTIONS); }
+ template <typename T> const T *builtin_options_as() const;
+ const Conv2DOptions *builtin_options_as_Conv2DOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_Conv2DOptions
+ ? static_cast<const Conv2DOptions *>(builtin_options())
+ : nullptr;
+ }
+ const DepthwiseConv2DOptions *builtin_options_as_DepthwiseConv2DOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_DepthwiseConv2DOptions
+ ? static_cast<const DepthwiseConv2DOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ConcatEmbeddingsOptions *builtin_options_as_ConcatEmbeddingsOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ConcatEmbeddingsOptions
+ ? static_cast<const ConcatEmbeddingsOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LSHProjectionOptions *builtin_options_as_LSHProjectionOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LSHProjectionOptions
+ ? static_cast<const LSHProjectionOptions *>(builtin_options())
+ : nullptr;
+ }
+ const Pool2DOptions *builtin_options_as_Pool2DOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_Pool2DOptions
+ ? static_cast<const Pool2DOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SVDFOptions *builtin_options_as_SVDFOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SVDFOptions
+ ? static_cast<const SVDFOptions *>(builtin_options())
+ : nullptr;
+ }
+ const RNNOptions *builtin_options_as_RNNOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_RNNOptions
+ ? static_cast<const RNNOptions *>(builtin_options())
+ : nullptr;
+ }
+ const FullyConnectedOptions *builtin_options_as_FullyConnectedOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_FullyConnectedOptions
+ ? static_cast<const FullyConnectedOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SoftmaxOptions *builtin_options_as_SoftmaxOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SoftmaxOptions
+ ? static_cast<const SoftmaxOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ConcatenationOptions *builtin_options_as_ConcatenationOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ConcatenationOptions
+ ? static_cast<const ConcatenationOptions *>(builtin_options())
+ : nullptr;
+ }
+ const AddOptions *builtin_options_as_AddOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_AddOptions
+ ? static_cast<const AddOptions *>(builtin_options())
+ : nullptr;
+ }
+ const L2NormOptions *builtin_options_as_L2NormOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_L2NormOptions
+ ? static_cast<const L2NormOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LocalResponseNormalizationOptions *
+ builtin_options_as_LocalResponseNormalizationOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LocalResponseNormalizationOptions
+ ? static_cast<const LocalResponseNormalizationOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LSTMOptions *builtin_options_as_LSTMOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LSTMOptions
+ ? static_cast<const LSTMOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ResizeBilinearOptions *builtin_options_as_ResizeBilinearOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ResizeBilinearOptions
+ ? static_cast<const ResizeBilinearOptions *>(builtin_options())
+ : nullptr;
+ }
+ const CallOptions *builtin_options_as_CallOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_CallOptions
+ ? static_cast<const CallOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ReshapeOptions *builtin_options_as_ReshapeOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ReshapeOptions
+ ? static_cast<const ReshapeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SkipGramOptions *builtin_options_as_SkipGramOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SkipGramOptions
+ ? static_cast<const SkipGramOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SpaceToDepthOptions *builtin_options_as_SpaceToDepthOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SpaceToDepthOptions
+ ? static_cast<const SpaceToDepthOptions *>(builtin_options())
+ : nullptr;
+ }
+ const EmbeddingLookupSparseOptions *builtin_options_as_EmbeddingLookupSparseOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_EmbeddingLookupSparseOptions
+ ? static_cast<const EmbeddingLookupSparseOptions *>(builtin_options())
+ : nullptr;
+ }
+ const MulOptions *builtin_options_as_MulOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_MulOptions
+ ? static_cast<const MulOptions *>(builtin_options())
+ : nullptr;
+ }
+ const PadOptions *builtin_options_as_PadOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_PadOptions
+ ? static_cast<const PadOptions *>(builtin_options())
+ : nullptr;
+ }
+ const GatherOptions *builtin_options_as_GatherOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_GatherOptions
+ ? static_cast<const GatherOptions *>(builtin_options())
+ : nullptr;
+ }
+ const BatchToSpaceNDOptions *builtin_options_as_BatchToSpaceNDOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_BatchToSpaceNDOptions
+ ? static_cast<const BatchToSpaceNDOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SpaceToBatchNDOptions *builtin_options_as_SpaceToBatchNDOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SpaceToBatchNDOptions
+ ? static_cast<const SpaceToBatchNDOptions *>(builtin_options())
+ : nullptr;
+ }
+ const TransposeOptions *builtin_options_as_TransposeOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_TransposeOptions
+ ? static_cast<const TransposeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ReducerOptions *builtin_options_as_ReducerOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ReducerOptions
+ ? static_cast<const ReducerOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SubOptions *builtin_options_as_SubOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SubOptions
+ ? static_cast<const SubOptions *>(builtin_options())
+ : nullptr;
+ }
+ const DivOptions *builtin_options_as_DivOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_DivOptions
+ ? static_cast<const DivOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SqueezeOptions *builtin_options_as_SqueezeOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SqueezeOptions
+ ? static_cast<const SqueezeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SequenceRNNOptions *builtin_options_as_SequenceRNNOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SequenceRNNOptions
+ ? static_cast<const SequenceRNNOptions *>(builtin_options())
+ : nullptr;
+ }
+ const StridedSliceOptions *builtin_options_as_StridedSliceOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_StridedSliceOptions
+ ? static_cast<const StridedSliceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ExpOptions *builtin_options_as_ExpOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ExpOptions
+ ? static_cast<const ExpOptions *>(builtin_options())
+ : nullptr;
+ }
+ const TopKV2Options *builtin_options_as_TopKV2Options() const
+ {
+ return builtin_options_type() == BuiltinOptions_TopKV2Options
+ ? static_cast<const TopKV2Options *>(builtin_options())
+ : nullptr;
+ }
+ const SplitOptions *builtin_options_as_SplitOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SplitOptions
+ ? static_cast<const SplitOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LogSoftmaxOptions *builtin_options_as_LogSoftmaxOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LogSoftmaxOptions
+ ? static_cast<const LogSoftmaxOptions *>(builtin_options())
+ : nullptr;
+ }
+ const CastOptions *builtin_options_as_CastOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_CastOptions
+ ? static_cast<const CastOptions *>(builtin_options())
+ : nullptr;
+ }
+ const DequantizeOptions *builtin_options_as_DequantizeOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_DequantizeOptions
+ ? static_cast<const DequantizeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const MaximumMinimumOptions *builtin_options_as_MaximumMinimumOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_MaximumMinimumOptions
+ ? static_cast<const MaximumMinimumOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ArgMaxOptions *builtin_options_as_ArgMaxOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ArgMaxOptions
+ ? static_cast<const ArgMaxOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LessOptions *builtin_options_as_LessOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LessOptions
+ ? static_cast<const LessOptions *>(builtin_options())
+ : nullptr;
+ }
+ const NegOptions *builtin_options_as_NegOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_NegOptions
+ ? static_cast<const NegOptions *>(builtin_options())
+ : nullptr;
+ }
+ const PadV2Options *builtin_options_as_PadV2Options() const
+ {
+ return builtin_options_type() == BuiltinOptions_PadV2Options
+ ? static_cast<const PadV2Options *>(builtin_options())
+ : nullptr;
+ }
+ const GreaterOptions *builtin_options_as_GreaterOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_GreaterOptions
+ ? static_cast<const GreaterOptions *>(builtin_options())
+ : nullptr;
+ }
+ const GreaterEqualOptions *builtin_options_as_GreaterEqualOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_GreaterEqualOptions
+ ? static_cast<const GreaterEqualOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LessEqualOptions *builtin_options_as_LessEqualOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LessEqualOptions
+ ? static_cast<const LessEqualOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SelectOptions *builtin_options_as_SelectOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SelectOptions
+ ? static_cast<const SelectOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SliceOptions *builtin_options_as_SliceOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SliceOptions
+ ? static_cast<const SliceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const TransposeConvOptions *builtin_options_as_TransposeConvOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_TransposeConvOptions
+ ? static_cast<const TransposeConvOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SparseToDenseOptions *builtin_options_as_SparseToDenseOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SparseToDenseOptions
+ ? static_cast<const SparseToDenseOptions *>(builtin_options())
+ : nullptr;
+ }
+ const TileOptions *builtin_options_as_TileOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_TileOptions
+ ? static_cast<const TileOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ExpandDimsOptions *builtin_options_as_ExpandDimsOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ExpandDimsOptions
+ ? static_cast<const ExpandDimsOptions *>(builtin_options())
+ : nullptr;
+ }
+ const EqualOptions *builtin_options_as_EqualOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_EqualOptions
+ ? static_cast<const EqualOptions *>(builtin_options())
+ : nullptr;
+ }
+ const NotEqualOptions *builtin_options_as_NotEqualOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_NotEqualOptions
+ ? static_cast<const NotEqualOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ShapeOptions *builtin_options_as_ShapeOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ShapeOptions
+ ? static_cast<const ShapeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const PowOptions *builtin_options_as_PowOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_PowOptions
+ ? static_cast<const PowOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ArgMinOptions *builtin_options_as_ArgMinOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ArgMinOptions
+ ? static_cast<const ArgMinOptions *>(builtin_options())
+ : nullptr;
+ }
+ const FakeQuantOptions *builtin_options_as_FakeQuantOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_FakeQuantOptions
+ ? static_cast<const FakeQuantOptions *>(builtin_options())
+ : nullptr;
+ }
+ const PackOptions *builtin_options_as_PackOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_PackOptions
+ ? static_cast<const PackOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LogicalOrOptions *builtin_options_as_LogicalOrOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LogicalOrOptions
+ ? static_cast<const LogicalOrOptions *>(builtin_options())
+ : nullptr;
+ }
+ const OneHotOptions *builtin_options_as_OneHotOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_OneHotOptions
+ ? static_cast<const OneHotOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LogicalAndOptions *builtin_options_as_LogicalAndOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LogicalAndOptions
+ ? static_cast<const LogicalAndOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LogicalNotOptions *builtin_options_as_LogicalNotOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LogicalNotOptions
+ ? static_cast<const LogicalNotOptions *>(builtin_options())
+ : nullptr;
+ }
+ const UnpackOptions *builtin_options_as_UnpackOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_UnpackOptions
+ ? static_cast<const UnpackOptions *>(builtin_options())
+ : nullptr;
+ }
+ const FloorDivOptions *builtin_options_as_FloorDivOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_FloorDivOptions
+ ? static_cast<const FloorDivOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SquareOptions *builtin_options_as_SquareOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SquareOptions
+ ? static_cast<const SquareOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ZerosLikeOptions *builtin_options_as_ZerosLikeOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ZerosLikeOptions
+ ? static_cast<const ZerosLikeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const FillOptions *builtin_options_as_FillOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_FillOptions
+ ? static_cast<const FillOptions *>(builtin_options())
+ : nullptr;
+ }
+ const BidirectionalSequenceLSTMOptions *
+ builtin_options_as_BidirectionalSequenceLSTMOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_BidirectionalSequenceLSTMOptions
+ ? static_cast<const BidirectionalSequenceLSTMOptions *>(builtin_options())
+ : nullptr;
+ }
+ const BidirectionalSequenceRNNOptions *builtin_options_as_BidirectionalSequenceRNNOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_BidirectionalSequenceRNNOptions
+ ? static_cast<const BidirectionalSequenceRNNOptions *>(builtin_options())
+ : nullptr;
+ }
+ const UnidirectionalSequenceLSTMOptions *
+ builtin_options_as_UnidirectionalSequenceLSTMOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_UnidirectionalSequenceLSTMOptions
+ ? static_cast<const UnidirectionalSequenceLSTMOptions *>(builtin_options())
+ : nullptr;
+ }
+ const FloorModOptions *builtin_options_as_FloorModOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_FloorModOptions
+ ? static_cast<const FloorModOptions *>(builtin_options())
+ : nullptr;
+ }
+ const RangeOptions *builtin_options_as_RangeOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_RangeOptions
+ ? static_cast<const RangeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ResizeNearestNeighborOptions *builtin_options_as_ResizeNearestNeighborOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ResizeNearestNeighborOptions
+ ? static_cast<const ResizeNearestNeighborOptions *>(builtin_options())
+ : nullptr;
+ }
+ const LeakyReluOptions *builtin_options_as_LeakyReluOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_LeakyReluOptions
+ ? static_cast<const LeakyReluOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SquaredDifferenceOptions *builtin_options_as_SquaredDifferenceOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SquaredDifferenceOptions
+ ? static_cast<const SquaredDifferenceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const MirrorPadOptions *builtin_options_as_MirrorPadOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_MirrorPadOptions
+ ? static_cast<const MirrorPadOptions *>(builtin_options())
+ : nullptr;
+ }
+ const AbsOptions *builtin_options_as_AbsOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_AbsOptions
+ ? static_cast<const AbsOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SplitVOptions *builtin_options_as_SplitVOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SplitVOptions
+ ? static_cast<const SplitVOptions *>(builtin_options())
+ : nullptr;
+ }
+ const UniqueOptions *builtin_options_as_UniqueOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_UniqueOptions
+ ? static_cast<const UniqueOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ReverseV2Options *builtin_options_as_ReverseV2Options() const
+ {
+ return builtin_options_type() == BuiltinOptions_ReverseV2Options
+ ? static_cast<const ReverseV2Options *>(builtin_options())
+ : nullptr;
+ }
+ const AddNOptions *builtin_options_as_AddNOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_AddNOptions
+ ? static_cast<const AddNOptions *>(builtin_options())
+ : nullptr;
+ }
+ const GatherNdOptions *builtin_options_as_GatherNdOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_GatherNdOptions
+ ? static_cast<const GatherNdOptions *>(builtin_options())
+ : nullptr;
+ }
+ const CosOptions *builtin_options_as_CosOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_CosOptions
+ ? static_cast<const CosOptions *>(builtin_options())
+ : nullptr;
+ }
+ const WhereOptions *builtin_options_as_WhereOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_WhereOptions
+ ? static_cast<const WhereOptions *>(builtin_options())
+ : nullptr;
+ }
+ const RankOptions *builtin_options_as_RankOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_RankOptions
+ ? static_cast<const RankOptions *>(builtin_options())
+ : nullptr;
+ }
+ const ReverseSequenceOptions *builtin_options_as_ReverseSequenceOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ReverseSequenceOptions
+ ? static_cast<const ReverseSequenceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const MatrixDiagOptions *builtin_options_as_MatrixDiagOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_MatrixDiagOptions
+ ? static_cast<const MatrixDiagOptions *>(builtin_options())
+ : nullptr;
+ }
+ const QuantizeOptions *builtin_options_as_QuantizeOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_QuantizeOptions
+ ? static_cast<const QuantizeOptions *>(builtin_options())
+ : nullptr;
+ }
+ const MatrixSetDiagOptions *builtin_options_as_MatrixSetDiagOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_MatrixSetDiagOptions
+ ? static_cast<const MatrixSetDiagOptions *>(builtin_options())
+ : nullptr;
+ }
+ const HardSwishOptions *builtin_options_as_HardSwishOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_HardSwishOptions
+ ? static_cast<const HardSwishOptions *>(builtin_options())
+ : nullptr;
+ }
+ const IfOptions *builtin_options_as_IfOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_IfOptions
+ ? static_cast<const IfOptions *>(builtin_options())
+ : nullptr;
+ }
+ const WhileOptions *builtin_options_as_WhileOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_WhileOptions
+ ? static_cast<const WhileOptions *>(builtin_options())
+ : nullptr;
+ }
+ const DepthToSpaceOptions *builtin_options_as_DepthToSpaceOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_DepthToSpaceOptions
+ ? static_cast<const DepthToSpaceOptions *>(builtin_options())
+ : nullptr;
+ }
+ const NonMaxSuppressionV4Options *builtin_options_as_NonMaxSuppressionV4Options() const
+ {
+ return builtin_options_type() == BuiltinOptions_NonMaxSuppressionV4Options
+ ? static_cast<const NonMaxSuppressionV4Options *>(builtin_options())
+ : nullptr;
+ }
+ const NonMaxSuppressionV5Options *builtin_options_as_NonMaxSuppressionV5Options() const
+ {
+ return builtin_options_type() == BuiltinOptions_NonMaxSuppressionV5Options
+ ? static_cast<const NonMaxSuppressionV5Options *>(builtin_options())
+ : nullptr;
+ }
+ const ScatterNdOptions *builtin_options_as_ScatterNdOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_ScatterNdOptions
+ ? static_cast<const ScatterNdOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SelectV2Options *builtin_options_as_SelectV2Options() const
+ {
+ return builtin_options_type() == BuiltinOptions_SelectV2Options
+ ? static_cast<const SelectV2Options *>(builtin_options())
+ : nullptr;
+ }
+ const DensifyOptions *builtin_options_as_DensifyOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_DensifyOptions
+ ? static_cast<const DensifyOptions *>(builtin_options())
+ : nullptr;
+ }
+ const SegmentSumOptions *builtin_options_as_SegmentSumOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_SegmentSumOptions
+ ? static_cast<const SegmentSumOptions *>(builtin_options())
+ : nullptr;
+ }
+ const BatchMatMulOptions *builtin_options_as_BatchMatMulOptions() const
+ {
+ return builtin_options_type() == BuiltinOptions_BatchMatMulOptions
+ ? static_cast<const BatchMatMulOptions *>(builtin_options())
+ : nullptr;
+ }
+ const flatbuffers::Vector<uint8_t> *custom_options() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_CUSTOM_OPTIONS);
+ }
+ CustomOptionsFormat custom_options_format() const
+ {
+ return static_cast<CustomOptionsFormat>(GetField<int8_t>(VT_CUSTOM_OPTIONS_FORMAT, 0));
+ }
+ const flatbuffers::Vector<uint8_t> *mutating_variable_inputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_MUTATING_VARIABLE_INPUTS);
+ }
+ const flatbuffers::Vector<int32_t> *intermediates() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_INTERMEDIATES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint32_t>(verifier, VT_OPCODE_INDEX) &&
+ VerifyOffset(verifier, VT_INPUTS) && verifier.VerifyVector(inputs()) &&
+ VerifyOffset(verifier, VT_OUTPUTS) && verifier.VerifyVector(outputs()) &&
+ VerifyField<uint8_t>(verifier, VT_BUILTIN_OPTIONS_TYPE) &&
+ VerifyOffset(verifier, VT_BUILTIN_OPTIONS) &&
+ VerifyBuiltinOptions(verifier, builtin_options(), builtin_options_type()) &&
+ VerifyOffset(verifier, VT_CUSTOM_OPTIONS) && verifier.VerifyVector(custom_options()) &&
+ VerifyField<int8_t>(verifier, VT_CUSTOM_OPTIONS_FORMAT) &&
+ VerifyOffset(verifier, VT_MUTATING_VARIABLE_INPUTS) &&
+ verifier.VerifyVector(mutating_variable_inputs()) &&
+ VerifyOffset(verifier, VT_INTERMEDIATES) && verifier.VerifyVector(intermediates()) &&
+ verifier.EndTable();
+ }
+};
+
+template <> inline const Conv2DOptions *Operator::builtin_options_as<Conv2DOptions>() const
+{
+ return builtin_options_as_Conv2DOptions();
+}
+
+template <>
+inline const DepthwiseConv2DOptions *Operator::builtin_options_as<DepthwiseConv2DOptions>() const
+{
+ return builtin_options_as_DepthwiseConv2DOptions();
+}
+
+template <>
+inline const ConcatEmbeddingsOptions *Operator::builtin_options_as<ConcatEmbeddingsOptions>() const
+{
+ return builtin_options_as_ConcatEmbeddingsOptions();
+}
+
+template <>
+inline const LSHProjectionOptions *Operator::builtin_options_as<LSHProjectionOptions>() const
+{
+ return builtin_options_as_LSHProjectionOptions();
+}
+
+template <> inline const Pool2DOptions *Operator::builtin_options_as<Pool2DOptions>() const
+{
+ return builtin_options_as_Pool2DOptions();
+}
+
+template <> inline const SVDFOptions *Operator::builtin_options_as<SVDFOptions>() const
+{
+ return builtin_options_as_SVDFOptions();
+}
+
+template <> inline const RNNOptions *Operator::builtin_options_as<RNNOptions>() const
+{
+ return builtin_options_as_RNNOptions();
+}
+
+template <>
+inline const FullyConnectedOptions *Operator::builtin_options_as<FullyConnectedOptions>() const
+{
+ return builtin_options_as_FullyConnectedOptions();
+}
+
+template <> inline const SoftmaxOptions *Operator::builtin_options_as<SoftmaxOptions>() const
+{
+ return builtin_options_as_SoftmaxOptions();
+}
+
+template <>
+inline const ConcatenationOptions *Operator::builtin_options_as<ConcatenationOptions>() const
+{
+ return builtin_options_as_ConcatenationOptions();
+}
+
+template <> inline const AddOptions *Operator::builtin_options_as<AddOptions>() const
+{
+ return builtin_options_as_AddOptions();
+}
+
+template <> inline const L2NormOptions *Operator::builtin_options_as<L2NormOptions>() const
+{
+ return builtin_options_as_L2NormOptions();
+}
+
+template <>
+inline const LocalResponseNormalizationOptions *
+Operator::builtin_options_as<LocalResponseNormalizationOptions>() const
+{
+ return builtin_options_as_LocalResponseNormalizationOptions();
+}
+
+template <> inline const LSTMOptions *Operator::builtin_options_as<LSTMOptions>() const
+{
+ return builtin_options_as_LSTMOptions();
+}
+
+template <>
+inline const ResizeBilinearOptions *Operator::builtin_options_as<ResizeBilinearOptions>() const
+{
+ return builtin_options_as_ResizeBilinearOptions();
+}
+
+template <> inline const CallOptions *Operator::builtin_options_as<CallOptions>() const
+{
+ return builtin_options_as_CallOptions();
+}
+
+template <> inline const ReshapeOptions *Operator::builtin_options_as<ReshapeOptions>() const
+{
+ return builtin_options_as_ReshapeOptions();
+}
+
+template <> inline const SkipGramOptions *Operator::builtin_options_as<SkipGramOptions>() const
+{
+ return builtin_options_as_SkipGramOptions();
+}
+
+template <>
+inline const SpaceToDepthOptions *Operator::builtin_options_as<SpaceToDepthOptions>() const
+{
+ return builtin_options_as_SpaceToDepthOptions();
+}
+
+template <>
+inline const EmbeddingLookupSparseOptions *
+Operator::builtin_options_as<EmbeddingLookupSparseOptions>() const
+{
+ return builtin_options_as_EmbeddingLookupSparseOptions();
+}
+
+template <> inline const MulOptions *Operator::builtin_options_as<MulOptions>() const
+{
+ return builtin_options_as_MulOptions();
+}
+
+template <> inline const PadOptions *Operator::builtin_options_as<PadOptions>() const
+{
+ return builtin_options_as_PadOptions();
+}
+
+template <> inline const GatherOptions *Operator::builtin_options_as<GatherOptions>() const
+{
+ return builtin_options_as_GatherOptions();
+}
+
+template <>
+inline const BatchToSpaceNDOptions *Operator::builtin_options_as<BatchToSpaceNDOptions>() const
+{
+ return builtin_options_as_BatchToSpaceNDOptions();
+}
+
+template <>
+inline const SpaceToBatchNDOptions *Operator::builtin_options_as<SpaceToBatchNDOptions>() const
+{
+ return builtin_options_as_SpaceToBatchNDOptions();
+}
+
+template <> inline const TransposeOptions *Operator::builtin_options_as<TransposeOptions>() const
+{
+ return builtin_options_as_TransposeOptions();
+}
+
+template <> inline const ReducerOptions *Operator::builtin_options_as<ReducerOptions>() const
+{
+ return builtin_options_as_ReducerOptions();
+}
+
+template <> inline const SubOptions *Operator::builtin_options_as<SubOptions>() const
+{
+ return builtin_options_as_SubOptions();
+}
+
+template <> inline const DivOptions *Operator::builtin_options_as<DivOptions>() const
+{
+ return builtin_options_as_DivOptions();
+}
+
+template <> inline const SqueezeOptions *Operator::builtin_options_as<SqueezeOptions>() const
+{
+ return builtin_options_as_SqueezeOptions();
+}
+
+template <>
+inline const SequenceRNNOptions *Operator::builtin_options_as<SequenceRNNOptions>() const
+{
+ return builtin_options_as_SequenceRNNOptions();
+}
+
+template <>
+inline const StridedSliceOptions *Operator::builtin_options_as<StridedSliceOptions>() const
+{
+ return builtin_options_as_StridedSliceOptions();
+}
+
+template <> inline const ExpOptions *Operator::builtin_options_as<ExpOptions>() const
+{
+ return builtin_options_as_ExpOptions();
+}
+
+template <> inline const TopKV2Options *Operator::builtin_options_as<TopKV2Options>() const
+{
+ return builtin_options_as_TopKV2Options();
+}
+
+template <> inline const SplitOptions *Operator::builtin_options_as<SplitOptions>() const
+{
+ return builtin_options_as_SplitOptions();
+}
+
+template <> inline const LogSoftmaxOptions *Operator::builtin_options_as<LogSoftmaxOptions>() const
+{
+ return builtin_options_as_LogSoftmaxOptions();
+}
+
+template <> inline const CastOptions *Operator::builtin_options_as<CastOptions>() const
+{
+ return builtin_options_as_CastOptions();
+}
+
+template <> inline const DequantizeOptions *Operator::builtin_options_as<DequantizeOptions>() const
+{
+ return builtin_options_as_DequantizeOptions();
+}
+
+template <>
+inline const MaximumMinimumOptions *Operator::builtin_options_as<MaximumMinimumOptions>() const
+{
+ return builtin_options_as_MaximumMinimumOptions();
+}
+
+template <> inline const ArgMaxOptions *Operator::builtin_options_as<ArgMaxOptions>() const
+{
+ return builtin_options_as_ArgMaxOptions();
+}
+
+template <> inline const LessOptions *Operator::builtin_options_as<LessOptions>() const
+{
+ return builtin_options_as_LessOptions();
+}
+
+template <> inline const NegOptions *Operator::builtin_options_as<NegOptions>() const
+{
+ return builtin_options_as_NegOptions();
+}
+
+template <> inline const PadV2Options *Operator::builtin_options_as<PadV2Options>() const
+{
+ return builtin_options_as_PadV2Options();
+}
+
+template <> inline const GreaterOptions *Operator::builtin_options_as<GreaterOptions>() const
+{
+ return builtin_options_as_GreaterOptions();
+}
+
+template <>
+inline const GreaterEqualOptions *Operator::builtin_options_as<GreaterEqualOptions>() const
+{
+ return builtin_options_as_GreaterEqualOptions();
+}
+
+template <> inline const LessEqualOptions *Operator::builtin_options_as<LessEqualOptions>() const
+{
+ return builtin_options_as_LessEqualOptions();
+}
+
+template <> inline const SelectOptions *Operator::builtin_options_as<SelectOptions>() const
+{
+ return builtin_options_as_SelectOptions();
+}
+
+template <> inline const SliceOptions *Operator::builtin_options_as<SliceOptions>() const
+{
+ return builtin_options_as_SliceOptions();
+}
+
+template <>
+inline const TransposeConvOptions *Operator::builtin_options_as<TransposeConvOptions>() const
+{
+ return builtin_options_as_TransposeConvOptions();
+}
+
+template <>
+inline const SparseToDenseOptions *Operator::builtin_options_as<SparseToDenseOptions>() const
+{
+ return builtin_options_as_SparseToDenseOptions();
+}
+
+template <> inline const TileOptions *Operator::builtin_options_as<TileOptions>() const
+{
+ return builtin_options_as_TileOptions();
+}
+
+template <> inline const ExpandDimsOptions *Operator::builtin_options_as<ExpandDimsOptions>() const
+{
+ return builtin_options_as_ExpandDimsOptions();
+}
+
+template <> inline const EqualOptions *Operator::builtin_options_as<EqualOptions>() const
+{
+ return builtin_options_as_EqualOptions();
+}
+
+template <> inline const NotEqualOptions *Operator::builtin_options_as<NotEqualOptions>() const
+{
+ return builtin_options_as_NotEqualOptions();
+}
+
+template <> inline const ShapeOptions *Operator::builtin_options_as<ShapeOptions>() const
+{
+ return builtin_options_as_ShapeOptions();
+}
+
+template <> inline const PowOptions *Operator::builtin_options_as<PowOptions>() const
+{
+ return builtin_options_as_PowOptions();
+}
+
+template <> inline const ArgMinOptions *Operator::builtin_options_as<ArgMinOptions>() const
+{
+ return builtin_options_as_ArgMinOptions();
+}
+
+template <> inline const FakeQuantOptions *Operator::builtin_options_as<FakeQuantOptions>() const
+{
+ return builtin_options_as_FakeQuantOptions();
+}
+
+template <> inline const PackOptions *Operator::builtin_options_as<PackOptions>() const
+{
+ return builtin_options_as_PackOptions();
+}
+
+template <> inline const LogicalOrOptions *Operator::builtin_options_as<LogicalOrOptions>() const
+{
+ return builtin_options_as_LogicalOrOptions();
+}
+
+template <> inline const OneHotOptions *Operator::builtin_options_as<OneHotOptions>() const
+{
+ return builtin_options_as_OneHotOptions();
+}
+
+template <> inline const LogicalAndOptions *Operator::builtin_options_as<LogicalAndOptions>() const
+{
+ return builtin_options_as_LogicalAndOptions();
+}
+
+template <> inline const LogicalNotOptions *Operator::builtin_options_as<LogicalNotOptions>() const
+{
+ return builtin_options_as_LogicalNotOptions();
+}
+
+template <> inline const UnpackOptions *Operator::builtin_options_as<UnpackOptions>() const
+{
+ return builtin_options_as_UnpackOptions();
+}
+
+template <> inline const FloorDivOptions *Operator::builtin_options_as<FloorDivOptions>() const
+{
+ return builtin_options_as_FloorDivOptions();
+}
+
+template <> inline const SquareOptions *Operator::builtin_options_as<SquareOptions>() const
+{
+ return builtin_options_as_SquareOptions();
+}
+
+template <> inline const ZerosLikeOptions *Operator::builtin_options_as<ZerosLikeOptions>() const
+{
+ return builtin_options_as_ZerosLikeOptions();
+}
+
+template <> inline const FillOptions *Operator::builtin_options_as<FillOptions>() const
+{
+ return builtin_options_as_FillOptions();
+}
+
+template <>
+inline const BidirectionalSequenceLSTMOptions *
+Operator::builtin_options_as<BidirectionalSequenceLSTMOptions>() const
+{
+ return builtin_options_as_BidirectionalSequenceLSTMOptions();
+}
+
+template <>
+inline const BidirectionalSequenceRNNOptions *
+Operator::builtin_options_as<BidirectionalSequenceRNNOptions>() const
+{
+ return builtin_options_as_BidirectionalSequenceRNNOptions();
+}
+
+template <>
+inline const UnidirectionalSequenceLSTMOptions *
+Operator::builtin_options_as<UnidirectionalSequenceLSTMOptions>() const
+{
+ return builtin_options_as_UnidirectionalSequenceLSTMOptions();
+}
+
+template <> inline const FloorModOptions *Operator::builtin_options_as<FloorModOptions>() const
+{
+ return builtin_options_as_FloorModOptions();
+}
+
+template <> inline const RangeOptions *Operator::builtin_options_as<RangeOptions>() const
+{
+ return builtin_options_as_RangeOptions();
+}
+
+template <>
+inline const ResizeNearestNeighborOptions *
+Operator::builtin_options_as<ResizeNearestNeighborOptions>() const
+{
+ return builtin_options_as_ResizeNearestNeighborOptions();
+}
+
+template <> inline const LeakyReluOptions *Operator::builtin_options_as<LeakyReluOptions>() const
+{
+ return builtin_options_as_LeakyReluOptions();
+}
+
+template <>
+inline const SquaredDifferenceOptions *
+Operator::builtin_options_as<SquaredDifferenceOptions>() const
+{
+ return builtin_options_as_SquaredDifferenceOptions();
+}
+
+template <> inline const MirrorPadOptions *Operator::builtin_options_as<MirrorPadOptions>() const
+{
+ return builtin_options_as_MirrorPadOptions();
+}
+
+template <> inline const AbsOptions *Operator::builtin_options_as<AbsOptions>() const
+{
+ return builtin_options_as_AbsOptions();
+}
+
+template <> inline const SplitVOptions *Operator::builtin_options_as<SplitVOptions>() const
+{
+ return builtin_options_as_SplitVOptions();
+}
+
+template <> inline const UniqueOptions *Operator::builtin_options_as<UniqueOptions>() const
+{
+ return builtin_options_as_UniqueOptions();
+}
+
+template <> inline const ReverseV2Options *Operator::builtin_options_as<ReverseV2Options>() const
+{
+ return builtin_options_as_ReverseV2Options();
+}
+
+template <> inline const AddNOptions *Operator::builtin_options_as<AddNOptions>() const
+{
+ return builtin_options_as_AddNOptions();
+}
+
+template <> inline const GatherNdOptions *Operator::builtin_options_as<GatherNdOptions>() const
+{
+ return builtin_options_as_GatherNdOptions();
+}
+
+template <> inline const CosOptions *Operator::builtin_options_as<CosOptions>() const
+{
+ return builtin_options_as_CosOptions();
+}
+
+template <> inline const WhereOptions *Operator::builtin_options_as<WhereOptions>() const
+{
+ return builtin_options_as_WhereOptions();
+}
+
+template <> inline const RankOptions *Operator::builtin_options_as<RankOptions>() const
+{
+ return builtin_options_as_RankOptions();
+}
+
+template <>
+inline const ReverseSequenceOptions *Operator::builtin_options_as<ReverseSequenceOptions>() const
+{
+ return builtin_options_as_ReverseSequenceOptions();
+}
+
+template <> inline const MatrixDiagOptions *Operator::builtin_options_as<MatrixDiagOptions>() const
+{
+ return builtin_options_as_MatrixDiagOptions();
+}
+
+template <> inline const QuantizeOptions *Operator::builtin_options_as<QuantizeOptions>() const
+{
+ return builtin_options_as_QuantizeOptions();
+}
+
+template <>
+inline const MatrixSetDiagOptions *Operator::builtin_options_as<MatrixSetDiagOptions>() const
+{
+ return builtin_options_as_MatrixSetDiagOptions();
+}
+
+template <> inline const HardSwishOptions *Operator::builtin_options_as<HardSwishOptions>() const
+{
+ return builtin_options_as_HardSwishOptions();
+}
+
+template <> inline const IfOptions *Operator::builtin_options_as<IfOptions>() const
+{
+ return builtin_options_as_IfOptions();
+}
+
+template <> inline const WhileOptions *Operator::builtin_options_as<WhileOptions>() const
+{
+ return builtin_options_as_WhileOptions();
+}
+
+template <>
+inline const DepthToSpaceOptions *Operator::builtin_options_as<DepthToSpaceOptions>() const
+{
+ return builtin_options_as_DepthToSpaceOptions();
+}
+
+template <>
+inline const NonMaxSuppressionV4Options *
+Operator::builtin_options_as<NonMaxSuppressionV4Options>() const
+{
+ return builtin_options_as_NonMaxSuppressionV4Options();
+}
+
+template <>
+inline const NonMaxSuppressionV5Options *
+Operator::builtin_options_as<NonMaxSuppressionV5Options>() const
+{
+ return builtin_options_as_NonMaxSuppressionV5Options();
+}
+
+template <> inline const ScatterNdOptions *Operator::builtin_options_as<ScatterNdOptions>() const
+{
+ return builtin_options_as_ScatterNdOptions();
+}
+
+template <> inline const SelectV2Options *Operator::builtin_options_as<SelectV2Options>() const
+{
+ return builtin_options_as_SelectV2Options();
+}
+
+template <> inline const DensifyOptions *Operator::builtin_options_as<DensifyOptions>() const
+{
+ return builtin_options_as_DensifyOptions();
+}
+
+template <> inline const SegmentSumOptions *Operator::builtin_options_as<SegmentSumOptions>() const
+{
+ return builtin_options_as_SegmentSumOptions();
+}
+
+template <>
+inline const BatchMatMulOptions *Operator::builtin_options_as<BatchMatMulOptions>() const
+{
+ return builtin_options_as_BatchMatMulOptions();
+}
+
+struct OperatorBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_opcode_index(uint32_t opcode_index)
+ {
+ fbb_.AddElement<uint32_t>(Operator::VT_OPCODE_INDEX, opcode_index, 0);
+ }
+ void add_inputs(flatbuffers::Offset<flatbuffers::Vector<int32_t>> inputs)
+ {
+ fbb_.AddOffset(Operator::VT_INPUTS, inputs);
+ }
+ void add_outputs(flatbuffers::Offset<flatbuffers::Vector<int32_t>> outputs)
+ {
+ fbb_.AddOffset(Operator::VT_OUTPUTS, outputs);
+ }
+ void add_builtin_options_type(BuiltinOptions builtin_options_type)
+ {
+ fbb_.AddElement<uint8_t>(Operator::VT_BUILTIN_OPTIONS_TYPE,
+ static_cast<uint8_t>(builtin_options_type), 0);
+ }
+ void add_builtin_options(flatbuffers::Offset<void> builtin_options)
+ {
+ fbb_.AddOffset(Operator::VT_BUILTIN_OPTIONS, builtin_options);
+ }
+ void add_custom_options(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> custom_options)
+ {
+ fbb_.AddOffset(Operator::VT_CUSTOM_OPTIONS, custom_options);
+ }
+ void add_custom_options_format(CustomOptionsFormat custom_options_format)
+ {
+ fbb_.AddElement<int8_t>(Operator::VT_CUSTOM_OPTIONS_FORMAT,
+ static_cast<int8_t>(custom_options_format), 0);
+ }
+ void add_mutating_variable_inputs(
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> mutating_variable_inputs)
+ {
+ fbb_.AddOffset(Operator::VT_MUTATING_VARIABLE_INPUTS, mutating_variable_inputs);
+ }
+ void add_intermediates(flatbuffers::Offset<flatbuffers::Vector<int32_t>> intermediates)
+ {
+ fbb_.AddOffset(Operator::VT_INTERMEDIATES, intermediates);
+ }
+ explicit OperatorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ OperatorBuilder &operator=(const OperatorBuilder &);
+ flatbuffers::Offset<Operator> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Operator>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Operator>
+CreateOperator(flatbuffers::FlatBufferBuilder &_fbb, uint32_t opcode_index = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> inputs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> outputs = 0,
+ BuiltinOptions builtin_options_type = BuiltinOptions_NONE,
+ flatbuffers::Offset<void> builtin_options = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> custom_options = 0,
+ CustomOptionsFormat custom_options_format = CustomOptionsFormat_FLEXBUFFERS,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> mutating_variable_inputs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> intermediates = 0)
+{
+ OperatorBuilder builder_(_fbb);
+ builder_.add_intermediates(intermediates);
+ builder_.add_mutating_variable_inputs(mutating_variable_inputs);
+ builder_.add_custom_options(custom_options);
+ builder_.add_builtin_options(builtin_options);
+ builder_.add_outputs(outputs);
+ builder_.add_inputs(inputs);
+ builder_.add_opcode_index(opcode_index);
+ builder_.add_custom_options_format(custom_options_format);
+ builder_.add_builtin_options_type(builtin_options_type);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Operator>
+CreateOperatorDirect(flatbuffers::FlatBufferBuilder &_fbb, uint32_t opcode_index = 0,
+ const std::vector<int32_t> *inputs = nullptr,
+ const std::vector<int32_t> *outputs = nullptr,
+ BuiltinOptions builtin_options_type = BuiltinOptions_NONE,
+ flatbuffers::Offset<void> builtin_options = 0,
+ const std::vector<uint8_t> *custom_options = nullptr,
+ CustomOptionsFormat custom_options_format = CustomOptionsFormat_FLEXBUFFERS,
+ const std::vector<uint8_t> *mutating_variable_inputs = nullptr,
+ const std::vector<int32_t> *intermediates = nullptr)
+{
+ return onert_tflite::CreateOperator(
+ _fbb, opcode_index, inputs ? _fbb.CreateVector<int32_t>(*inputs) : 0,
+ outputs ? _fbb.CreateVector<int32_t>(*outputs) : 0, builtin_options_type, builtin_options,
+ custom_options ? _fbb.CreateVector<uint8_t>(*custom_options) : 0, custom_options_format,
+ mutating_variable_inputs ? _fbb.CreateVector<uint8_t>(*mutating_variable_inputs) : 0,
+ intermediates ? _fbb.CreateVector<int32_t>(*intermediates) : 0);
+}
+
+struct SubGraph FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_TENSORS = 4,
+ VT_INPUTS = 6,
+ VT_OUTPUTS = 8,
+ VT_OPERATORS = 10,
+ VT_NAME = 12
+ };
+ const flatbuffers::Vector<flatbuffers::Offset<Tensor>> *tensors() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Tensor>> *>(VT_TENSORS);
+ }
+ const flatbuffers::Vector<int32_t> *inputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_INPUTS);
+ }
+ const flatbuffers::Vector<int32_t> *outputs() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_OUTPUTS);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<Operator>> *operators() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Operator>> *>(VT_OPERATORS);
+ }
+ const flatbuffers::String *name() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TENSORS) &&
+ verifier.VerifyVector(tensors()) && verifier.VerifyVectorOfTables(tensors()) &&
+ VerifyOffset(verifier, VT_INPUTS) && verifier.VerifyVector(inputs()) &&
+ VerifyOffset(verifier, VT_OUTPUTS) && verifier.VerifyVector(outputs()) &&
+ VerifyOffset(verifier, VT_OPERATORS) && verifier.VerifyVector(operators()) &&
+ verifier.VerifyVectorOfTables(operators()) && VerifyOffset(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) && verifier.EndTable();
+ }
+};
+
+struct SubGraphBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_tensors(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Tensor>>> tensors)
+ {
+ fbb_.AddOffset(SubGraph::VT_TENSORS, tensors);
+ }
+ void add_inputs(flatbuffers::Offset<flatbuffers::Vector<int32_t>> inputs)
+ {
+ fbb_.AddOffset(SubGraph::VT_INPUTS, inputs);
+ }
+ void add_outputs(flatbuffers::Offset<flatbuffers::Vector<int32_t>> outputs)
+ {
+ fbb_.AddOffset(SubGraph::VT_OUTPUTS, outputs);
+ }
+ void
+ add_operators(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Operator>>> operators)
+ {
+ fbb_.AddOffset(SubGraph::VT_OPERATORS, operators);
+ }
+ void add_name(flatbuffers::Offset<flatbuffers::String> name)
+ {
+ fbb_.AddOffset(SubGraph::VT_NAME, name);
+ }
+ explicit SubGraphBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ SubGraphBuilder &operator=(const SubGraphBuilder &);
+ flatbuffers::Offset<SubGraph> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SubGraph>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SubGraph> CreateSubGraph(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Tensor>>> tensors = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> inputs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> outputs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Operator>>> operators = 0,
+ flatbuffers::Offset<flatbuffers::String> name = 0)
+{
+ SubGraphBuilder builder_(_fbb);
+ builder_.add_name(name);
+ builder_.add_operators(operators);
+ builder_.add_outputs(outputs);
+ builder_.add_inputs(inputs);
+ builder_.add_tensors(tensors);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<SubGraph>
+CreateSubGraphDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<flatbuffers::Offset<Tensor>> *tensors = nullptr,
+ const std::vector<int32_t> *inputs = nullptr,
+ const std::vector<int32_t> *outputs = nullptr,
+ const std::vector<flatbuffers::Offset<Operator>> *operators = nullptr,
+ const char *name = nullptr)
+{
+ return onert_tflite::CreateSubGraph(
+ _fbb, tensors ? _fbb.CreateVector<flatbuffers::Offset<Tensor>>(*tensors) : 0,
+ inputs ? _fbb.CreateVector<int32_t>(*inputs) : 0,
+ outputs ? _fbb.CreateVector<int32_t>(*outputs) : 0,
+ operators ? _fbb.CreateVector<flatbuffers::Offset<Operator>>(*operators) : 0,
+ name ? _fbb.CreateString(name) : 0);
+}
+
+struct Buffer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_DATA = 4
+ };
+ const flatbuffers::Vector<uint8_t> *data() const
+ {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_DATA);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_DATA) &&
+ verifier.VerifyVector(data()) && verifier.EndTable();
+ }
+};
+
+struct BufferBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_data(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> data)
+ {
+ fbb_.AddOffset(Buffer::VT_DATA, data);
+ }
+ explicit BufferBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ BufferBuilder &operator=(const BufferBuilder &);
+ flatbuffers::Offset<Buffer> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Buffer>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Buffer>
+CreateBuffer(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> data = 0)
+{
+ BufferBuilder builder_(_fbb);
+ builder_.add_data(data);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Buffer> CreateBufferDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<uint8_t> *data = nullptr)
+{
+ return onert_tflite::CreateBuffer(_fbb, data ? _fbb.CreateVector<uint8_t>(*data) : 0);
+}
+
+struct Metadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_NAME = 4,
+ VT_BUFFER = 6
+ };
+ const flatbuffers::String *name() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ uint32_t buffer() const { return GetField<uint32_t>(VT_BUFFER, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) && VerifyField<uint32_t>(verifier, VT_BUFFER) &&
+ verifier.EndTable();
+ }
+};
+
+struct MetadataBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name)
+ {
+ fbb_.AddOffset(Metadata::VT_NAME, name);
+ }
+ void add_buffer(uint32_t buffer) { fbb_.AddElement<uint32_t>(Metadata::VT_BUFFER, buffer, 0); }
+ explicit MetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ MetadataBuilder &operator=(const MetadataBuilder &);
+ flatbuffers::Offset<Metadata> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Metadata>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Metadata>
+CreateMetadata(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0, uint32_t buffer = 0)
+{
+ MetadataBuilder builder_(_fbb);
+ builder_.add_buffer(buffer);
+ builder_.add_name(name);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Metadata> CreateMetadataDirect(flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ uint32_t buffer = 0)
+{
+ return onert_tflite::CreateMetadata(_fbb, name ? _fbb.CreateString(name) : 0, buffer);
+}
+
+struct Model FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
+{
+ enum
+ {
+ VT_VERSION = 4,
+ VT_OPERATOR_CODES = 6,
+ VT_SUBGRAPHS = 8,
+ VT_DESCRIPTION = 10,
+ VT_BUFFERS = 12,
+ VT_METADATA_BUFFER = 14,
+ VT_METADATA = 16
+ };
+ uint32_t version() const { return GetField<uint32_t>(VT_VERSION, 0); }
+ const flatbuffers::Vector<flatbuffers::Offset<OperatorCode>> *operator_codes() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<OperatorCode>> *>(
+ VT_OPERATOR_CODES);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<SubGraph>> *subgraphs() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<SubGraph>> *>(VT_SUBGRAPHS);
+ }
+ const flatbuffers::String *description() const
+ {
+ return GetPointer<const flatbuffers::String *>(VT_DESCRIPTION);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<Buffer>> *buffers() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Buffer>> *>(VT_BUFFERS);
+ }
+ const flatbuffers::Vector<int32_t> *metadata_buffer() const
+ {
+ return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_METADATA_BUFFER);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<Metadata>> *metadata() const
+ {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Metadata>> *>(VT_METADATA);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const
+ {
+ return VerifyTableStart(verifier) && VerifyField<uint32_t>(verifier, VT_VERSION) &&
+ VerifyOffset(verifier, VT_OPERATOR_CODES) && verifier.VerifyVector(operator_codes()) &&
+ verifier.VerifyVectorOfTables(operator_codes()) &&
+ VerifyOffset(verifier, VT_SUBGRAPHS) && verifier.VerifyVector(subgraphs()) &&
+ verifier.VerifyVectorOfTables(subgraphs()) && VerifyOffset(verifier, VT_DESCRIPTION) &&
+ verifier.VerifyString(description()) && VerifyOffset(verifier, VT_BUFFERS) &&
+ verifier.VerifyVector(buffers()) && verifier.VerifyVectorOfTables(buffers()) &&
+ VerifyOffset(verifier, VT_METADATA_BUFFER) && verifier.VerifyVector(metadata_buffer()) &&
+ VerifyOffset(verifier, VT_METADATA) && verifier.VerifyVector(metadata()) &&
+ verifier.VerifyVectorOfTables(metadata()) && verifier.EndTable();
+ }
+};
+
+struct ModelBuilder
+{
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_version(uint32_t version) { fbb_.AddElement<uint32_t>(Model::VT_VERSION, version, 0); }
+ void add_operator_codes(
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<OperatorCode>>> operator_codes)
+ {
+ fbb_.AddOffset(Model::VT_OPERATOR_CODES, operator_codes);
+ }
+ void
+ add_subgraphs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<SubGraph>>> subgraphs)
+ {
+ fbb_.AddOffset(Model::VT_SUBGRAPHS, subgraphs);
+ }
+ void add_description(flatbuffers::Offset<flatbuffers::String> description)
+ {
+ fbb_.AddOffset(Model::VT_DESCRIPTION, description);
+ }
+ void add_buffers(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Buffer>>> buffers)
+ {
+ fbb_.AddOffset(Model::VT_BUFFERS, buffers);
+ }
+ void add_metadata_buffer(flatbuffers::Offset<flatbuffers::Vector<int32_t>> metadata_buffer)
+ {
+ fbb_.AddOffset(Model::VT_METADATA_BUFFER, metadata_buffer);
+ }
+ void
+ add_metadata(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Metadata>>> metadata)
+ {
+ fbb_.AddOffset(Model::VT_METADATA, metadata);
+ }
+ explicit ModelBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb)
+ {
+ start_ = fbb_.StartTable();
+ }
+ ModelBuilder &operator=(const ModelBuilder &);
+ flatbuffers::Offset<Model> Finish()
+ {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Model>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Model> CreateModel(
+ flatbuffers::FlatBufferBuilder &_fbb, uint32_t version = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<OperatorCode>>> operator_codes = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<SubGraph>>> subgraphs = 0,
+ flatbuffers::Offset<flatbuffers::String> description = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Buffer>>> buffers = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> metadata_buffer = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Metadata>>> metadata = 0)
+{
+ ModelBuilder builder_(_fbb);
+ builder_.add_metadata(metadata);
+ builder_.add_metadata_buffer(metadata_buffer);
+ builder_.add_buffers(buffers);
+ builder_.add_description(description);
+ builder_.add_subgraphs(subgraphs);
+ builder_.add_operator_codes(operator_codes);
+ builder_.add_version(version);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Model>
+CreateModelDirect(flatbuffers::FlatBufferBuilder &_fbb, uint32_t version = 0,
+ const std::vector<flatbuffers::Offset<OperatorCode>> *operator_codes = nullptr,
+ const std::vector<flatbuffers::Offset<SubGraph>> *subgraphs = nullptr,
+ const char *description = nullptr,
+ const std::vector<flatbuffers::Offset<Buffer>> *buffers = nullptr,
+ const std::vector<int32_t> *metadata_buffer = nullptr,
+ const std::vector<flatbuffers::Offset<Metadata>> *metadata = nullptr)
+{
+ return onert_tflite::CreateModel(
+ _fbb, version,
+ operator_codes ? _fbb.CreateVector<flatbuffers::Offset<OperatorCode>>(*operator_codes) : 0,
+ subgraphs ? _fbb.CreateVector<flatbuffers::Offset<SubGraph>>(*subgraphs) : 0,
+ description ? _fbb.CreateString(description) : 0,
+ buffers ? _fbb.CreateVector<flatbuffers::Offset<Buffer>>(*buffers) : 0,
+ metadata_buffer ? _fbb.CreateVector<int32_t>(*metadata_buffer) : 0,
+ metadata ? _fbb.CreateVector<flatbuffers::Offset<Metadata>>(*metadata) : 0);
+}
+
+inline bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj,
+ QuantizationDetails type)
+{
+ switch (type)
+ {
+ case QuantizationDetails_NONE:
+ {
+ return true;
+ }
+ case QuantizationDetails_CustomQuantization:
+ {
+ auto ptr = reinterpret_cast<const CustomQuantization *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default:
+ return false;
+ }
+}
+
+inline bool
+VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types)
+{
+ if (!values || !types)
+ return !values && !types;
+ if (values->size() != types->size())
+ return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i)
+ {
+ if (!VerifyQuantizationDetails(verifier, values->Get(i),
+ types->GetEnum<QuantizationDetails>(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj,
+ SparseIndexVector type)
+{
+ switch (type)
+ {
+ case SparseIndexVector_NONE:
+ {
+ return true;
+ }
+ case SparseIndexVector_Int32Vector:
+ {
+ auto ptr = reinterpret_cast<const Int32Vector *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case SparseIndexVector_Uint16Vector:
+ {
+ auto ptr = reinterpret_cast<const Uint16Vector *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case SparseIndexVector_Uint8Vector:
+ {
+ auto ptr = reinterpret_cast<const Uint8Vector *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default:
+ return false;
+ }
+}
+
+inline bool
+VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types)
+{
+ if (!values || !types)
+ return !values && !types;
+ if (values->size() != types->size())
+ return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i)
+ {
+ if (!VerifySparseIndexVector(verifier, values->Get(i), types->GetEnum<SparseIndexVector>(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj,
+ BuiltinOptions type)
+{
+ switch (type)
+ {
+ case BuiltinOptions_NONE:
+ {
+ return true;
+ }
+ case BuiltinOptions_Conv2DOptions:
+ {
+ auto ptr = reinterpret_cast<const Conv2DOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DepthwiseConv2DOptions:
+ {
+ auto ptr = reinterpret_cast<const DepthwiseConv2DOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ConcatEmbeddingsOptions:
+ {
+ auto ptr = reinterpret_cast<const ConcatEmbeddingsOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LSHProjectionOptions:
+ {
+ auto ptr = reinterpret_cast<const LSHProjectionOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_Pool2DOptions:
+ {
+ auto ptr = reinterpret_cast<const Pool2DOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SVDFOptions:
+ {
+ auto ptr = reinterpret_cast<const SVDFOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_RNNOptions:
+ {
+ auto ptr = reinterpret_cast<const RNNOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FullyConnectedOptions:
+ {
+ auto ptr = reinterpret_cast<const FullyConnectedOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SoftmaxOptions:
+ {
+ auto ptr = reinterpret_cast<const SoftmaxOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ConcatenationOptions:
+ {
+ auto ptr = reinterpret_cast<const ConcatenationOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_AddOptions:
+ {
+ auto ptr = reinterpret_cast<const AddOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_L2NormOptions:
+ {
+ auto ptr = reinterpret_cast<const L2NormOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LocalResponseNormalizationOptions:
+ {
+ auto ptr = reinterpret_cast<const LocalResponseNormalizationOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LSTMOptions:
+ {
+ auto ptr = reinterpret_cast<const LSTMOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ResizeBilinearOptions:
+ {
+ auto ptr = reinterpret_cast<const ResizeBilinearOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_CallOptions:
+ {
+ auto ptr = reinterpret_cast<const CallOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ReshapeOptions:
+ {
+ auto ptr = reinterpret_cast<const ReshapeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SkipGramOptions:
+ {
+ auto ptr = reinterpret_cast<const SkipGramOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SpaceToDepthOptions:
+ {
+ auto ptr = reinterpret_cast<const SpaceToDepthOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_EmbeddingLookupSparseOptions:
+ {
+ auto ptr = reinterpret_cast<const EmbeddingLookupSparseOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MulOptions:
+ {
+ auto ptr = reinterpret_cast<const MulOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_PadOptions:
+ {
+ auto ptr = reinterpret_cast<const PadOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_GatherOptions:
+ {
+ auto ptr = reinterpret_cast<const GatherOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BatchToSpaceNDOptions:
+ {
+ auto ptr = reinterpret_cast<const BatchToSpaceNDOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SpaceToBatchNDOptions:
+ {
+ auto ptr = reinterpret_cast<const SpaceToBatchNDOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_TransposeOptions:
+ {
+ auto ptr = reinterpret_cast<const TransposeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ReducerOptions:
+ {
+ auto ptr = reinterpret_cast<const ReducerOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SubOptions:
+ {
+ auto ptr = reinterpret_cast<const SubOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DivOptions:
+ {
+ auto ptr = reinterpret_cast<const DivOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SqueezeOptions:
+ {
+ auto ptr = reinterpret_cast<const SqueezeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SequenceRNNOptions:
+ {
+ auto ptr = reinterpret_cast<const SequenceRNNOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_StridedSliceOptions:
+ {
+ auto ptr = reinterpret_cast<const StridedSliceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ExpOptions:
+ {
+ auto ptr = reinterpret_cast<const ExpOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_TopKV2Options:
+ {
+ auto ptr = reinterpret_cast<const TopKV2Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SplitOptions:
+ {
+ auto ptr = reinterpret_cast<const SplitOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LogSoftmaxOptions:
+ {
+ auto ptr = reinterpret_cast<const LogSoftmaxOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_CastOptions:
+ {
+ auto ptr = reinterpret_cast<const CastOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DequantizeOptions:
+ {
+ auto ptr = reinterpret_cast<const DequantizeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MaximumMinimumOptions:
+ {
+ auto ptr = reinterpret_cast<const MaximumMinimumOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ArgMaxOptions:
+ {
+ auto ptr = reinterpret_cast<const ArgMaxOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LessOptions:
+ {
+ auto ptr = reinterpret_cast<const LessOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_NegOptions:
+ {
+ auto ptr = reinterpret_cast<const NegOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_PadV2Options:
+ {
+ auto ptr = reinterpret_cast<const PadV2Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_GreaterOptions:
+ {
+ auto ptr = reinterpret_cast<const GreaterOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_GreaterEqualOptions:
+ {
+ auto ptr = reinterpret_cast<const GreaterEqualOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LessEqualOptions:
+ {
+ auto ptr = reinterpret_cast<const LessEqualOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SelectOptions:
+ {
+ auto ptr = reinterpret_cast<const SelectOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SliceOptions:
+ {
+ auto ptr = reinterpret_cast<const SliceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_TransposeConvOptions:
+ {
+ auto ptr = reinterpret_cast<const TransposeConvOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SparseToDenseOptions:
+ {
+ auto ptr = reinterpret_cast<const SparseToDenseOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_TileOptions:
+ {
+ auto ptr = reinterpret_cast<const TileOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ExpandDimsOptions:
+ {
+ auto ptr = reinterpret_cast<const ExpandDimsOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_EqualOptions:
+ {
+ auto ptr = reinterpret_cast<const EqualOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_NotEqualOptions:
+ {
+ auto ptr = reinterpret_cast<const NotEqualOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ShapeOptions:
+ {
+ auto ptr = reinterpret_cast<const ShapeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_PowOptions:
+ {
+ auto ptr = reinterpret_cast<const PowOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ArgMinOptions:
+ {
+ auto ptr = reinterpret_cast<const ArgMinOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FakeQuantOptions:
+ {
+ auto ptr = reinterpret_cast<const FakeQuantOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_PackOptions:
+ {
+ auto ptr = reinterpret_cast<const PackOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LogicalOrOptions:
+ {
+ auto ptr = reinterpret_cast<const LogicalOrOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_OneHotOptions:
+ {
+ auto ptr = reinterpret_cast<const OneHotOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LogicalAndOptions:
+ {
+ auto ptr = reinterpret_cast<const LogicalAndOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LogicalNotOptions:
+ {
+ auto ptr = reinterpret_cast<const LogicalNotOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_UnpackOptions:
+ {
+ auto ptr = reinterpret_cast<const UnpackOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FloorDivOptions:
+ {
+ auto ptr = reinterpret_cast<const FloorDivOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SquareOptions:
+ {
+ auto ptr = reinterpret_cast<const SquareOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ZerosLikeOptions:
+ {
+ auto ptr = reinterpret_cast<const ZerosLikeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FillOptions:
+ {
+ auto ptr = reinterpret_cast<const FillOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BidirectionalSequenceLSTMOptions:
+ {
+ auto ptr = reinterpret_cast<const BidirectionalSequenceLSTMOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BidirectionalSequenceRNNOptions:
+ {
+ auto ptr = reinterpret_cast<const BidirectionalSequenceRNNOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_UnidirectionalSequenceLSTMOptions:
+ {
+ auto ptr = reinterpret_cast<const UnidirectionalSequenceLSTMOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_FloorModOptions:
+ {
+ auto ptr = reinterpret_cast<const FloorModOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_RangeOptions:
+ {
+ auto ptr = reinterpret_cast<const RangeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ResizeNearestNeighborOptions:
+ {
+ auto ptr = reinterpret_cast<const ResizeNearestNeighborOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_LeakyReluOptions:
+ {
+ auto ptr = reinterpret_cast<const LeakyReluOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SquaredDifferenceOptions:
+ {
+ auto ptr = reinterpret_cast<const SquaredDifferenceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MirrorPadOptions:
+ {
+ auto ptr = reinterpret_cast<const MirrorPadOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_AbsOptions:
+ {
+ auto ptr = reinterpret_cast<const AbsOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SplitVOptions:
+ {
+ auto ptr = reinterpret_cast<const SplitVOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_UniqueOptions:
+ {
+ auto ptr = reinterpret_cast<const UniqueOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ReverseV2Options:
+ {
+ auto ptr = reinterpret_cast<const ReverseV2Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_AddNOptions:
+ {
+ auto ptr = reinterpret_cast<const AddNOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_GatherNdOptions:
+ {
+ auto ptr = reinterpret_cast<const GatherNdOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_CosOptions:
+ {
+ auto ptr = reinterpret_cast<const CosOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_WhereOptions:
+ {
+ auto ptr = reinterpret_cast<const WhereOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_RankOptions:
+ {
+ auto ptr = reinterpret_cast<const RankOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ReverseSequenceOptions:
+ {
+ auto ptr = reinterpret_cast<const ReverseSequenceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MatrixDiagOptions:
+ {
+ auto ptr = reinterpret_cast<const MatrixDiagOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_QuantizeOptions:
+ {
+ auto ptr = reinterpret_cast<const QuantizeOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_MatrixSetDiagOptions:
+ {
+ auto ptr = reinterpret_cast<const MatrixSetDiagOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_HardSwishOptions:
+ {
+ auto ptr = reinterpret_cast<const HardSwishOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_IfOptions:
+ {
+ auto ptr = reinterpret_cast<const IfOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_WhileOptions:
+ {
+ auto ptr = reinterpret_cast<const WhileOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DepthToSpaceOptions:
+ {
+ auto ptr = reinterpret_cast<const DepthToSpaceOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_NonMaxSuppressionV4Options:
+ {
+ auto ptr = reinterpret_cast<const NonMaxSuppressionV4Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_NonMaxSuppressionV5Options:
+ {
+ auto ptr = reinterpret_cast<const NonMaxSuppressionV5Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_ScatterNdOptions:
+ {
+ auto ptr = reinterpret_cast<const ScatterNdOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SelectV2Options:
+ {
+ auto ptr = reinterpret_cast<const SelectV2Options *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_DensifyOptions:
+ {
+ auto ptr = reinterpret_cast<const DensifyOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_SegmentSumOptions:
+ {
+ auto ptr = reinterpret_cast<const SegmentSumOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case BuiltinOptions_BatchMatMulOptions:
+ {
+ auto ptr = reinterpret_cast<const BatchMatMulOptions *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default:
+ return false;
+ }
+}
+
+inline bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier,
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *values,
+ const flatbuffers::Vector<uint8_t> *types)
+{
+ if (!values || !types)
+ return !values && !types;
+ if (values->size() != types->size())
+ return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i)
+ {
+ if (!VerifyBuiltinOptions(verifier, values->Get(i), types->GetEnum<BuiltinOptions>(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline const onert_tflite::Model *GetModel(const void *buf)
+{
+ return flatbuffers::GetRoot<onert_tflite::Model>(buf);
+}
+
+inline const onert_tflite::Model *GetSizePrefixedModel(const void *buf)
+{
+ return flatbuffers::GetSizePrefixedRoot<onert_tflite::Model>(buf);
+}
+
+inline const char *ModelIdentifier() { return "TFL3"; }
+
+inline bool ModelBufferHasIdentifier(const void *buf)
+{
+ return flatbuffers::BufferHasIdentifier(buf, ModelIdentifier());
+}
+
+inline bool VerifyModelBuffer(flatbuffers::Verifier &verifier)
+{
+ return verifier.VerifyBuffer<onert_tflite::Model>(ModelIdentifier());
+}
+
+inline bool VerifySizePrefixedModelBuffer(flatbuffers::Verifier &verifier)
+{
+ return verifier.VerifySizePrefixedBuffer<onert_tflite::Model>(ModelIdentifier());
+}
+
+inline const char *ModelExtension() { return "tflite"; }
+
+inline void FinishModelBuffer(flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<onert_tflite::Model> root)
+{
+ fbb.Finish(root, ModelIdentifier());
+}
+
+inline void FinishSizePrefixedModelBuffer(flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<onert_tflite::Model> root)
+{
+ fbb.FinishSizePrefixed(root, ModelIdentifier());
+}
+
+} // namespace onert_tflite
+
+#endif // FLATBUFFERS_GENERATED_TFLITESCHEMA_ONERT_TFLITE_H_
diff --git a/runtime/onert/frontend/tflite/tflite_schema-1.13.1.fbs b/runtime/onert/frontend/tflite/tflite_schema-1.13.1.fbs
new file mode 100644
index 000000000..ae6b5230f
--- /dev/null
+++ b/runtime/onert/frontend/tflite/tflite_schema-1.13.1.fbs
@@ -0,0 +1,795 @@
+// Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Revision History
+// Version 0: Initial version.
+// Version 1: Add subgraphs to schema.
+// Version 2: Rename operators to conform to NN API.
+// Version 3: Move buffer data from Model.Subgraph.Tensors to Model.Buffers.
+
+// Change namespace to onert_tflite
+namespace onert_tflite;
+
+// This corresponds to the version.
+file_identifier "TFL3";
+// File extension of any written files.
+file_extension "tflite";
+
+// IMPORTANT: All new members of tables, enums and unions must be added at the
+// end to ensure backwards compatibility.
+
+// The type of data stored in a tensor.
+enum TensorType : byte {
+ FLOAT32 = 0,
+ FLOAT16 = 1,
+ INT32 = 2,
+ UINT8 = 3,
+ INT64 = 4,
+ STRING = 5,
+ BOOL = 6,
+ INT16 = 7,
+ COMPLEX64 = 8,
+ INT8 = 9,
+}
+
+// Custom quantization parameters for experimenting with new quantization
+// techniques.
+table CustomQuantization {
+ custom:[ubyte] (force_align: 16);
+}
+
+// Represents a specific quantization technique's parameters.
+union QuantizationDetails {
+ CustomQuantization,
+}
+
+// Parameters for converting a quantized tensor back to float.
+table QuantizationParameters {
+ // These four parameters are the asymmetric linear quantization parameters.
+ // Given a quantized value q, the corresponding float value f should be:
+ // f = scale * (q - zero_point)
+ // For other quantization types, the QuantizationDetails below is used.
+ min:[float]; // For importing back into tensorflow.
+ max:[float]; // For importing back into tensorflow.
+ scale:[float]; // For dequantizing the tensor's values.
+ zero_point:[long];
+
+ // If this is not none, the quantization parameters above are ignored and the
+ // value of the QuantizationDetails union below should be used.
+ details:QuantizationDetails;
+}
+
+table Tensor {
+ // The tensor shape. The meaning of each entry is operator-specific but
+ // builtin ops use: [batch size, height, width, number of channels] (That's
+ // Tensorflow's NHWC).
+ shape:[int];
+ type:TensorType;
+ // An index that refers to the buffers table at the root of the model. Or,
+ // if there is no data buffer associated (i.e. intermediate results), then
+ // this is 0 (which refers to an always existent empty buffer).
+ //
+ // The data_buffer itself is an opaque container, with the assumption that the
+ // target device is little-endian. In addition, all builtin operators assume
+ // the memory is ordered such that if `shape` is [4, 3, 2], then index
+ // [i, j, k] maps to data_buffer[i*3*2 + j*2 + k].
+ buffer:uint;
+ name:string; // For debugging and importing back into tensorflow.
+ quantization:QuantizationParameters; // Optional.
+
+ is_variable:bool = false;
+}
+
+// A list of builtin operators. Builtin operators are slightly faster than custom
+// ones, but not by much. Moreover, while custom operators accept an opaque
+// object containing configuration parameters, builtins have a predetermined
+// set of acceptable options.
+enum BuiltinOperator : byte {
+ ADD = 0,
+ AVERAGE_POOL_2D = 1,
+ CONCATENATION = 2,
+ CONV_2D = 3,
+ DEPTHWISE_CONV_2D = 4,
+ // DEPTH_TO_SPACE = 5,
+ DEQUANTIZE = 6,
+ EMBEDDING_LOOKUP = 7,
+ FLOOR = 8,
+ FULLY_CONNECTED = 9,
+ HASHTABLE_LOOKUP = 10,
+ L2_NORMALIZATION = 11,
+ L2_POOL_2D = 12,
+ LOCAL_RESPONSE_NORMALIZATION = 13,
+ LOGISTIC = 14,
+ LSH_PROJECTION = 15,
+ LSTM = 16,
+ MAX_POOL_2D = 17,
+ MUL = 18,
+ RELU = 19,
+ // NOTE(aselle): RELU_N1_TO_1 used to be called RELU1, but it was renamed
+ // since different model developers use RELU1 in different ways. Never
+ // create another op called RELU1.
+ RELU_N1_TO_1 = 20,
+ RELU6 = 21,
+ RESHAPE = 22,
+ RESIZE_BILINEAR = 23,
+ RNN = 24,
+ SOFTMAX = 25,
+ SPACE_TO_DEPTH = 26,
+ SVDF = 27,
+ TANH = 28,
+ // TODO(aselle): Consider rename to CONCATENATE_EMBEDDINGS
+ CONCAT_EMBEDDINGS = 29,
+ SKIP_GRAM = 30,
+ CALL = 31,
+ CUSTOM = 32,
+ EMBEDDING_LOOKUP_SPARSE = 33,
+ PAD = 34,
+ UNIDIRECTIONAL_SEQUENCE_RNN = 35,
+ GATHER = 36,
+ BATCH_TO_SPACE_ND = 37,
+ SPACE_TO_BATCH_ND = 38,
+ TRANSPOSE = 39,
+ MEAN = 40,
+ SUB = 41,
+ DIV = 42,
+ SQUEEZE = 43,
+ UNIDIRECTIONAL_SEQUENCE_LSTM = 44,
+ STRIDED_SLICE = 45,
+ BIDIRECTIONAL_SEQUENCE_RNN = 46,
+ EXP = 47,
+ TOPK_V2 = 48,
+ SPLIT = 49,
+ LOG_SOFTMAX = 50,
+ // DELEGATE is a special op type for the operations which are delegated to
+ // other backends.
+ // WARNING: Experimental interface, subject to change
+ DELEGATE = 51,
+ BIDIRECTIONAL_SEQUENCE_LSTM = 52,
+ CAST = 53,
+ PRELU = 54,
+ MAXIMUM = 55,
+ ARG_MAX = 56,
+ MINIMUM = 57,
+ LESS = 58,
+ NEG = 59,
+ PADV2 = 60,
+ GREATER = 61,
+ GREATER_EQUAL = 62,
+ LESS_EQUAL = 63,
+ SELECT = 64,
+ SLICE = 65,
+ SIN = 66,
+ TRANSPOSE_CONV = 67,
+ SPARSE_TO_DENSE = 68,
+ TILE = 69,
+ EXPAND_DIMS = 70,
+ EQUAL = 71,
+ NOT_EQUAL = 72,
+ LOG = 73,
+ SUM = 74,
+ SQRT = 75,
+ RSQRT = 76,
+ SHAPE = 77,
+ POW = 78,
+ ARG_MIN = 79,
+ FAKE_QUANT = 80,
+ REDUCE_PROD = 81,
+ REDUCE_MAX = 82,
+ PACK = 83,
+ LOGICAL_OR = 84,
+ ONE_HOT = 85,
+ LOGICAL_AND = 86,
+ LOGICAL_NOT = 87,
+ UNPACK = 88,
+ REDUCE_MIN = 89,
+ FLOOR_DIV = 90,
+ REDUCE_ANY = 91,
+ SQUARE = 92,
+ ZEROS_LIKE = 93,
+ FILL = 94,
+ FLOOR_MOD = 95,
+ RANGE = 96,
+ RESIZE_NEAREST_NEIGHBOR = 97,
+ LEAKY_RELU = 98,
+ SQUARED_DIFFERENCE = 99,
+ MIRROR_PAD = 100,
+ ABS = 101,
+ SPLIT_V = 102,
+}
+
+// Options for the builtin operators.
+union BuiltinOptions {
+ Conv2DOptions,
+ DepthwiseConv2DOptions,
+ ConcatEmbeddingsOptions,
+ LSHProjectionOptions,
+ Pool2DOptions,
+ SVDFOptions,
+ RNNOptions,
+ FullyConnectedOptions,
+ SoftmaxOptions,
+ ConcatenationOptions,
+ AddOptions,
+ L2NormOptions,
+ LocalResponseNormalizationOptions,
+ LSTMOptions,
+ ResizeBilinearOptions,
+ CallOptions,
+ ReshapeOptions,
+ SkipGramOptions,
+ SpaceToDepthOptions,
+ EmbeddingLookupSparseOptions,
+ MulOptions,
+ PadOptions,
+ GatherOptions,
+ BatchToSpaceNDOptions,
+ SpaceToBatchNDOptions,
+ TransposeOptions,
+ ReducerOptions,
+ SubOptions,
+ DivOptions,
+ SqueezeOptions,
+ SequenceRNNOptions,
+ StridedSliceOptions,
+ ExpOptions,
+ TopKV2Options,
+ SplitOptions,
+ LogSoftmaxOptions,
+ CastOptions,
+ DequantizeOptions,
+ MaximumMinimumOptions,
+ ArgMaxOptions,
+ LessOptions,
+ NegOptions,
+ PadV2Options,
+ GreaterOptions,
+ GreaterEqualOptions,
+ LessEqualOptions,
+ SelectOptions,
+ SliceOptions,
+ TransposeConvOptions,
+ SparseToDenseOptions,
+ TileOptions,
+ ExpandDimsOptions,
+ EqualOptions,
+ NotEqualOptions,
+ ShapeOptions,
+ PowOptions,
+ ArgMinOptions,
+ FakeQuantOptions,
+ PackOptions,
+ LogicalOrOptions,
+ OneHotOptions,
+ LogicalAndOptions,
+ LogicalNotOptions,
+ UnpackOptions,
+ FloorDivOptions,
+ SquareOptions,
+ ZerosLikeOptions,
+ FillOptions,
+ BidirectionalSequenceLSTMOptions,
+ BidirectionalSequenceRNNOptions,
+ UnidirectionalSequenceLSTMOptions,
+ FloorModOptions,
+ RangeOptions,
+ ResizeNearestNeighborOptions,
+ LeakyReluOptions,
+ SquaredDifferenceOptions,
+ MirrorPadOptions,
+ AbsOptions,
+ SplitVOptions,
+}
+
+enum Padding : byte { SAME, VALID }
+
+enum ActivationFunctionType : byte {
+ NONE = 0,
+ RELU = 1,
+ RELU_N1_TO_1 = 2,
+ RELU6 = 3,
+ TANH = 4,
+ SIGN_BIT = 5,
+}
+
+table Conv2DOptions {
+ padding:Padding;
+ stride_w:int;
+ stride_h:int;
+ fused_activation_function:ActivationFunctionType;
+ dilation_w_factor:int = 1;
+ dilation_h_factor:int = 1;
+}
+
+table Pool2DOptions {
+ padding:Padding;
+ stride_w:int;
+ stride_h:int;
+ filter_width:int;
+ filter_height:int;
+ fused_activation_function:ActivationFunctionType;
+}
+
+table DepthwiseConv2DOptions {
+ // Parameters for DepthwiseConv version 1 or above.
+ padding:Padding;
+ stride_w:int;
+ stride_h:int;
+ depth_multiplier:int;
+ fused_activation_function:ActivationFunctionType;
+ // Parameters for DepthwiseConv version 2 or above.
+ dilation_w_factor:int = 1;
+ dilation_h_factor:int = 1;
+}
+
+table ConcatEmbeddingsOptions {
+ num_channels:int;
+ num_columns_per_channel:[int];
+ embedding_dim_per_channel:[int]; // This could be inferred from parameters.
+}
+
+enum LSHProjectionType: byte {
+ UNKNOWN = 0,
+ SPARSE = 1,
+ DENSE = 2,
+}
+
+table LSHProjectionOptions {
+ type: LSHProjectionType;
+}
+
+table SVDFOptions {
+ rank:int;
+ fused_activation_function:ActivationFunctionType;
+}
+
+// An implementation of TensorFlow RNNCell.
+table RNNOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+// An implementation of TensorFlow dynamic_rnn with RNNCell.
+table SequenceRNNOptions {
+ time_major:bool;
+ fused_activation_function:ActivationFunctionType;
+}
+
+// An implementation of TensorFlow bidrectional_dynamic_rnn with RNNCell.
+table BidirectionalSequenceRNNOptions {
+ time_major:bool;
+ fused_activation_function:ActivationFunctionType;
+ merge_outputs: bool;
+}
+
+enum FullyConnectedOptionsWeightsFormat: byte {
+ DEFAULT = 0,
+ SHUFFLED4x16INT8 = 1,
+}
+
+// An implementation of TensorFlow fully_connected (a.k.a Dense) layer.
+table FullyConnectedOptions {
+ // Parameters for FullyConnected version 1 or above.
+ fused_activation_function:ActivationFunctionType;
+
+ // Parameters for FullyConnected version 2 or above.
+ weights_format:FullyConnectedOptionsWeightsFormat = DEFAULT;
+}
+
+table SoftmaxOptions {
+ beta: float;
+}
+
+// An implementation of TensorFlow concat.
+table ConcatenationOptions {
+ axis:int;
+ fused_activation_function:ActivationFunctionType;
+}
+
+table AddOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table MulOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table L2NormOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table LocalResponseNormalizationOptions {
+ radius:int;
+ bias:float;
+ alpha:float;
+ beta:float;
+}
+
+enum LSTMKernelType : byte {
+ // Full LSTM kernel which supports peephole and projection.
+ FULL = 0,
+ // Basic LSTM kernels. Equivalent to TensorFlow BasicLSTMCell.
+ BASIC = 1,
+}
+
+// An implementation of TensorFlow LSTMCell and CoupledInputForgetGateLSTMCell
+table LSTMOptions {
+ // Parameters for LSTM version 1 or above.
+ fused_activation_function:ActivationFunctionType;
+ cell_clip: float; // Optional, 0.0 means no clipping
+ proj_clip: float; // Optional, 0.0 means no clipping
+
+ // Parameters for LSTM version 2 or above.
+ // Basic kernel is only supported in version 2 or above.
+ kernel_type: LSTMKernelType = FULL;
+}
+
+// An implementation of TensorFlow dynamic_rnn with LSTMCell.
+table UnidirectionalSequenceLSTMOptions {
+ fused_activation_function:ActivationFunctionType;
+ cell_clip: float; // Optional, 0.0 means no clipping
+ proj_clip: float; // Optional, 0.0 means no clipping
+
+ // If true then first dimension is sequence, otherwise batch.
+ time_major:bool;
+}
+
+table BidirectionalSequenceLSTMOptions {
+ fused_activation_function:ActivationFunctionType;
+ cell_clip: float; // Optional, 0.0 means no clipping
+ proj_clip: float; // Optional, 0.0 means no clipping
+
+ // If true, store the outputs of both directions into the first output.
+ merge_outputs: bool;
+}
+
+table ResizeBilinearOptions {
+ new_height: int (deprecated);
+ new_width: int (deprecated);
+ align_corners: bool;
+}
+
+table ResizeNearestNeighborOptions {
+ align_corners: bool;
+}
+
+// A call operation options
+table CallOptions {
+ // The subgraph index that needs to be called.
+ subgraph:uint;
+}
+
+table PadOptions {
+}
+
+table PadV2Options {
+}
+
+table ReshapeOptions {
+ new_shape:[int];
+}
+
+table SpaceToBatchNDOptions {
+}
+
+table BatchToSpaceNDOptions {
+}
+
+table SkipGramOptions {
+ ngram_size: int;
+ max_skip_size: int;
+ include_all_ngrams: bool;
+}
+
+table SpaceToDepthOptions {
+ block_size: int;
+}
+
+table SubOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table DivOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table TopKV2Options {
+}
+
+enum CombinerType : byte {
+ SUM = 0,
+ MEAN = 1,
+ SQRTN = 2,
+}
+
+table EmbeddingLookupSparseOptions {
+ combiner:CombinerType;
+}
+
+table GatherOptions {
+ axis: int;
+}
+
+table TransposeOptions {
+}
+
+table ExpOptions {
+}
+
+table ReducerOptions {
+ keep_dims: bool;
+}
+
+table SqueezeOptions {
+ squeeze_dims:[int];
+}
+
+table SplitOptions {
+ num_splits: int;
+}
+
+table SplitVOptions {
+ num_splits: int;
+}
+
+table StridedSliceOptions {
+ begin_mask: int;
+ end_mask: int;
+ ellipsis_mask: int;
+ new_axis_mask: int;
+ shrink_axis_mask: int;
+}
+
+table LogSoftmaxOptions {
+}
+
+table CastOptions {
+ in_data_type: TensorType;
+ out_data_type: TensorType;
+}
+
+table DequantizeOptions {
+}
+
+table MaximumMinimumOptions {
+}
+
+table TileOptions {
+}
+
+table ArgMaxOptions {
+ output_type : TensorType;
+}
+
+table ArgMinOptions {
+ output_type : TensorType;
+}
+
+table GreaterOptions {
+}
+
+table GreaterEqualOptions {
+}
+
+table LessOptions {
+}
+
+table LessEqualOptions {
+}
+
+table NegOptions {
+}
+
+table SelectOptions {
+}
+
+table SliceOptions {
+}
+
+table TransposeConvOptions {
+ padding:Padding;
+ stride_w:int;
+ stride_h:int;
+}
+
+table ExpandDimsOptions {
+}
+
+table SparseToDenseOptions {
+ validate_indices:bool;
+}
+
+table EqualOptions {
+}
+
+table NotEqualOptions {
+}
+
+table ShapeOptions {
+ // Optional output type of the operation (int32 or int64). Defaults to int32.
+ out_type : TensorType;
+}
+
+table PowOptions {
+}
+
+table FakeQuantOptions {
+ // Parameters supported by version 1:
+ min:float;
+ max:float;
+ num_bits:int;
+
+ // Parameters supported by version 2:
+ narrow_range:bool;
+}
+
+table PackOptions {
+ values_count:int;
+ axis:int;
+}
+
+table LogicalOrOptions {
+}
+
+table OneHotOptions {
+ axis:int;
+}
+
+table AbsOptions {
+}
+
+
+table LogicalAndOptions {
+}
+
+table LogicalNotOptions {
+}
+
+table UnpackOptions {
+ num:int;
+ axis:int;
+}
+
+table FloorDivOptions {
+}
+
+table SquareOptions {
+}
+
+table ZerosLikeOptions {
+}
+
+table FillOptions {
+}
+
+table FloorModOptions {
+}
+
+table RangeOptions {
+}
+
+table LeakyReluOptions {
+ alpha:float;
+}
+
+table SquaredDifferenceOptions {
+}
+
+enum MirrorPadMode : byte {
+ // Doesn't include borders.
+ REFLECT = 0,
+ // Includes borders.
+ SYMMETRIC = 1,
+}
+
+table MirrorPadOptions {
+ mode:MirrorPadMode;
+}
+
+// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a
+// builtin, or a string if the operator is custom.
+table OperatorCode {
+ builtin_code:BuiltinOperator;
+ custom_code:string;
+
+ // The version of the operator. The version need to be bumped whenever new
+ // parameters are introduced into an op.
+ version:int = 1;
+}
+
+enum CustomOptionsFormat : byte {
+ FLEXBUFFERS = 0,
+}
+
+// An operator takes tensors as inputs and outputs. The type of operation being
+// performed is determined by an index into the list of valid OperatorCodes,
+// while the specifics of each operations is configured using builtin_options
+// or custom_options.
+table Operator {
+ // Index into the operator_codes array. Using an integer here avoids
+ // complicate map lookups.
+ opcode_index:uint;
+
+ // Optional input and output tensors are indicated by -1.
+ inputs:[int];
+ outputs:[int];
+
+ builtin_options:BuiltinOptions;
+ custom_options:[ubyte];
+ custom_options_format:CustomOptionsFormat;
+
+ // A list of booleans indicating the input tensors which are being mutated by
+ // this operator.(e.g. used by RNN and LSTM).
+ // For example, if the "inputs" array refers to 5 tensors and the second and
+ // fifth are mutable variables, then this list will contain
+ // [false, true, false, false, true].
+ //
+ // If the list is empty, no variable is mutated in this operator.
+ // The list either has the same length as `inputs`, or is empty.
+ mutating_variable_inputs:[bool];
+}
+
+// The root type, defining a subgraph, which typically represents an entire
+// model.
+table SubGraph {
+ // A list of all tensors used in this subgraph.
+ tensors:[Tensor];
+
+ // Indices of the tensors that are inputs into this subgraph. Note this is
+ // the list of non-static tensors that feed into the subgraph for inference.
+ inputs:[int];
+
+ // Indices of the tensors that are outputs out of this subgraph. Note this is
+ // the list of output tensors that are considered the product of the
+ // subgraph's inference.
+ outputs:[int];
+
+ // All operators, in execution order.
+ operators:[Operator];
+
+ // Name of this subgraph (used for debugging).
+ name:string;
+}
+
+// Table of raw data buffers (used for constant tensors). Referenced by tensors
+// by index. The generous alignment accommodates mmap-friendly data structures.
+table Buffer {
+ data:[ubyte] (force_align: 16);
+}
+
+table Model {
+ // Version of the schema.
+ version:uint;
+
+ // A list of all operator codes used in this model. This is
+ // kept in order because operators carry an index into this
+ // vector.
+ operator_codes:[OperatorCode];
+
+ // All the subgraphs of the model. The 0th is assumed to be the main
+ // model.
+ subgraphs:[SubGraph];
+
+ // A description of the model.
+ description:string;
+
+ // Buffers of the model.
+ // Note the 0th entry of this array must be an empty buffer (sentinel).
+ // This is a convention so that tensors without a buffer can provide 0 as
+ // their buffer.
+ buffers:[Buffer];
+
+ // Metadata about the model. Indirects into the existings buffers list.
+ metadata_buffer:[int];
+}
+
+root_type Model;
diff --git a/runtime/onert/frontend/tflite/tflite_schema.fbs b/runtime/onert/frontend/tflite/tflite_schema.fbs
new file mode 100644
index 000000000..9bffb4f3c
--- /dev/null
+++ b/runtime/onert/frontend/tflite/tflite_schema.fbs
@@ -0,0 +1,1095 @@
+// Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+// Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Revision History
+// Version 0: Initial version.
+// Version 1: Add subgraphs to schema.
+// Version 2: Rename operators to conform to NN API.
+// Version 3: Move buffer data from Model.Subgraph.Tensors to Model.Buffers.
+
+// Change namespace to onert_tflite
+namespace onert_tflite;
+
+// This corresponds to the version.
+file_identifier "TFL3";
+// File extension of any written files.
+file_extension "tflite";
+
+// IMPORTANT: All new members of tables, enums and unions must be added at the
+// end to ensure backwards compatibility.
+
+// The type of data stored in a tensor.
+enum TensorType : byte {
+ FLOAT32 = 0,
+ FLOAT16 = 1,
+ INT32 = 2,
+ UINT8 = 3,
+ INT64 = 4,
+ STRING = 5,
+ BOOL = 6,
+ INT16 = 7,
+ COMPLEX64 = 8,
+ INT8 = 9,
+ FLOAT64 = 10,
+}
+
+// Custom quantization parameters for experimenting with new quantization
+// techniques.
+table CustomQuantization {
+ custom:[ubyte] (force_align: 16);
+}
+
+// Represents a specific quantization technique's parameters.
+union QuantizationDetails {
+ CustomQuantization,
+}
+
+// Parameters for converting a quantized tensor back to float.
+table QuantizationParameters {
+ // These four parameters are the asymmetric linear quantization parameters.
+ // Given a quantized value q, the corresponding float value f should be:
+ // f = scale * (q - zero_point)
+ // For other quantization types, the QuantizationDetails below is used.
+ min:[float]; // For importing back into tensorflow.
+ max:[float]; // For importing back into tensorflow.
+ scale:[float]; // For dequantizing the tensor's values.
+ zero_point:[long];
+
+ // If this is not none, the other quantization parameters (i.e. min, max,
+ // scale, zero_point fields above) are ignored and the value of the
+ // QuantizationDetails union should be used.
+ details:QuantizationDetails;
+
+ // Specifies the dimension of the Tensor's shape that the scales and
+ // zero_points correspond to. For example, a tensor t, with dims=[4, 3, 2, 1]
+ // with quantization params:
+ // scale=[1.0, 2.0, 3.0], zero_point=[1, 2, 3], quantization_dimension=1
+ // will be quantized across the second dimension of t.
+ // t[:, 0, :, :] will have scale[0]=1.0, zero_point[0]=1
+ // t[:, 1, :, :] will have scale[1]=2.0, zero_point[0]=2
+ // t[:, 2, :, :] will have scale[2]=3.0, zero_point[0]=3
+ quantized_dimension:int;
+}
+
+// Sparse tensors.
+// We use a modification of the TACO format.
+// Reference: http://tensor-compiler.org/kjolstad-oopsla17-tensor-compiler.pdf
+//
+// To encode a conceptual n-dimensional dense tensor with dims (d0, ..., dn-1),
+// potentially with a k-dimensional block (0 <= k <= n) with dims
+// (dn, ..., dn+k-1), the format needs to specify:
+// 1. In what order to traverse these dimensions. For example, to store a 2-D
+// matrix in row major order, the traversal order would be (d0, d1),
+// whereas to store it in column major order, the traversal order would be
+// (d1, d0). If the 2-D matrix has a 2-D inner block, the traversal order
+// could be (d0, d1, d2, d3).
+// 2. How each block dimension in (dn, ..., dn+k-1) maps to the original
+// tensor dimension in (d0, ..., dn-1).
+// 3. In the traversal order defined above, the format (dense vs. sparse) and
+// index metadata for each dimension. For a dense dimension, this is just
+// the size of that dimension. For a sparse dimension, it's the same as
+// the compressed index defined in the Compressed Sparse Row (CSR) format.
+// (http://scipy-lectures.org/advanced/scipy_sparse/csr_matrix.html)
+
+// The storage type for a dimension. Currently we support:
+// 1. DENSE: each coordinate in this dimension is stored implicitly.
+// 2. SPARSE_CSR: only the coordinates with non-zero elements are stored. The
+// compression technique is the same what CSR uses.
+// More types like a sparse dimension with a different compression technique
+// could be added to the list in the future.
+enum DimensionType : byte {
+ DENSE = 0,
+ SPARSE_CSR = 1,
+}
+
+table Int32Vector {
+ values:[int];
+}
+
+table Uint16Vector {
+ values:[ushort] (force_align: 4);
+}
+
+table Uint8Vector {
+ values:[ubyte] (force_align: 4);
+}
+
+// Variable-typed buffer to store the index metadata for a sparse dimension.
+// The widest type is Int32 instead of UInt32 because tensor's shape is a int32
+// vector. We don't want the per-dimensional index to overflow that range.
+union SparseIndexVector {
+ Int32Vector,
+ Uint16Vector,
+ Uint8Vector
+}
+
+table DimensionMetadata {
+ // Whether a dimension is dense or sparse.
+ format:DimensionType;
+ // Index metadata used for a dimension.
+ // - If format is DimensionType.DENSE then we use the dense_size field to
+ // store the size of that dimension. Each index in that dimension is
+ // stored implicitly.
+ // - If format is DimensionType.SPARSE_CSR then we use array_segments and
+ // array_indices to encode that dimension. array_segments represents how
+ // to segment the indices array, each segment corresponds to one element
+ // in the previous dimension. array_indices represents the index of the
+ // non-zero elements within this dimension (as those in the CSR matrix
+ // format, where the first array is row pointers and the second array is
+ // column indices).
+ dense_size:int;
+ array_segments:SparseIndexVector;
+ array_indices:SparseIndexVector;
+}
+
+// Parameters to encode a sparse TfLite tensor.
+table SparsityParameters {
+ // The traversal order of the dimensions defined in the `shape` field of the
+ // conceptual dense tensor. For a n-dimensional tensors with dims (d0, d1,
+ // ..., dn-1),
+ // - if not block sparse, the traversal_order is just a permutation of (d0,
+ // ..., dn-1). For example, a 2-D matrix stored in row-major order would
+ // have traversal_order = (d0, d1).
+ // - if block sparse with a k-dimensional block (0 <= k <= n), the
+ // traversal_order has n + k elements. The first n elements are still a
+ // permutation of (d0, ..., dn-1). The lask k elements are a permutation
+ // of (dn, ..., dn+k-1), defining how to traverse a block internally. For
+ // example, a 2-D matrix with 2-D blocks, both stored in row-major order
+ // would have traversal_order = (d0, d1, d2, d3).
+ traversal_order:[int];
+ // For an n-dimensional tensor with a k-dimensional block (0 <= k <= n),
+ // stores how a block dimension in (dn, ..., dn+k-1) maps to the original
+ // tensor dimension in (d0, ..., dn).
+ // It's stored in the order of (dn, ..., dn+k-1).
+ // If not block-sparse, this field is NULL.
+ block_map:[int];
+ // In the traversal order defined above, the metadata needed for
+ // each dimension to locate the non-zero values in the original dense tensor.
+ // The size of the dim_metadata array = the size of the traversal_order array
+ // = n + k.
+ dim_metadata:[DimensionMetadata];
+}
+
+table Tensor {
+ // The tensor shape. The meaning of each entry is operator-specific but
+ // builtin ops use: [batch size, height, width, number of channels] (That's
+ // Tensorflow's NHWC).
+ shape:[int];
+ type:TensorType;
+ // An index that refers to the buffers table at the root of the model. Or,
+ // if there is no data buffer associated (i.e. intermediate results), then
+ // this is 0 (which refers to an always existent empty buffer).
+ //
+ // The data_buffer itself is an opaque container, with the assumption that the
+ // target device is little-endian. In addition, all builtin operators assume
+ // the memory is ordered such that if `shape` is [4, 3, 2], then index
+ // [i, j, k] maps to data_buffer[i*3*2 + j*2 + k].
+ buffer:uint;
+ name:string; // For debugging and importing back into tensorflow.
+ quantization:QuantizationParameters; // Optional.
+
+ is_variable:bool = false;
+
+ // Parameters to encode a sparse tensor. See the example in
+ // tensorflow/lite/testdata/sparse_tensor.json.
+ sparsity:SparsityParameters; // Optional.
+
+ // Encodes `shape` with unknown dimensions. Unknown dimensions are
+ // represented with -1.
+ shape_signature:[int]; // Optional.
+}
+
+// A list of builtin operators. Builtin operators are slightly faster than custom
+// ones, but not by much. Moreover, while custom operators accept an opaque
+// object containing configuration parameters, builtins have a predetermined
+// set of acceptable options.
+
+enum BuiltinOperator : byte {
+ ADD = 0,
+ AVERAGE_POOL_2D = 1,
+ CONCATENATION = 2,
+ CONV_2D = 3,
+ DEPTHWISE_CONV_2D = 4,
+ DEPTH_TO_SPACE = 5,
+ DEQUANTIZE = 6,
+ EMBEDDING_LOOKUP = 7,
+ FLOOR = 8,
+ FULLY_CONNECTED = 9,
+ HASHTABLE_LOOKUP = 10,
+ L2_NORMALIZATION = 11,
+ L2_POOL_2D = 12,
+ LOCAL_RESPONSE_NORMALIZATION = 13,
+ LOGISTIC = 14,
+ LSH_PROJECTION = 15,
+ LSTM = 16,
+ MAX_POOL_2D = 17,
+ MUL = 18,
+ RELU = 19,
+ // NOTE(aselle): RELU_N1_TO_1 used to be called RELU1, but it was renamed
+ // since different model developers use RELU1 in different ways. Never
+ // create another op called RELU1.
+ RELU_N1_TO_1 = 20,
+ RELU6 = 21,
+ RESHAPE = 22,
+ RESIZE_BILINEAR = 23,
+ RNN = 24,
+ SOFTMAX = 25,
+ SPACE_TO_DEPTH = 26,
+ SVDF = 27,
+ TANH = 28,
+ // TODO(aselle): Consider rename to CONCATENATE_EMBEDDINGS
+ CONCAT_EMBEDDINGS = 29,
+ SKIP_GRAM = 30,
+ CALL = 31,
+ CUSTOM = 32,
+ EMBEDDING_LOOKUP_SPARSE = 33,
+ PAD = 34,
+ UNIDIRECTIONAL_SEQUENCE_RNN = 35,
+ GATHER = 36,
+ BATCH_TO_SPACE_ND = 37,
+ SPACE_TO_BATCH_ND = 38,
+ TRANSPOSE = 39,
+ MEAN = 40,
+ SUB = 41,
+ DIV = 42,
+ SQUEEZE = 43,
+ UNIDIRECTIONAL_SEQUENCE_LSTM = 44,
+ STRIDED_SLICE = 45,
+ BIDIRECTIONAL_SEQUENCE_RNN = 46,
+ EXP = 47,
+ TOPK_V2 = 48,
+ SPLIT = 49,
+ LOG_SOFTMAX = 50,
+ // DELEGATE is a special op type for the operations which are delegated to
+ // other backends.
+ // WARNING: Experimental interface, subject to change
+ DELEGATE = 51,
+ BIDIRECTIONAL_SEQUENCE_LSTM = 52,
+ CAST = 53,
+ PRELU = 54,
+ MAXIMUM = 55,
+ ARG_MAX = 56,
+ MINIMUM = 57,
+ LESS = 58,
+ NEG = 59,
+ PADV2 = 60,
+ GREATER = 61,
+ GREATER_EQUAL = 62,
+ LESS_EQUAL = 63,
+ SELECT = 64,
+ SLICE = 65,
+ SIN = 66,
+ TRANSPOSE_CONV = 67,
+ SPARSE_TO_DENSE = 68,
+ TILE = 69,
+ EXPAND_DIMS = 70,
+ EQUAL = 71,
+ NOT_EQUAL = 72,
+ LOG = 73,
+ SUM = 74,
+ SQRT = 75,
+ RSQRT = 76,
+ SHAPE = 77,
+ POW = 78,
+ ARG_MIN = 79,
+ FAKE_QUANT = 80,
+ REDUCE_PROD = 81,
+ REDUCE_MAX = 82,
+ PACK = 83,
+ LOGICAL_OR = 84,
+ ONE_HOT = 85,
+ LOGICAL_AND = 86,
+ LOGICAL_NOT = 87,
+ UNPACK = 88,
+ REDUCE_MIN = 89,
+ FLOOR_DIV = 90,
+ REDUCE_ANY = 91,
+ SQUARE = 92,
+ ZEROS_LIKE = 93,
+ FILL = 94,
+ FLOOR_MOD = 95,
+ RANGE = 96,
+ RESIZE_NEAREST_NEIGHBOR = 97,
+ LEAKY_RELU = 98,
+ SQUARED_DIFFERENCE = 99,
+ MIRROR_PAD = 100,
+ ABS = 101,
+ SPLIT_V = 102,
+ UNIQUE = 103,
+ CEIL = 104,
+ REVERSE_V2 = 105,
+ ADD_N = 106,
+ GATHER_ND = 107,
+ COS = 108,
+ WHERE = 109,
+ RANK = 110,
+ ELU = 111,
+ REVERSE_SEQUENCE = 112,
+ MATRIX_DIAG = 113,
+ QUANTIZE = 114,
+ MATRIX_SET_DIAG = 115,
+ ROUND = 116,
+ HARD_SWISH = 117,
+ IF = 118,
+ WHILE = 119,
+ NON_MAX_SUPPRESSION_V4 = 120,
+ NON_MAX_SUPPRESSION_V5 = 121,
+ SCATTER_ND = 122,
+ SELECT_V2 = 123,
+ DENSIFY = 124,
+ SEGMENT_SUM = 125,
+ BATCH_MATMUL = 126
+}
+
+
+// Options for the builtin operators.
+union BuiltinOptions {
+ Conv2DOptions,
+ DepthwiseConv2DOptions,
+ ConcatEmbeddingsOptions,
+ LSHProjectionOptions,
+ Pool2DOptions,
+ SVDFOptions,
+ RNNOptions,
+ FullyConnectedOptions,
+ SoftmaxOptions,
+ ConcatenationOptions,
+ AddOptions,
+ L2NormOptions,
+ LocalResponseNormalizationOptions,
+ LSTMOptions,
+ ResizeBilinearOptions,
+ CallOptions,
+ ReshapeOptions,
+ SkipGramOptions,
+ SpaceToDepthOptions,
+ EmbeddingLookupSparseOptions,
+ MulOptions,
+ PadOptions,
+ GatherOptions,
+ BatchToSpaceNDOptions,
+ SpaceToBatchNDOptions,
+ TransposeOptions,
+ ReducerOptions,
+ SubOptions,
+ DivOptions,
+ SqueezeOptions,
+ SequenceRNNOptions,
+ StridedSliceOptions,
+ ExpOptions,
+ TopKV2Options,
+ SplitOptions,
+ LogSoftmaxOptions,
+ CastOptions,
+ DequantizeOptions,
+ MaximumMinimumOptions,
+ ArgMaxOptions,
+ LessOptions,
+ NegOptions,
+ PadV2Options,
+ GreaterOptions,
+ GreaterEqualOptions,
+ LessEqualOptions,
+ SelectOptions,
+ SliceOptions,
+ TransposeConvOptions,
+ SparseToDenseOptions,
+ TileOptions,
+ ExpandDimsOptions,
+ EqualOptions,
+ NotEqualOptions,
+ ShapeOptions,
+ PowOptions,
+ ArgMinOptions,
+ FakeQuantOptions,
+ PackOptions,
+ LogicalOrOptions,
+ OneHotOptions,
+ LogicalAndOptions,
+ LogicalNotOptions,
+ UnpackOptions,
+ FloorDivOptions,
+ SquareOptions,
+ ZerosLikeOptions,
+ FillOptions,
+ BidirectionalSequenceLSTMOptions,
+ BidirectionalSequenceRNNOptions,
+ UnidirectionalSequenceLSTMOptions,
+ FloorModOptions,
+ RangeOptions,
+ ResizeNearestNeighborOptions,
+ LeakyReluOptions,
+ SquaredDifferenceOptions,
+ MirrorPadOptions,
+ AbsOptions,
+ SplitVOptions,
+ UniqueOptions,
+ ReverseV2Options,
+ AddNOptions,
+ GatherNdOptions,
+ CosOptions,
+ WhereOptions,
+ RankOptions,
+ ReverseSequenceOptions,
+ MatrixDiagOptions,
+ QuantizeOptions,
+ MatrixSetDiagOptions,
+ HardSwishOptions,
+ IfOptions,
+ WhileOptions,
+ DepthToSpaceOptions,
+ NonMaxSuppressionV4Options,
+ NonMaxSuppressionV5Options,
+ ScatterNdOptions,
+ SelectV2Options,
+ DensifyOptions,
+ SegmentSumOptions,
+ BatchMatMulOptions
+}
+
+enum Padding : byte { SAME, VALID }
+
+enum ActivationFunctionType : byte {
+ NONE = 0,
+ RELU = 1,
+ RELU_N1_TO_1 = 2,
+ RELU6 = 3,
+ TANH = 4,
+ SIGN_BIT = 5,
+}
+
+table Conv2DOptions {
+ padding:Padding;
+ stride_w:int;
+ stride_h:int;
+ fused_activation_function:ActivationFunctionType;
+ dilation_w_factor:int = 1;
+ dilation_h_factor:int = 1;
+}
+
+table Pool2DOptions {
+ padding:Padding;
+ stride_w:int;
+ stride_h:int;
+ filter_width:int;
+ filter_height:int;
+ fused_activation_function:ActivationFunctionType;
+}
+
+table DepthwiseConv2DOptions {
+ // Parameters for DepthwiseConv version 1 or above.
+ padding:Padding;
+ stride_w:int;
+ stride_h:int;
+ // `depth_multiplier` is redundant. It's used by CPU kernels in
+ // TensorFlow 2.0 or below, but ignored in versions above.
+ // See comments in lite/c/builtin_op_data.h for more details.
+ depth_multiplier:int;
+ fused_activation_function:ActivationFunctionType;
+ // Parameters for DepthwiseConv version 2 or above.
+ dilation_w_factor:int = 1;
+ dilation_h_factor:int = 1;
+}
+
+table ConcatEmbeddingsOptions {
+ num_channels:int;
+ num_columns_per_channel:[int];
+ embedding_dim_per_channel:[int]; // This could be inferred from parameters.
+}
+
+enum LSHProjectionType: byte {
+ UNKNOWN = 0,
+ SPARSE = 1,
+ DENSE = 2,
+}
+
+table LSHProjectionOptions {
+ type: LSHProjectionType;
+}
+
+table SVDFOptions {
+ rank:int;
+ fused_activation_function:ActivationFunctionType;
+ // For weights-only quantization, use asymmetric quantization for non
+ // constant inputs at evaluation time.
+ asymmetric_quantize_inputs:bool;
+}
+
+// An implementation of TensorFlow RNNCell.
+table RNNOptions {
+ fused_activation_function:ActivationFunctionType;
+ asymmetric_quantize_inputs:bool;
+}
+
+// An implementation of TensorFlow dynamic_rnn with RNNCell.
+table SequenceRNNOptions {
+ time_major:bool;
+ fused_activation_function:ActivationFunctionType;
+ asymmetric_quantize_inputs:bool;
+}
+
+// An implementation of TensorFlow bidrectional_dynamic_rnn with RNNCell.
+table BidirectionalSequenceRNNOptions {
+ time_major:bool;
+ fused_activation_function:ActivationFunctionType;
+ merge_outputs: bool;
+ asymmetric_quantize_inputs:bool;
+}
+
+enum FullyConnectedOptionsWeightsFormat: byte {
+ DEFAULT = 0,
+ SHUFFLED4x16INT8 = 1,
+}
+
+// An implementation of TensorFlow fully_connected (a.k.a Dense) layer.
+table FullyConnectedOptions {
+ // Parameters for FullyConnected version 1 or above.
+ fused_activation_function:ActivationFunctionType;
+
+ // Parameters for FullyConnected version 2 or above.
+ weights_format:FullyConnectedOptionsWeightsFormat = DEFAULT;
+
+ // Parameters for FullyConnected version 5 or above.
+ // If set to true, then the number of dimension is preserved. Furthermore,
+ // all but the last dimension of the input and output shapes will be equal.
+ keep_num_dims: bool;
+
+ // Parameters for FullyConnected version 7 or above.
+ // If set to true, then weights-only op will use asymmetric quantization for
+ // inputs.
+ asymmetric_quantize_inputs: bool;
+}
+
+table SoftmaxOptions {
+ beta: float;
+}
+
+// An implementation of TensorFlow concat.
+table ConcatenationOptions {
+ axis:int;
+ fused_activation_function:ActivationFunctionType;
+}
+
+table AddOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table MulOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table L2NormOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table LocalResponseNormalizationOptions {
+ radius:int;
+ bias:float;
+ alpha:float;
+ beta:float;
+}
+
+enum LSTMKernelType : byte {
+ // Full LSTM kernel which supports peephole and projection.
+ FULL = 0,
+ // Basic LSTM kernels. Equivalent to TensorFlow BasicLSTMCell.
+ BASIC = 1,
+}
+
+// An implementation of TensorFlow LSTMCell and CoupledInputForgetGateLSTMCell
+table LSTMOptions {
+ // Parameters for LSTM version 1 or above.
+ fused_activation_function:ActivationFunctionType;
+ cell_clip: float; // Optional, 0.0 means no clipping
+ proj_clip: float; // Optional, 0.0 means no clipping
+
+ // Parameters for LSTM version 2 or above.
+ // Basic kernel is only supported in version 2 or above.
+ kernel_type: LSTMKernelType = FULL;
+
+ // Parameters for LSTM version 4 or above.
+ asymmetric_quantize_inputs: bool;
+}
+
+// An implementation of TensorFlow dynamic_rnn with LSTMCell.
+table UnidirectionalSequenceLSTMOptions {
+ fused_activation_function:ActivationFunctionType;
+ cell_clip: float; // Optional, 0.0 means no clipping
+ proj_clip: float; // Optional, 0.0 means no clipping
+
+ // If true then first dimension is sequence, otherwise batch.
+ time_major:bool;
+
+ // Parameter for Unidirectional Sequence LSTM version 4.
+ asymmetric_quantize_inputs:bool;
+}
+
+table BidirectionalSequenceLSTMOptions {
+ // Parameters supported by version 1:
+ fused_activation_function:ActivationFunctionType;
+ cell_clip: float; // Optional, 0.0 means no clipping
+ proj_clip: float; // Optional, 0.0 means no clipping
+
+ // If true, store the outputs of both directions into the first output.
+ merge_outputs: bool;
+
+ // Parameters supported by version 2:
+ // If true then first dimension is sequence, otherwise batch.
+ // Version 1 implementations assumed time_major to be true, so this default
+ // value should never change.
+ time_major: bool = true;
+
+ // Parameters for version 3 or above.
+ asymmetric_quantize_inputs:bool;
+}
+
+table ResizeBilinearOptions {
+ new_height: int (deprecated);
+ new_width: int (deprecated);
+ align_corners: bool;
+ half_pixel_centers: bool;
+}
+
+table ResizeNearestNeighborOptions {
+ align_corners: bool;
+}
+
+// A call operation options
+table CallOptions {
+ // The subgraph index that needs to be called.
+ subgraph:uint;
+}
+
+table PadOptions {
+}
+
+table PadV2Options {
+}
+
+table ReshapeOptions {
+ new_shape:[int];
+}
+
+table SpaceToBatchNDOptions {
+}
+
+table BatchToSpaceNDOptions {
+}
+
+table SkipGramOptions {
+ ngram_size: int;
+ max_skip_size: int;
+ include_all_ngrams: bool;
+}
+
+table SpaceToDepthOptions {
+ block_size: int;
+}
+
+table DepthToSpaceOptions {
+ block_size: int;
+}
+
+table SubOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table DivOptions {
+ fused_activation_function:ActivationFunctionType;
+}
+
+table TopKV2Options {
+}
+
+enum CombinerType : byte {
+ SUM = 0,
+ MEAN = 1,
+ SQRTN = 2,
+}
+
+table EmbeddingLookupSparseOptions {
+ combiner:CombinerType;
+}
+
+table GatherOptions {
+ axis: int;
+}
+
+table TransposeOptions {
+}
+
+table ExpOptions {
+}
+
+table CosOptions {
+}
+
+table ReducerOptions {
+ keep_dims: bool;
+}
+
+table SqueezeOptions {
+ squeeze_dims:[int];
+}
+
+table SplitOptions {
+ num_splits: int;
+}
+
+table SplitVOptions {
+ num_splits: int;
+}
+
+table StridedSliceOptions {
+ begin_mask: int;
+ end_mask: int;
+ ellipsis_mask: int;
+ new_axis_mask: int;
+ shrink_axis_mask: int;
+}
+
+table LogSoftmaxOptions {
+}
+
+table CastOptions {
+ in_data_type: TensorType;
+ out_data_type: TensorType;
+}
+
+table DequantizeOptions {
+}
+
+table MaximumMinimumOptions {
+}
+
+table TileOptions {
+}
+
+table ArgMaxOptions {
+ output_type : TensorType;
+}
+
+table ArgMinOptions {
+ output_type : TensorType;
+}
+
+table GreaterOptions {
+}
+
+table GreaterEqualOptions {
+}
+
+table LessOptions {
+}
+
+table LessEqualOptions {
+}
+
+table NegOptions {
+}
+
+table SelectOptions {
+}
+
+table SliceOptions {
+}
+
+table TransposeConvOptions {
+ padding:Padding;
+ stride_w:int;
+ stride_h:int;
+}
+
+table ExpandDimsOptions {
+}
+
+table SparseToDenseOptions {
+ validate_indices:bool;
+}
+
+table EqualOptions {
+}
+
+table NotEqualOptions {
+}
+
+table ShapeOptions {
+ // Optional output type of the operation (int32 or int64). Defaults to int32.
+ out_type : TensorType;
+}
+
+table RankOptions {
+}
+
+table PowOptions {
+}
+
+table FakeQuantOptions {
+ // Parameters supported by version 1:
+ min:float;
+ max:float;
+ num_bits:int;
+
+ // Parameters supported by version 2:
+ narrow_range:bool;
+}
+
+table PackOptions {
+ values_count:int;
+ axis:int;
+}
+
+table LogicalOrOptions {
+}
+
+table OneHotOptions {
+ axis:int;
+}
+
+table AbsOptions {
+}
+
+
+table HardSwishOptions {
+}
+
+table LogicalAndOptions {
+}
+
+table LogicalNotOptions {
+}
+
+table UnpackOptions {
+ num:int;
+ axis:int;
+}
+
+table FloorDivOptions {
+}
+
+table SquareOptions {
+}
+
+table ZerosLikeOptions {
+}
+
+table FillOptions {
+}
+
+table FloorModOptions {
+}
+
+table RangeOptions {
+}
+
+table LeakyReluOptions {
+ alpha:float;
+}
+
+table SquaredDifferenceOptions {
+}
+
+enum MirrorPadMode : byte {
+ // Doesn't include borders.
+ REFLECT = 0,
+ // Includes borders.
+ SYMMETRIC = 1,
+}
+
+table MirrorPadOptions {
+ mode:MirrorPadMode;
+}
+
+table UniqueOptions {
+ idx_out_type:TensorType = INT32;
+}
+
+table ReverseV2Options {
+}
+
+table AddNOptions {
+}
+
+table GatherNdOptions {
+}
+
+table WhereOptions {
+}
+
+table ReverseSequenceOptions {
+ seq_dim:int;
+ batch_dim:int = 0;
+}
+
+table MatrixDiagOptions {
+}
+
+table QuantizeOptions {
+}
+
+table MatrixSetDiagOptions {
+}
+
+table IfOptions {
+ then_subgraph_index:int;
+ else_subgraph_index:int;
+}
+
+table WhileOptions {
+ cond_subgraph_index:int;
+ body_subgraph_index:int;
+}
+
+table NonMaxSuppressionV4Options {
+}
+
+table NonMaxSuppressionV5Options {
+}
+
+table ScatterNdOptions {
+}
+
+table SelectV2Options {
+}
+
+table DensifyOptions {
+}
+
+table SegmentSumOptions {
+}
+
+table BatchMatMulOptions {
+ adjoint_lhs:bool;
+ adjoint_rhs:bool;
+}
+
+// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a
+// builtin, or a string if the operator is custom.
+table OperatorCode {
+ builtin_code:BuiltinOperator;
+ custom_code:string;
+
+ // The version of the operator. The version need to be bumped whenever new
+ // parameters are introduced into an op.
+ version:int = 1;
+}
+
+enum CustomOptionsFormat : byte {
+ FLEXBUFFERS = 0,
+}
+
+// An operator takes tensors as inputs and outputs. The type of operation being
+// performed is determined by an index into the list of valid OperatorCodes,
+// while the specifics of each operations is configured using builtin_options
+// or custom_options.
+table Operator {
+ // Index into the operator_codes array. Using an integer here avoids
+ // complicate map lookups.
+ opcode_index:uint;
+
+ // Optional input are indicated by -1.
+ inputs:[int];
+ outputs:[int];
+
+ builtin_options:BuiltinOptions;
+ custom_options:[ubyte];
+ custom_options_format:CustomOptionsFormat;
+
+ // A list of booleans indicating the input tensors which are being mutated by
+ // this operator.(e.g. used by RNN and LSTM).
+ // For example, if the "inputs" array refers to 5 tensors and the second and
+ // fifth are mutable variables, then this list will contain
+ // [false, true, false, false, true].
+ //
+ // If the list is empty, no variable is mutated in this operator.
+ // The list either has the same length as `inputs`, or is empty.
+ mutating_variable_inputs:[bool];
+
+ // A list of indices to the subgraph's "tensors" that are internal to an Op.
+ // Internal tensors are those that do not flow in or out of the operation,
+ // but instead are part of internal computation. As such, the operation's
+ // implementation may manage its memory more efficiently. They are needed
+ // however (i.e. not just an implementation detail) since they are part of the
+ // computation, which may require relevant metadata such as quantization
+ // parameters.
+ intermediates:[int];
+}
+
+// The root type, defining a subgraph, which typically represents an entire
+// model.
+table SubGraph {
+ // A list of all tensors used in this subgraph.
+ tensors:[Tensor];
+
+ // Indices of the tensors that are inputs into this subgraph. Note this is
+ // the list of non-static tensors that feed into the subgraph for inference.
+ inputs:[int];
+
+ // Indices of the tensors that are outputs out of this subgraph. Note this is
+ // the list of output tensors that are considered the product of the
+ // subgraph's inference.
+ outputs:[int];
+
+ // All operators, in execution order.
+ operators:[Operator];
+
+ // Name of this subgraph (used for debugging).
+ name:string;
+}
+
+// Table of raw data buffers (used for constant tensors). Referenced by tensors
+// by index. The generous alignment accommodates mmap-friendly data structures.
+table Buffer {
+ data:[ubyte] (force_align: 16);
+}
+
+table Metadata {
+ // A human readable string to uniquely identify a Metadata.
+ name:string;
+ // An index to the buffers table.
+ buffer:uint;
+}
+
+table Model {
+ // Version of the schema.
+ version:uint;
+
+ // A list of all operator codes used in this model. This is
+ // kept in order because operators carry an index into this
+ // vector.
+ operator_codes:[OperatorCode];
+
+ // All the subgraphs of the model. The 0th is assumed to be the main
+ // model.
+ subgraphs:[SubGraph];
+
+ // A description of the model.
+ description:string;
+
+ // Buffers of the model.
+ // Note the 0th entry of this array must be an empty buffer (sentinel).
+ // This is a convention so that tensors without a buffer can provide 0 as
+ // their buffer.
+ buffers:[Buffer];
+
+ // Metadata about the model. Indirects into the existings buffers list.
+ // Deprecated, prefer to use metadata field.
+ metadata_buffer:[int];
+
+ // Metadata about the model.
+ metadata:[Metadata];
+}
+
+root_type Model;
diff --git a/runtime/onert/sample/CMakeLists.txt b/runtime/onert/sample/CMakeLists.txt
new file mode 100644
index 000000000..d853ba634
--- /dev/null
+++ b/runtime/onert/sample/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(minimal)
diff --git a/runtime/onert/sample/minimal/CMakeLists.txt b/runtime/onert/sample/minimal/CMakeLists.txt
new file mode 100644
index 000000000..e54223e3b
--- /dev/null
+++ b/runtime/onert/sample/minimal/CMakeLists.txt
@@ -0,0 +1,10 @@
+if(NOT BUILD_MINIMAL_SAMPLE)
+ return()
+endif(NOT BUILD_MINIMAL_SAMPLE)
+
+list(APPEND MINIMAL_SRCS "src/minimal.cc")
+
+add_executable(onert-minimal-app ${MINIMAL_SRCS})
+target_link_libraries(onert-minimal-app nnfw-dev pthread dl)
+
+install(TARGETS onert-minimal-app DESTINATION bin)
diff --git a/runtime/onert/sample/minimal/README.md b/runtime/onert/sample/minimal/README.md
new file mode 100644
index 000000000..fecad6fb2
--- /dev/null
+++ b/runtime/onert/sample/minimal/README.md
@@ -0,0 +1,13 @@
+# minimal
+
+`minimal` is a simple driver to run `nnpackage` with nnfw API.
+
+It takes `nnpackage` as input. It uses **nnfwAPI** internally.
+
+It assumes model of float32 tensor type as an input.
+
+## Usage
+
+```
+$ ./minimal path_to_nnpackage_directory
+```
diff --git a/runtime/onert/sample/minimal/src/minimal.cc b/runtime/onert/sample/minimal/src/minimal.cc
new file mode 100644
index 000000000..0436b9368
--- /dev/null
+++ b/runtime/onert/sample/minimal/src/minimal.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nnfw.h"
+#include <vector>
+#include <iostream>
+
+uint64_t num_elems(const nnfw_tensorinfo *ti)
+{
+ uint64_t n = 1;
+ for (uint32_t i = 0; i < ti->rank; ++i)
+ {
+ n *= ti->dims[i];
+ }
+ return n;
+}
+
+int main(const int argc, char **argv)
+{
+ nnfw_session *session = nullptr;
+ nnfw_create_session(&session);
+
+ // Loading nnpackage
+ nnfw_load_model_from_file(session, argv[1]);
+
+ // Use acl_neon backend for CONV_2D and acl_cl for otherwise.
+ // Note that defalut backend is acl_cl
+ nnfw_set_op_backend(session, "CONV_2D", "acl_neon");
+
+ // Compile model
+ nnfw_prepare(session);
+
+ // Prepare input. Here we just allocate dummy input arrays.
+ std::vector<float> input;
+ nnfw_tensorinfo ti;
+ nnfw_input_tensorinfo(session, 0, &ti); // get first input's info
+ uint32_t input_elements = num_elems(&ti);
+ input.resize(input_elements);
+ // TODO: Please add initialization for your input.
+ nnfw_set_input(session, 0, ti.dtype, input.data(), sizeof(float) * input_elements);
+
+ // Prepare output
+ std::vector<float> output;
+ nnfw_output_tensorinfo(session, 0, &ti); // get first output's info
+ uint32_t output_elements = num_elems(&ti);
+ output.resize(output_elements);
+ nnfw_set_output(session, 0, ti.dtype, output.data(), sizeof(float) * output_elements);
+
+ // Do inference
+ nnfw_run(session);
+
+ // TODO: Please print or compare the output value in your way.
+
+ nnfw_close_session(session);
+
+ std::cout << "nnpackage " << argv[1] << " runs successfully." << std::endl;
+ return 0;
+}
diff --git a/runtime/onert/test/CMakeLists.txt b/runtime/onert/test/CMakeLists.txt
new file mode 100644
index 000000000..38899976d
--- /dev/null
+++ b/runtime/onert/test/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(TEST_ONERT test_onert)
+
+file(GLOB_RECURSE TESTS "*.cc")
+
+add_executable(${TEST_ONERT} ${TESTS})
+
+target_include_directories(${TEST_ONERT} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../core/src)
+
+target_link_libraries(${TEST_ONERT} onert_core)
+target_link_libraries(${TEST_ONERT} gtest)
+target_link_libraries(${TEST_ONERT} gtest_main)
+target_link_libraries(${TEST_ONERT} ${LIB_PTHREAD} dl)
+add_test(${TEST_ONERT} ${TEST_ONERT})
+
+install(TARGETS ${TEST_ONERT} DESTINATION unittest_standalone)
diff --git a/runtime/onert/test/core/compiler/Scheduler.cc b/runtime/onert/test/core/compiler/Scheduler.cc
new file mode 100644
index 000000000..50f3964db
--- /dev/null
+++ b/runtime/onert/test/core/compiler/Scheduler.cc
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <compiler/HEScheduler.h>
+#include <exec/ExecTime.h>
+
+#include <ir/Shape.h>
+#include <ir/InternalType.h>
+#include <ir/TypeInfo.h>
+#include <ir/DataType.h>
+
+#include <ir/operation/BinaryArithmetic.h>
+#include <ir/operation/FullyConnected.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+using namespace onert;
+using namespace ir;
+using namespace backend;
+using namespace operation;
+using namespace exec;
+
+//
+// Mock backends classes
+//
+
+struct MockConfigCPU : public IConfig
+{
+ std::string id() override { return "cpu"; }
+ bool initialize() override { return true; };
+ bool supportPermutation() override { return false; }
+ Layout supportLayout(const Operation &, Layout) override { return Layout::UNKNOWN; }
+ bool supportDynamicTensor() override { return false; }
+ bool supportFP16() override { return false; }
+};
+
+struct MockBackendCPU : public Backend
+{
+ std::shared_ptr<IConfig> config() const override { return std::make_shared<MockConfigCPU>(); }
+ std::unique_ptr<BackendContext>
+ newContext(const Graph &, const std::shared_ptr<custom::IKernelBuilder> &, bool) const override
+ {
+ return std::unique_ptr<BackendContext>(
+ new BackendContext{this, nullptr, nullptr, nullptr, nullptr});
+ }
+};
+
+struct MockConfigGPU : public IConfig
+{
+ std::string id() override { return "gpu"; }
+ bool initialize() override { return true; };
+ bool supportPermutation() override { return false; }
+ ir::Layout supportLayout(const ir::Operation &, ir::Layout) override
+ {
+ return ir::Layout::UNKNOWN;
+ }
+ bool supportDynamicTensor() override { return false; }
+ bool supportFP16() override { return false; }
+};
+
+struct MockBackendGPU : public Backend
+{
+ std::shared_ptr<IConfig> config() const override { return std::make_shared<MockConfigGPU>(); }
+ std::unique_ptr<BackendContext>
+ newContext(const Graph &, const std::shared_ptr<custom::IKernelBuilder> &, bool) const override
+ {
+ return std::unique_ptr<BackendContext>(
+ new BackendContext{this, nullptr, nullptr, nullptr, nullptr});
+ }
+};
+
+struct MockConfigNPU : public IConfig
+{
+ std::string id() override { return "npu"; }
+ bool initialize() override { return true; };
+ bool supportPermutation() override { return false; }
+ ir::Layout supportLayout(const ir::Operation &, ir::Layout) override
+ {
+ return ir::Layout::UNKNOWN;
+ }
+ bool supportDynamicTensor() override { return false; }
+ bool supportFP16() override { return false; }
+};
+
+struct MockBackendNPU : public Backend
+{
+ std::shared_ptr<IConfig> config() const override { return std::make_shared<MockConfigNPU>(); }
+ std::unique_ptr<BackendContext>
+ newContext(const Graph &, const std::shared_ptr<custom::IKernelBuilder> &, bool) const override
+ {
+ return std::unique_ptr<BackendContext>(
+ new BackendContext{this, nullptr, nullptr, nullptr, nullptr});
+ }
+};
+
+//
+// Constants
+//
+
+const int OPERAND_ELEMS = 268203;
+const int OPERAND_SIZE = OPERAND_ELEMS * 4;
+const int OPERATION_SIZE = OPERAND_SIZE * 3;
+
+const std::string LINEAR("Linear");
+const std::string DATAFLOW("Dataflow");
+const std::string PARALLEL("Parallel");
+
+//
+// Helper functions
+//
+
+// Set executor through environment variable
+void setExecutor(const std::string &executor) { setenv("EXECUTOR", executor.c_str(), true); }
+
+// Set profiling mode through environment variable
+void setProfilingMode(const bool value) { setenv("PROFILING_MODE", value ? "1" : "0", true); }
+
+// Calculate operation size by addition sizes of all input and output operands
+uint32_t calcOpSize(const std::shared_ptr<Graph> &graph, const OperationIndex &op_idx)
+{
+ uint32_t size = 0;
+ const auto &op = graph->operations().at(op_idx);
+ for (const auto &ind : op.getInputs() + op.getOutputs())
+ size += graph->operands().at(ind).info().total_size();
+ return size;
+}
+
+// Set execution operation time. This method is needed since ExecutionTime has only
+// 'updateOperationExecTime' method.
+void setOperationExecTime(ExecTime &et, const Backend *backend, const std::string &operation,
+ bool quant, uint32_t op_size, int64_t time)
+{
+ // You shouldn't set negative time with this method since nnfw JSON deserializer can't read it
+ assert(time > 0);
+ int64_t prev_time = et.getOperationExecTime(backend, operation, quant, op_size);
+ int64_t time_to_set = prev_time == ExecTime::NOT_FOUND ? time : 2 * time - prev_time;
+ et.updateOperationExecTime(backend, operation, quant, op_size, time_to_set);
+ assert(et.getOperationExecTime(backend, operation, quant, op_size) == time);
+}
+
+// Set same execution time for all given backends/operations
+void setOperationsExecutionTime(const std::vector<const Backend *> &backends,
+ const std::vector<std::string> &op_names,
+ const std::vector<uint32_t> &op_sizes, int64_t exec_time)
+{
+ assert(op_names.size() == op_sizes.size());
+ ExecTime et(backends);
+ for (int i = 0; i < op_names.size(); ++i)
+ {
+ for (auto &backend : backends)
+ setOperationExecTime(et, backend, op_names[i], false, op_sizes[i], exec_time);
+ }
+ et.uploadOperationsExecTime();
+}
+
+// Set permute time from one backend to another. This method is needed since ExecutionTime has only
+// 'updatePermuteTime' method.
+void setPermutationTime(ExecTime &et, const Backend *from_backend, const Backend *to_backend,
+ bool quant, uint32_t op_size, int64_t time)
+{
+ // You shouldn't set negative time with this method since nnfw JSON deserializer can't read it
+ assert(time > 0);
+ int64_t prev_time = et.getPermuteTime(from_backend, to_backend, quant, op_size);
+ int64_t time_to_set = prev_time == ExecTime::NOT_FOUND ? time : 2 * time - prev_time;
+ et.updatePermuteTime(from_backend, to_backend, quant, op_size, time_to_set);
+ assert(et.getPermuteTime(from_backend, to_backend, quant, op_size) == time);
+}
+
+// Set same permutation time between all given backends
+void setPermutationsExecutionTime(const std::vector<const Backend *> &backends,
+ const int operand_size, const int64_t exec_time)
+{
+ ExecTime et(backends);
+ for (const auto &backend : backends)
+ {
+ for (auto &other_backend : backends)
+ {
+ if (backend == other_backend)
+ continue;
+ setPermutationTime(et, backend, other_backend, false, operand_size, exec_time);
+ }
+ }
+ et.uploadOperationsExecTime();
+}
+
+//
+// Functions for creating graphs
+//
+
+using OIS = OperandIndexSequence;
+
+template <typename NodeT, typename... Types>
+OperationIndex create(std::shared_ptr<Graph> graph, Types &&... args)
+{
+ auto op = std::make_unique<NodeT>(std::forward<Types>(args)...);
+ auto op_idx = graph->addOperation(std::move(op));
+ // For now in scheduler test all operations in tested graphs has same size (for simplicity)
+ assert(calcOpSize(graph, op_idx) == OPERATION_SIZE);
+ return op_idx;
+}
+
+// Create straight graph: Add->Sub->Mul
+std::shared_ptr<Graph> createStraightGraph()
+{
+ auto graph = std::make_shared<Graph>();
+ const TypeInfo float_op(DataType::FLOAT32);
+
+ // Create add node
+ auto add_lhs_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto add_rhs_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto add_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ BinaryArithmetic::Param add_op_params{BinaryArithmetic::ArithmeticType::ADD, Activation::NONE};
+ create<BinaryArithmetic>(graph, OIS{add_lhs_idx, add_rhs_idx}, OIS{add_out_idx}, add_op_params);
+
+ // Create sub node
+ auto sub_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto sub_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ BinaryArithmetic::Param sub_op_params{BinaryArithmetic::ArithmeticType::SUB, Activation::NONE};
+ create<BinaryArithmetic>(graph, OIS{add_out_idx, sub_const_idx}, OIS{sub_out_idx}, sub_op_params);
+
+ // Create mul node
+ auto mul_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto mul_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ BinaryArithmetic::Param mul_op_params{BinaryArithmetic::ArithmeticType::MUL, Activation::NONE};
+ create<BinaryArithmetic>(graph, OIS{sub_out_idx, mul_const_idx}, OIS{mul_out_idx}, mul_op_params);
+
+ graph->finishBuilding();
+ return graph;
+}
+
+/* Create branched graph:
+ * [Add]
+ * // \\
+ * [Mul1] [FC2]
+ * || ||
+ * [Mul2] [FC2]
+ * \\ //
+ * [Sub]
+ */
+std::shared_ptr<Graph> createBranchedGraph()
+{
+ auto graph = std::make_shared<Graph>();
+ const TypeInfo float_op(DataType::FLOAT32);
+
+ // Create add node
+ auto add_lhs_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto add_rhs_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto add_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ BinaryArithmetic::Param add_op_params{BinaryArithmetic::ArithmeticType::ADD, Activation::NONE};
+ create<BinaryArithmetic>(graph, OIS{add_lhs_idx, add_rhs_idx}, OIS{add_out_idx}, add_op_params);
+
+ // Create mul1 node
+ auto mul1_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto mul1_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ BinaryArithmetic::Param mul1_op_params{BinaryArithmetic::ArithmeticType::MUL, Activation::NONE};
+ create<BinaryArithmetic>(graph, OIS{add_out_idx, mul1_const_idx}, OIS{mul1_out_idx},
+ mul1_op_params);
+
+ // Create mul2 node
+ auto mul2_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto mul2_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ BinaryArithmetic::Param mul2_op_params{BinaryArithmetic::ArithmeticType::MUL, Activation::NONE};
+ create<BinaryArithmetic>(graph, OIS{mul1_out_idx, mul2_const_idx}, OIS{mul2_out_idx},
+ mul2_op_params);
+
+ // Create fc1 node
+ auto fc1_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto fc1_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ FullyConnected::Param fc1_op_params{Activation::NONE};
+ create<FullyConnected>(graph, OIS{add_out_idx, fc1_const_idx}, OIS{fc1_out_idx}, fc1_op_params);
+
+ // Create fc2 node
+ auto fc2_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ auto fc2_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ FullyConnected::Param fc2_op_params{Activation::NONE};
+ create<FullyConnected>(graph, OIS{fc1_out_idx, fc2_const_idx}, OIS{fc2_out_idx}, fc2_op_params);
+
+ // Create sub node
+ auto sub_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op);
+ BinaryArithmetic::Param sub_op_params{BinaryArithmetic::ArithmeticType::SUB, Activation::NONE};
+ create<BinaryArithmetic>(graph, OIS{mul2_out_idx, fc2_out_idx}, OIS{sub_out_idx}, sub_op_params);
+
+ graph->finishBuilding();
+ return graph;
+}
+
+//
+// Tests setup/teardown
+//
+
+// SetUp/TearDown methods runs before/after each test and performs actions common for each test
+class SchedulerTest : public ::testing::Test
+{
+protected:
+ void SetUp() override
+ {
+ // Initialize mock backends
+ _cpu_backend = new MockBackendCPU();
+ _gpu_backend = new MockBackendGPU();
+ _npu_backend = new MockBackendNPU();
+ _mock_backends = {_cpu_backend, _gpu_backend, _npu_backend};
+
+ // Remove previous profile data if it exists
+ if (!remove("exec_time.json"))
+ {
+ // DO NOTHING (no profile data)
+ }
+
+ // Remember original value of 'EXECUTOR' environment variable
+ char *executor = std::getenv("EXECUTOR");
+ _original_executor = executor == nullptr ? "" : executor;
+
+ // Remember original value of 'PROFILING_MODE' environment variable
+ char *profiling_mode = std::getenv("PROFILING_MODE");
+ _original_profiling_mode = profiling_mode == nullptr ? "" : profiling_mode;
+ }
+
+ void TearDown() override
+ {
+ delete _cpu_backend;
+ delete _gpu_backend;
+ delete _npu_backend;
+ EXPECT_EQ(remove("exec_time.json"), 0);
+ setenv("EXECUTOR", _original_executor.c_str(), true);
+ setenv("PROFILING_MODE", _original_profiling_mode.c_str(), true);
+ }
+
+ backend::BackendContexts buildBackendContexts(const Graph &graph)
+ {
+ backend::BackendContexts contexts;
+ for (auto backend : _mock_backends)
+ {
+ contexts.emplace(backend, backend->newContext(graph, nullptr, false));
+ }
+ return contexts;
+ }
+
+ const MockBackendCPU *_cpu_backend{nullptr};
+ const MockBackendGPU *_gpu_backend{nullptr};
+ const MockBackendNPU *_npu_backend{nullptr};
+ std::vector<const Backend *> _mock_backends;
+
+ std::string _original_executor;
+ std::string _original_profiling_mode;
+};
+
+class SchedulerTestWithExecutorParam : public SchedulerTest,
+ public testing::WithParamInterface<std::string>
+{
+};
+
+//
+// HEScheduler tests
+//
+
+// Test scheduler behavior for straight graph with known execution time of all nodes and permutes.
+TEST_P(SchedulerTestWithExecutorParam, straight_graph_known_exec_time)
+{
+ setExecutor(GetParam());
+
+ // Prepare graph
+ ir::Subgraphs subgs;
+ auto graph(createStraightGraph());
+ subgs.push(ir::SubgraphIndex{0}, graph);
+ OperationIndex add_op_idx(0), sub_op_idx(1), mul_op_idx(2);
+
+ // Set default execution and transfer time
+ setPermutationsExecutionTime(_mock_backends, OPERAND_SIZE, 1);
+ setOperationsExecutionTime(_mock_backends, {"Add", "Sub", "Mul"},
+ {OPERATION_SIZE, OPERATION_SIZE, OPERATION_SIZE}, 1e4);
+
+ // Test 1
+ // Expected behaviour: scheduler assigns different backend to each node
+ {
+ // For each backend reduce execution time of one node
+ ExecTime et(_mock_backends);
+ setOperationExecTime(et, _cpu_backend, "Add", false, OPERATION_SIZE, 1);
+ setOperationExecTime(et, _gpu_backend, "Sub", false, OPERATION_SIZE, 1);
+ setOperationExecTime(et, _npu_backend, "Mul", false, OPERATION_SIZE, 1);
+ et.uploadOperationsExecTime();
+
+ // Test scheduler
+ auto backend_contexts = buildBackendContexts(*graph);
+ auto scheduler = compiler::HEScheduler(backend_contexts,
+ compiler::fetchCompilerOptionsFromGlobalConfig(subgs));
+ const auto br = scheduler.schedule(*graph);
+ ASSERT_EQ(br->getBackend(add_op_idx)->config()->id(), "cpu");
+ ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "gpu");
+ ASSERT_EQ(br->getBackend(mul_op_idx)->config()->id(), "npu");
+ }
+
+ // Test 2
+ // Expected behaviour: scheduler assigns single backend to all nodes because of big transfer time
+ {
+ // Increase transfer time
+ setPermutationsExecutionTime(_mock_backends, OPERAND_SIZE, 1e5);
+
+ // Test scheduler
+ auto backend_contexts = buildBackendContexts(*graph);
+ auto scheduler = compiler::HEScheduler(backend_contexts,
+ compiler::fetchCompilerOptionsFromGlobalConfig(subgs));
+ const auto br = scheduler.schedule(*graph);
+ ASSERT_EQ(br->getBackend(add_op_idx)->config()->id(), "cpu");
+ ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "cpu");
+ ASSERT_EQ(br->getBackend(mul_op_idx)->config()->id(), "cpu");
+ }
+}
+
+// Test scheduler behavior for branched graph with known execution time of all nodes and permutes
+TEST_P(SchedulerTestWithExecutorParam, branched_graph_known_exec_time)
+{
+ const int64_t NPU_ET = 5000;
+ setExecutor(GetParam());
+
+ // Prepare graph
+ ir::Subgraphs subgs;
+ auto graph(createBranchedGraph());
+ subgs.push(ir::SubgraphIndex{0}, graph);
+ OperationIndex add_op_idx(0), mul1_op_idx(1), mul2_op_idx(2), fc1_op_idx(3), fc2_op_idx(4),
+ sub_op_idx(5);
+
+ // Set default execution and transfer time
+ setPermutationsExecutionTime(_mock_backends, OPERAND_SIZE, 1000);
+ setOperationsExecutionTime(_mock_backends, {"Add", "Sub", "Mul", "FullyConnected"},
+ {OPERATION_SIZE, OPERATION_SIZE, OPERATION_SIZE, OPERATION_SIZE}, 1e4);
+
+ // Test 1
+ // Expected behaviour: for dataflow and linear executors scheduler assigns fastest backend to all
+ // nodes, in case of parallel executor scheduler assigns different backends to branches.
+ {
+ // Reduce execution time
+ ExecTime et(_mock_backends);
+ setOperationExecTime(et, _npu_backend, "Add", false, OPERATION_SIZE, NPU_ET);
+ setOperationExecTime(et, _npu_backend, "Mul", false, OPERATION_SIZE, NPU_ET);
+ setOperationExecTime(et, _npu_backend, "Sub", false, OPERATION_SIZE, NPU_ET);
+ setOperationExecTime(et, _npu_backend, "FullyConnected", false, OPERATION_SIZE, NPU_ET);
+ setOperationExecTime(et, _gpu_backend, "Mul", false, OPERATION_SIZE, NPU_ET + 1000);
+ setOperationExecTime(et, _gpu_backend, "FullyConnected", false, OPERATION_SIZE, NPU_ET + 1000);
+ et.uploadOperationsExecTime();
+
+ // Test scheduler
+ auto backend_contexts = buildBackendContexts(*graph);
+ auto scheduler = compiler::HEScheduler(backend_contexts,
+ compiler::fetchCompilerOptionsFromGlobalConfig(subgs));
+ const auto br = scheduler.schedule(*graph);
+
+ std::string branch1_expected_backend("npu"), branch2_expected_backend("npu");
+ if (GetParam() == PARALLEL)
+ {
+ branch1_expected_backend =
+ br->getBackend(mul1_op_idx)->config()->id() == "npu" ? "npu" : "gpu";
+ branch2_expected_backend = branch1_expected_backend == "npu" ? "gpu" : "npu";
+ }
+
+ ASSERT_EQ(br->getBackend(add_op_idx)->config()->id(), "npu");
+ ASSERT_EQ(br->getBackend(mul1_op_idx)->config()->id(), branch1_expected_backend);
+ ASSERT_EQ(br->getBackend(mul2_op_idx)->config()->id(), branch1_expected_backend);
+ ASSERT_EQ(br->getBackend(fc1_op_idx)->config()->id(), branch2_expected_backend);
+ ASSERT_EQ(br->getBackend(fc2_op_idx)->config()->id(), branch2_expected_backend);
+ ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "npu");
+ }
+
+ // Test 2
+ // Expected behaviour: scheduler assigns single backend to all nodes
+ {
+ // Increase execution time for GPU backend
+ ExecTime et(_mock_backends);
+ /* for parallel executor: set a time, that is larger than sum_of_other_branches_nodes_cnt *
+ * npu_exec_time so that npu is prefered: the ith branch will wait for npu until it finishes the
+ * [0;i-1] branches nodes in DFS order. In each branch it goes deep intul doesn't encounter
+ * branching or scheduler assigns another backend to a node*/
+ setOperationExecTime(et, _gpu_backend, "Mul", false, OPERATION_SIZE, NPU_ET * 3 + 1);
+ setOperationExecTime(et, _gpu_backend, "FullyConnected", false, OPERATION_SIZE, NPU_ET * 3 + 1);
+ et.uploadOperationsExecTime();
+
+ // Test scheduler
+ auto backend_contexts = buildBackendContexts(*graph);
+ auto scheduler = compiler::HEScheduler(backend_contexts,
+ compiler::fetchCompilerOptionsFromGlobalConfig(subgs));
+ const auto br = scheduler.schedule(*graph);
+ ASSERT_EQ(br->getBackend(add_op_idx)->config()->id(), "npu");
+ ASSERT_EQ(br->getBackend(mul1_op_idx)->config()->id(), "npu");
+ ASSERT_EQ(br->getBackend(mul2_op_idx)->config()->id(), "npu");
+ ASSERT_EQ(br->getBackend(fc1_op_idx)->config()->id(), "npu");
+ ASSERT_EQ(br->getBackend(fc2_op_idx)->config()->id(), "npu");
+ ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "npu");
+ }
+}
+
+// SchedulerTestWithExecutorParam tests are parameterized with executor name and runs three times -
+// one time for each executor
+INSTANTIATE_TEST_CASE_P(AllExecutors, SchedulerTestWithExecutorParam,
+ testing::Values(LINEAR, DATAFLOW, PARALLEL));
+
+// Test scheduler behavior for branched graph and enabled profiling mode
+TEST_F(SchedulerTest, branched_graph_profiling_mode)
+{
+ const int ET = 1e5;
+
+ // Turn on profiling mode
+ setProfilingMode(true);
+ setExecutor(DATAFLOW);
+
+ // Prepare graph
+ ir::Subgraphs subgs;
+ auto graph(createBranchedGraph());
+ subgs.push(ir::SubgraphIndex{0}, graph);
+ OperationIndex add_op_idx(0), mul1_op_idx(1), mul2_op_idx(2), fc1_op_idx(3), fc2_op_idx(4),
+ sub_op_idx(5);
+
+ // Test 1
+ // Expected behaviour: scheduler assigns backends to nodes with unknown execution time
+ {
+ // Set execution time for all backends/nodes except for cpu/Sub, npu/Mul, gpu/FC
+ ExecTime et(_mock_backends);
+ setOperationExecTime(et, _cpu_backend, "Add", false, OPERATION_SIZE, ET);
+ setOperationExecTime(et, _cpu_backend, "Mul", false, OPERATION_SIZE, ET + 1);
+ setOperationExecTime(et, _cpu_backend, "FullyConnected", false, OPERATION_SIZE, ET);
+ setOperationExecTime(et, _npu_backend, "Add", false, OPERATION_SIZE, ET);
+ setOperationExecTime(et, _npu_backend, "FullyConnected", false, OPERATION_SIZE, ET);
+ setOperationExecTime(et, _npu_backend, "Sub", false, OPERATION_SIZE, ET);
+ setOperationExecTime(et, _gpu_backend, "Add", false, OPERATION_SIZE, ET);
+ setOperationExecTime(et, _gpu_backend, "Mul", false, OPERATION_SIZE, ET + 1);
+ setOperationExecTime(et, _gpu_backend, "Sub", false, OPERATION_SIZE, ET);
+ et.uploadOperationsExecTime();
+
+ // Test scheduler
+ auto backend_contexts = buildBackendContexts(*graph);
+ auto scheduler = compiler::HEScheduler(backend_contexts,
+ compiler::fetchCompilerOptionsFromGlobalConfig(subgs));
+ const auto br = scheduler.schedule(*graph);
+ ASSERT_EQ(br->getBackend(mul1_op_idx)->config()->id(), "npu");
+ ASSERT_EQ(br->getBackend(mul2_op_idx)->config()->id(), "npu");
+ ASSERT_EQ(br->getBackend(fc1_op_idx)->config()->id(), "gpu");
+ ASSERT_EQ(br->getBackend(fc2_op_idx)->config()->id(), "gpu");
+ ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "cpu");
+ }
+
+ // Test 2
+ // Expected behaviour: scheduler shuffling backends, so different backends are assigned to
+ // neighbor nodes
+ {
+ // Set execution time for rest backends/nodes (cpu/Sub, npu/Mul, gpu/FC)
+ ExecTime et(_mock_backends);
+ setOperationExecTime(et, _cpu_backend, "Sub", false, OPERATION_SIZE, ET);
+ setOperationExecTime(et, _npu_backend, "Mul", false, OPERATION_SIZE, ET + 1);
+ setOperationExecTime(et, _gpu_backend, "FullyConnected", false, OPERATION_SIZE, ET);
+ et.uploadOperationsExecTime();
+
+ // Test scheduler
+ auto backend_contexts = buildBackendContexts(*graph);
+ auto scheduler = compiler::HEScheduler(backend_contexts,
+ compiler::fetchCompilerOptionsFromGlobalConfig(subgs));
+ const auto br = scheduler.schedule(*graph);
+ ASSERT_NE(br->getBackend(add_op_idx)->config()->id(),
+ br->getBackend(mul1_op_idx)->config()->id());
+ ASSERT_NE(br->getBackend(add_op_idx)->config()->id(),
+ br->getBackend(fc1_op_idx)->config()->id());
+ ASSERT_NE(br->getBackend(mul1_op_idx)->config()->id(),
+ br->getBackend(mul2_op_idx)->config()->id());
+ ASSERT_NE(br->getBackend(fc1_op_idx)->config()->id(),
+ br->getBackend(fc2_op_idx)->config()->id());
+ ASSERT_NE(br->getBackend(mul2_op_idx)->config()->id(),
+ br->getBackend(sub_op_idx)->config()->id());
+ ASSERT_NE(br->getBackend(fc2_op_idx)->config()->id(),
+ br->getBackend(sub_op_idx)->config()->id());
+ }
+}
+
+// TODO: Add tests with unknown execution and permutation time
+
+} // unnamed namespace
diff --git a/runtime/onert/test/core/exec/ExecInstance.cc b/runtime/onert/test/core/exec/ExecInstance.cc
new file mode 100644
index 000000000..806b47ecc
--- /dev/null
+++ b/runtime/onert/test/core/exec/ExecInstance.cc
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <thread>
+
+#include "ir/Graph.h"
+#include "compiler/Compiler.h"
+#include "exec/Execution.h"
+#include "ir/operation/BinaryArithmetic.h"
+
+namespace
+{
+
+using namespace onert::ir;
+
+class CompiledMockUpModel
+{
+public:
+ CompiledMockUpModel()
+ {
+ // Model: two elementwise add operation
+ // model input: lhs, rhs1
+ // model output: second add result (result2)
+ // constant: rhs2
+ // result1 <= (lhs + rhs)
+ // result2 <= (result1 + rhs2)
+ // lhs, rhs1, rh2, result1, result2 shape: {1, 2, 2, 1}
+ // activation: none (constant)
+ graph = std::make_shared<Graph>();
+ // 1st add operands (result1 <= lhs + rhs1)
+ Shape shape{1, 2, 2, 1};
+ TypeInfo type{DataType::FLOAT32};
+ static float rhs2_data[4] = {3, 1, -1, 5};
+ auto operand_lhs = graph->addOperand(shape, type);
+ auto operand_rhs1 = graph->addOperand(shape, type);
+ auto operand_result1 = graph->addOperand(shape, type);
+ auto operand_rhs2 = graph->addOperand(shape, type);
+ auto operand_result2 = graph->addOperand(shape, type);
+ graph->operands()
+ .at(operand_rhs2)
+ .data(std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(&rhs2_data), 16));
+ // 2nd add operations (result2 <= result1 + rhs2)
+ operation::BinaryArithmetic::Param param1;
+ param1.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
+ param1.activation = Activation::NONE;
+ auto input_set1 = OperandIndexSequence{operand_lhs, operand_rhs1};
+ auto output_set1 = OperandIndexSequence{operand_result1};
+ graph->addOperation(
+ std::make_unique<operation::BinaryArithmetic>(input_set1, output_set1, param1));
+ operation::BinaryArithmetic::Param param2;
+ param2.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
+ param2.activation = Activation::NONE;
+ auto input_set2 = OperandIndexSequence{operand_result1, operand_rhs2};
+ auto output_set2 = OperandIndexSequence{operand_result2};
+ graph->addOperation(
+ std::make_unique<operation::BinaryArithmetic>(input_set2, output_set2, param2));
+ // Identify model inputs and outputs
+ graph->addInput(operand_lhs);
+ graph->addInput(operand_rhs1);
+ graph->addOutput(operand_result2);
+ graph->finishBuilding();
+
+ // Compile
+ auto subgs = std::make_shared<onert::ir::Subgraphs>();
+ subgs->push(onert::ir::SubgraphIndex{0}, graph);
+ onert::compiler::Compiler compiler{subgs};
+ executors = compiler.compile();
+ }
+
+public:
+ std::shared_ptr<Graph> graph;
+ std::shared_ptr<onert::exec::ExecutorMap> executors;
+};
+
+TEST(ExecInstance, simple)
+{
+ auto mockup = CompiledMockUpModel();
+ auto graph = mockup.graph;
+ auto executors = mockup.executors;
+
+ auto input1 = IOIndex{0};
+ auto input2 = IOIndex{1};
+ auto output = IOIndex{0};
+
+ const float input1_buffer[4] = {1, 0, -1, -2};
+ const float input2_buffer[4] = {1, -3, 2, -4};
+ float output_buffer[4] = {};
+ const float output_expected[4] = {5, -2, 0, -1};
+
+ onert::exec::Execution execution{executors};
+
+ execution.setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16);
+ execution.setInput(input2, reinterpret_cast<const void *>(input2_buffer), 16);
+ execution.setOutput(output, reinterpret_cast<void *>(output_buffer), 16);
+ execution.execute();
+
+ for (auto i = 0; i < 4; i++)
+ {
+ EXPECT_EQ(output_buffer[i], output_expected[i]);
+ }
+}
+
+TEST(ExecInstance, twoCompile)
+{
+ auto mockup = CompiledMockUpModel();
+ auto graph = mockup.graph;
+ auto executors1 = mockup.executors;
+ onert::exec::Execution execution1{executors1};
+
+ auto input1 = IOIndex{0};
+ auto input2 = IOIndex{1};
+ auto output = IOIndex{0};
+
+ const float exe1_input1_buffer[4] = {1, 0, -1, -2};
+ const float exe1_input2_buffer[4] = {1, -3, 2, -4};
+ float exe1_output_buffer[4] = {};
+ const float exe1_output_expected[4] = {5, -2, 0, -1};
+
+ execution1.setInput(input1, reinterpret_cast<const void *>(exe1_input1_buffer), 16);
+ execution1.setInput(input2, reinterpret_cast<const void *>(exe1_input2_buffer), 16);
+ execution1.setOutput(output, reinterpret_cast<void *>(exe1_output_buffer), 16);
+
+ // Make new executor: compile again
+ auto subgs = std::make_shared<onert::ir::Subgraphs>();
+ subgs->push(onert::ir::SubgraphIndex{0}, graph);
+ onert::compiler::Compiler compiler{subgs};
+ std::shared_ptr<onert::exec::ExecutorMap> executors2 = compiler.compile();
+ onert::exec::Execution execution2{executors2};
+
+ const float exe2_input1_buffer[4] = {2, 1, -2, 0};
+ const float exe2_input2_buffer[4] = {-3, 3, 1, 2};
+ float exe2_output_buffer[4] = {};
+ const float exe2_output_expected[4] = {2, 5, -2, 7};
+
+ execution2.setInput(input1, reinterpret_cast<const void *>(exe2_input1_buffer), 16);
+ execution2.setInput(input2, reinterpret_cast<const void *>(exe2_input2_buffer), 16);
+ execution2.setOutput(output, reinterpret_cast<void *>(exe2_output_buffer), 16);
+
+ execution1.execute();
+ execution2.execute();
+
+ for (auto i = 0; i < 4; i++)
+ {
+ EXPECT_EQ(exe1_output_buffer[i], exe1_output_expected[i]);
+ EXPECT_EQ(exe2_output_buffer[i], exe2_output_expected[i]);
+ }
+}
+
+// Support two initialized execution instance then ordered execution
+TEST(ExecInstance, twoExecution)
+{
+ auto mockup = CompiledMockUpModel();
+ auto executors = mockup.executors;
+ auto input1 = IOIndex{0};
+ auto input2 = IOIndex{1};
+ auto output1 = IOIndex{0};
+
+ const float exe1_input1_buffer[4] = {1, 0, -1, -2};
+ const float exe1_input2_buffer[4] = {1, -3, 2, -4};
+ float exe1_output_buffer[4] = {};
+ const float exe1_output_expected[4] = {5, -2, 0, -1};
+ const float exe2_output_expected[4] = {2, 5, -2, 7};
+
+ onert::exec::Execution execution1{executors};
+ execution1.setInput(input1, reinterpret_cast<const void *>(exe1_input1_buffer), 16);
+ execution1.setInput(input2, reinterpret_cast<const void *>(exe1_input2_buffer), 16);
+ execution1.setOutput(output1, reinterpret_cast<void *>(exe1_output_buffer), 16);
+
+ const float exe2_input1_buffer[4] = {2, 1, -2, 0};
+ const float exe2_input2_buffer[4] = {-3, 3, 1, 2};
+ float exe2_output_buffer[4] = {};
+
+ // Make new execution
+ onert::exec::Execution execution2{executors};
+ execution2.setInput(input1, reinterpret_cast<const void *>(exe2_input1_buffer), 16);
+ execution2.setInput(input2, reinterpret_cast<const void *>(exe2_input2_buffer), 16);
+ execution2.setOutput(output1, reinterpret_cast<void *>(exe2_output_buffer), 16);
+
+ execution1.execute();
+ execution2.execute();
+
+ for (auto i = 0; i < 4; i++)
+ {
+ EXPECT_EQ(exe1_output_buffer[i], exe1_output_expected[i]);
+ EXPECT_EQ(exe2_output_buffer[i], exe2_output_expected[i]);
+ }
+}
+
+class Inference
+{
+public:
+ Inference(const float (&input1)[4], const float (&input2)[4], float (&output)[4],
+ std::shared_ptr<onert::exec::ExecutorMap> &executors)
+ : _input1{input1}, _input2{input2}, _output{output}, _executors{executors}
+ {
+ // DO NOTHING
+ }
+
+ void inference(void)
+ {
+ auto input1 = IOIndex{0};
+ auto input2 = IOIndex{1};
+ auto output1 = IOIndex{0};
+
+ onert::exec::Execution execution{_executors};
+ execution.setInput(input1, reinterpret_cast<const void *>(_input1), 16);
+ execution.setInput(input2, reinterpret_cast<const void *>(_input2), 16);
+ execution.setOutput(output1, reinterpret_cast<void *>(_output), 16);
+
+ execution.execute();
+ }
+
+private:
+ const float (&_input1)[4];
+ const float (&_input2)[4];
+ float (&_output)[4];
+ std::shared_ptr<onert::exec::ExecutorMap> &_executors;
+};
+
+// Support multi-thread execution
+TEST(ExecInstance, twoThreads)
+{
+ auto mockup = CompiledMockUpModel();
+ auto executors = mockup.executors;
+
+ const float exe1_input1_buffer[4] = {1, 0, -1, -2};
+ const float exe1_input2_buffer[4] = {1, -3, 2, -4};
+ float exe1_output_buffer[4] = {};
+ const float exe1_output_expected[4] = {5, -2, 0, -1};
+
+ Inference execution1{exe1_input1_buffer, exe1_input2_buffer, exe1_output_buffer, executors};
+
+ const float exe2_input1_buffer[4] = {2, 1, -2, 0};
+ const float exe2_input2_buffer[4] = {-3, 3, 1, 2};
+ float exe2_output_buffer[4] = {};
+ const float exe2_output_expected[4] = {2, 5, -2, 7};
+
+ Inference execution2{exe2_input1_buffer, exe2_input2_buffer, exe2_output_buffer, executors};
+
+ std::thread t1{&Inference::inference, &execution1};
+ std::thread t2{&Inference::inference, &execution2};
+
+ t1.join();
+ t2.join();
+
+ for (auto i = 0; i < 4; i++)
+ {
+ EXPECT_EQ(exe1_output_buffer[i], exe1_output_expected[i]);
+ EXPECT_EQ(exe2_output_buffer[i], exe2_output_expected[i]);
+ }
+}
+
+// Support asynchronous execution
+TEST(ExecInstance, async)
+{
+ auto mockup = CompiledMockUpModel();
+ auto graph = mockup.graph;
+ auto executors = mockup.executors;
+
+ auto input1 = IOIndex{0};
+ auto input2 = IOIndex{1};
+ auto output = IOIndex{0};
+
+ const float input1_buffer[4] = {1, 0, -1, -2};
+ const float input2_buffer[4] = {1, -3, 2, -4};
+ float output_buffer[4] = {};
+ const float output_expected[4] = {5, -2, 0, -1};
+
+ onert::exec::Execution execution{executors};
+
+ execution.setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16);
+ execution.setInput(input2, reinterpret_cast<const void *>(input2_buffer), 16);
+ execution.setOutput(output, reinterpret_cast<void *>(output_buffer), 16);
+ execution.startExecute();
+ execution.waitFinish();
+
+ for (auto i = 0; i < 4; i++)
+ {
+ EXPECT_EQ(output_buffer[i], output_expected[i]);
+ }
+}
+
+} // namespace
diff --git a/runtime/onert/test/core/exec/ExecTime.test.cc b/runtime/onert/test/core/exec/ExecTime.test.cc
new file mode 100644
index 000000000..8c2e34df8
--- /dev/null
+++ b/runtime/onert/test/core/exec/ExecTime.test.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "exec/ExecTime.h"
+#include "backend/IConfig.h"
+#include "backend/Backend.h"
+#include <gtest/gtest.h>
+#include <string>
+
+namespace
+{
+using namespace onert;
+using namespace exec;
+using namespace backend;
+
+struct MockConfig : public IConfig
+{
+ std::string id() override { return "b1"; }
+ bool initialize() override { return true; };
+ bool supportPermutation() override { return false; }
+ ir::Layout supportLayout(const ir::Operation &, ir::Layout) override
+ {
+ return ir::Layout::UNKNOWN;
+ }
+ bool supportDynamicTensor() override { return false; }
+ bool supportFP16() override { return false; }
+};
+
+struct MockBackend : public ::onert::backend::Backend
+{
+ std::shared_ptr<onert::backend::IConfig> config() const override
+ {
+ return std::make_shared<MockConfig>();
+ }
+ std::unique_ptr<BackendContext> newContext(const ir::Graph &,
+ const std::shared_ptr<custom::IKernelBuilder> &kb,
+ bool) const override
+ {
+ return nullptr;
+ }
+};
+
+TEST(ExecTime, roundtrip_ok)
+{
+ const auto *b = new MockBackend();
+ std::vector<const Backend *> bs = {b};
+ {
+ ExecTime et(bs);
+ et.updateOperationExecTime(b, "op1", true, 100, 100);
+ et.updateOperationExecTime(b, "op1", true, 200, 200);
+ et.updateOperationExecTime(b, "op1", false, 100, 888);
+ et.uploadOperationsExecTime();
+ }
+ {
+ ExecTime et(bs);
+ auto time = et.getOperationExecTime(b, "op1", true, 100);
+ ASSERT_EQ(time, 100);
+ // Check interpolation
+ time = et.getOperationExecTime(b, "op1", true, 150);
+ ASSERT_EQ(time, 150);
+ time = et.getOperationExecTime(b, "op1", false, 100);
+ ASSERT_EQ(time, 888);
+ et.uploadOperationsExecTime();
+ }
+ // clean up
+ EXPECT_EQ(remove("exec_time.json"), 0);
+}
+
+TEST(ExecTime, structure)
+{
+
+ const auto *b = new MockBackend();
+ std::vector<const Backend *> bs = {b};
+ {
+ ExecTime et(bs);
+ et.updateOperationExecTime(b, "op1", true, 100, 100);
+ et.updateOperationExecTime(b, "op1", true, 200, 200);
+ et.uploadOperationsExecTime();
+ }
+ {
+ ExecTime et(bs);
+ auto time = et.getOperationExecTime(b, "op1", true, 100);
+ ASSERT_EQ(time, 100);
+ // Check interpolation
+ time = et.getOperationExecTime(b, "op1", true, 200);
+ ASSERT_EQ(time, 200);
+ et.uploadOperationsExecTime();
+ }
+ // clean up
+ EXPECT_EQ(remove("exec_time.json"), 0);
+}
+} // unnamed namespace
diff --git a/runtime/onert/test/core/interp/ExecManager.cc b/runtime/onert/test/core/interp/ExecManager.cc
new file mode 100644
index 000000000..0c7b1b762
--- /dev/null
+++ b/runtime/onert/test/core/interp/ExecManager.cc
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <memory>
+
+#include "ir/Graph.h"
+#include "interp/InterpExecutor.h"
+#include "exec/Execution.h"
+#include "ir/operation/BinaryArithmetic.h"
+
+namespace
+{
+
+using namespace onert::ir;
+using InterpExecutor = onert::interp::InterpExecutor;
+using Execution = onert::exec::Execution;
+using ExecutorMap = onert::exec::ExecutorMap;
+
+class InterpExecutorTest : public ::testing::Test
+{
+protected:
+ virtual void SetUp() {}
+ void CreateSimpleModel()
+ {
+ // Model: one elementwise add operation
+ // model input: lhs, rhs
+ // model output: add result
+ // lhs, rhs, result shape: {1, 2, 2, 1}
+ // activation: none (constant)
+ _graph = std::make_unique<Graph>();
+
+ // Add operands
+
+ Shape shape{1, 2, 2, 1};
+ TypeInfo type{DataType::INT32};
+ Shape shape_scalar(0);
+ TypeInfo type_scalar{DataType::INT32};
+
+ auto operand_lhs = _graph->addOperand(shape, type);
+ auto operand_rhs = _graph->addOperand(shape, type);
+ auto operand_result = _graph->addOperand(shape, type);
+
+ // Add operations
+
+ operation::BinaryArithmetic::Param param;
+ param.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
+ param.activation = Activation::NONE;
+ auto input_set = OperandIndexSequence{operand_lhs, operand_rhs};
+ auto output_set = OperandIndexSequence{operand_result};
+ _graph->addOperation(
+ std::make_unique<operation::BinaryArithmetic>(input_set, output_set, param));
+
+ // Identify model inputs and outputs
+
+ _graph->getInputs().append(operand_lhs);
+ _graph->getInputs().append(operand_rhs);
+ _graph->getOutputs().append(operand_result);
+
+ _graph->finishBuilding();
+
+ auto subgs = std::make_shared<onert::ir::Subgraphs>();
+ subgs->push(onert::ir::SubgraphIndex{0}, _graph);
+ _graph->setSubgraphs(subgs);
+
+ _executors = std::make_shared<ExecutorMap>();
+ _executors->insert(
+ std::make_pair(onert::ir::SubgraphIndex{0}, std::make_unique<InterpExecutor>(*_graph)));
+ }
+
+ void CreateTwoStepModel()
+ {
+ // Model: two elementwise add operation
+ // model input: lhs, rhs1
+ // model output: second add result (result2)
+ // constant: rhs2
+ // result1 <= (lhs + rhs)
+ // result2 <= (result1 + rhs2)
+ // lhs, rhs1, rh2, result1, result2 shape: {1, 2, 2, 1}
+ // activation: none (constant)
+ _graph = std::make_unique<Graph>();
+
+ // 1st add operands (result1 <= lhs + rhs1)
+
+ Shape shape{1, 2, 2, 1};
+ TypeInfo type{DataType::INT32};
+ Shape shape_scalar(0);
+ TypeInfo type_scalar{DataType::INT32};
+
+ static int32_t rhs2_data[4] = {3, 1, -1, 5};
+
+ auto operand_lhs = _graph->addOperand(shape, type);
+ auto operand_rhs1 = _graph->addOperand(shape, type);
+ auto operand_result1 = _graph->addOperand(shape, type);
+ auto operand_rhs2 = _graph->addOperand(shape, type);
+ auto operand_result2 = _graph->addOperand(shape, type);
+ _graph->operands()
+ .at(operand_rhs2)
+ .data(std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(&rhs2_data), 16));
+
+ // 2nd add operations (result2 <= result1 + rhs2)
+
+ operation::BinaryArithmetic::Param param1;
+ param1.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
+ param1.activation = Activation::NONE;
+ auto input_set1 = OperandIndexSequence{operand_lhs, operand_rhs1};
+ auto output_set1 = OperandIndexSequence{operand_result1};
+ _graph->addOperation(
+ std::make_unique<operation::BinaryArithmetic>(input_set1, output_set1, param1));
+
+ operation::BinaryArithmetic::Param param2;
+ param2.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
+ param2.activation = Activation::NONE;
+ auto input_set2 = OperandIndexSequence{operand_result1, operand_rhs2};
+ auto output_set2 = OperandIndexSequence{operand_result2};
+ _graph->addOperation(
+ std::make_unique<operation::BinaryArithmetic>(input_set2, output_set2, param2));
+
+ // Identify model inputs and outputs
+
+ _graph->getInputs().append(operand_lhs);
+ _graph->getInputs().append(operand_rhs1);
+ _graph->getOutputs().append(operand_result2);
+
+ _graph->finishBuilding();
+
+ auto subgs = std::make_shared<onert::ir::Subgraphs>();
+ subgs->push(onert::ir::SubgraphIndex{0}, _graph);
+ _graph->setSubgraphs(subgs);
+
+ _executors = std::make_shared<ExecutorMap>();
+ _executors->insert(
+ std::make_pair(onert::ir::SubgraphIndex{0}, std::make_unique<InterpExecutor>(*_graph)));
+ }
+
+ void CreateUnspecifiedDimensionsModel()
+ {
+ // Model: one elementwise add operation
+ // model input: lhs, rhs
+ // model output: add result
+ // lhs, rhs, result shape: {1, unknown, 2, 1}
+ // activation: none (constant)
+ _graph = std::make_unique<Graph>();
+
+ // Add operands
+
+ Shape shape{1, 0, 2, 1};
+ TypeInfo type{DataType::INT32};
+ Shape shape_scalar(0);
+ TypeInfo type_scalar{DataType::INT32};
+
+ auto operand_lhs = _graph->addOperand(shape, type);
+ auto operand_rhs = _graph->addOperand(shape, type);
+
+ auto operand_activation = _graph->addOperand(shape_scalar, type_scalar);
+ _graph->operands()
+ .at(operand_activation)
+ .data(
+ std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(&_activation_value), 4));
+
+ auto operand_result = _graph->addOperand(shape, type);
+
+ // Add operations
+
+ operation::BinaryArithmetic::Param param;
+ param.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
+ param.activation = Activation::NONE;
+ auto input_set = OperandIndexSequence{operand_lhs, operand_rhs};
+ auto output_set = OperandIndexSequence{operand_result};
+ _graph->addOperation(
+ std::make_unique<operation::BinaryArithmetic>(input_set, output_set, param));
+
+ // Identify model inputs and outputs
+
+ _graph->getInputs().append(operand_lhs);
+ _graph->getInputs().append(operand_rhs);
+ _graph->getOutputs().append(operand_result);
+
+ _graph->finishBuilding();
+
+ auto subgs = std::make_shared<onert::ir::Subgraphs>();
+ subgs->push(onert::ir::SubgraphIndex{0}, _graph);
+ _graph->setSubgraphs(subgs);
+
+ _executors = std::make_shared<ExecutorMap>();
+ _executors->insert(
+ std::make_pair(onert::ir::SubgraphIndex{0}, std::make_unique<InterpExecutor>(*_graph)));
+ }
+
+ void createExecution() { _execution = std::make_unique<Execution>(_executors); }
+
+ virtual void TearDown() { _executors = nullptr; }
+
+ std::shared_ptr<Graph> _graph{nullptr};
+ std::shared_ptr<ExecutorMap> _executors{nullptr};
+ std::unique_ptr<Execution> _execution{nullptr};
+ const int32_t _activation_value{0};
+};
+
+TEST_F(InterpExecutorTest, create_empty)
+{
+ Graph graph;
+ graph.finishBuilding();
+ auto executor = std::make_unique<InterpExecutor>(graph);
+ ASSERT_NE(executor, nullptr);
+}
+
+TEST_F(InterpExecutorTest, create_simple)
+{
+ CreateSimpleModel();
+ ASSERT_NE(_executors, nullptr);
+ ASSERT_NE(_executors->at(onert::ir::SubgraphIndex{0}), nullptr);
+}
+
+TEST_F(InterpExecutorTest, neg_setInput)
+{
+ CreateSimpleModel();
+ createExecution();
+
+ auto input1 = IOIndex{0};
+ const int32_t input1_buffer[4] = {1, 0, -1, -2};
+
+ EXPECT_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 4),
+ std::runtime_error);
+ EXPECT_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 12),
+ std::runtime_error);
+ EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
+}
+
+TEST_F(InterpExecutorTest, neg_setOutput)
+{
+ CreateSimpleModel();
+ createExecution();
+
+ auto output = IOIndex{0};
+ auto output_idx = _graph->getOutputs().at(output);
+
+ int32_t output_buffer[4] = {};
+
+ EXPECT_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 4),
+ std::runtime_error);
+ EXPECT_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 12),
+ std::runtime_error);
+ EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
+}
+
+TEST_F(InterpExecutorTest, neg_setInputForUnspecifiedDimensions)
+{
+ CreateUnspecifiedDimensionsModel();
+ createExecution();
+
+ auto input1 = IOIndex{0};
+ const int32_t input1_buffer[4] = {1, 0, -1, -2};
+
+ TypeInfo operand_type{DataType::INT32};
+ Shape operand_shape{1, 2, 2, 1};
+
+ EXPECT_THROW(_execution->setInput(input1, operand_type, operand_shape,
+ reinterpret_cast<const void *>(input1_buffer), 4),
+ std::runtime_error);
+ EXPECT_THROW(_execution->setInput(input1, operand_type, operand_shape,
+ reinterpret_cast<const void *>(input1_buffer), 12),
+ std::runtime_error);
+ EXPECT_NO_THROW(_execution->setInput(input1, operand_type, operand_shape,
+ reinterpret_cast<const void *>(input1_buffer), 16));
+}
+
+TEST_F(InterpExecutorTest, neg_setOutputForUnspecifiedDimensions)
+{
+ CreateUnspecifiedDimensionsModel();
+ createExecution();
+
+ auto output = IOIndex{0};
+ auto output_idx = _graph->getOutputs().at(output);
+
+ TypeInfo operand_type{DataType::INT32};
+ Shape operand_shape{1, 2, 2, 1};
+
+ int32_t output_buffer[4] = {};
+
+ EXPECT_THROW(_execution->setOutput(output, operand_type, operand_shape,
+ reinterpret_cast<void *>(output_buffer), 4),
+ std::runtime_error);
+ EXPECT_THROW(_execution->setOutput(output, operand_type, operand_shape,
+ reinterpret_cast<void *>(output_buffer), 12),
+ std::runtime_error);
+ EXPECT_NO_THROW(_execution->setOutput(output, operand_type, operand_shape,
+ reinterpret_cast<void *>(output_buffer), 16));
+}
+
+TEST_F(InterpExecutorTest, execute)
+{
+ CreateSimpleModel();
+ createExecution();
+
+ auto input1 = IOIndex{0};
+ auto input2 = IOIndex{1};
+ auto input1_idx = _graph->getInputs().at(input1);
+ auto input2_idx = _graph->getInputs().at(input2);
+
+ const int32_t input1_buffer[4] = {1, 0, -1, -2};
+ const int32_t input2_buffer[4] = {1, -3, 2, -4};
+
+ auto output = IOIndex{0};
+ auto output_idx = _graph->getOutputs().at(output);
+
+ int32_t output_buffer[4] = {};
+
+ EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
+ EXPECT_NO_THROW(_execution->setInput(input2, reinterpret_cast<const void *>(input2_buffer), 16));
+ EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
+ EXPECT_NO_THROW(_execution->execute());
+ EXPECT_EQ(output_buffer[0], 2);
+ EXPECT_EQ(output_buffer[1], -3);
+ EXPECT_EQ(output_buffer[2], 1);
+ EXPECT_EQ(output_buffer[3], -6);
+}
+
+TEST_F(InterpExecutorTest, executeTwoStep)
+{
+ CreateTwoStepModel();
+ createExecution();
+
+ auto input1 = IOIndex{0};
+ auto input2 = IOIndex{1};
+ auto input1_idx = _graph->getInputs().at(input1);
+ auto input2_idx = _graph->getInputs().at(input2);
+
+ const int32_t input1_buffer[4] = {1, 0, -1, -2};
+ const int32_t input2_buffer[4] = {1, -3, 2, -4};
+
+ auto output = IOIndex{0};
+ auto output_idx = _graph->getOutputs().at(output);
+
+ int32_t output_buffer[4] = {};
+
+ EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast<const void *>(input1_buffer), 16));
+ EXPECT_NO_THROW(_execution->setInput(input2, reinterpret_cast<const void *>(input2_buffer), 16));
+ EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast<void *>(output_buffer), 16));
+ EXPECT_NO_THROW(_execution->execute());
+ EXPECT_EQ(output_buffer[0], 5);
+ EXPECT_EQ(output_buffer[1], -2);
+ EXPECT_EQ(output_buffer[2], 0);
+ EXPECT_EQ(output_buffer[3], -1);
+}
+
+} // namespace
diff --git a/runtime/onert/test/graph/Graph.cc b/runtime/onert/test/graph/Graph.cc
new file mode 100644
index 000000000..6461a0821
--- /dev/null
+++ b/runtime/onert/test/graph/Graph.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ir/Graph.h"
+#include "ir/operation/BinaryArithmetic.h"
+#include "ir/verifier/Verifier.h"
+
+TEST(Graph, neg_inputs_and_outputs)
+{
+ onert::ir::Graph graph;
+
+ onert::ir::OperandIndex index0{0u};
+ onert::ir::OperandIndex index1{1u};
+
+ graph.addInput({index0});
+ graph.addInput({index1});
+
+ onert::ir::OperandIndex index10{10u};
+ onert::ir::OperandIndex index11{11u};
+ onert::ir::OperandIndex index12{12u};
+
+ graph.addOutput({index10});
+ graph.addOutput({index11});
+ graph.addOutput({index12});
+
+ ASSERT_EQ(graph.getInputs().size(), 2);
+ ASSERT_EQ(graph.getOutputs().size(), 3);
+
+ onert::ir::IOIndex io_index0{0};
+ onert::ir::IOIndex io_index1{1};
+ onert::ir::IOIndex io_index2{2};
+
+ ASSERT_EQ(graph.getInputs().at(io_index0), 0);
+ ASSERT_EQ(graph.getInputs().at(io_index1), 1);
+
+ ASSERT_EQ(graph.getOutputs().at(io_index0), 10);
+ ASSERT_EQ(graph.getOutputs().at(io_index1), 11);
+ ASSERT_EQ(graph.getOutputs().at(io_index2), 12);
+
+ EXPECT_THROW(graph.getOutputs().at(onert::ir::IOIndex{3}), std::out_of_range);
+}
+
+using namespace onert::ir;
+
+OperationIndex addAddOperation(Graph &graph, const OperandIndexSequence inputs,
+ const OperandIndexSequence outputs)
+{
+ // Add "ADD" operation
+ operation::BinaryArithmetic::Param param;
+ param.arithmetic_type = operation::BinaryArithmetic::ArithmeticType::ADD;
+ param.activation = Activation::NONE;
+ return graph.addOperation(std::make_unique<operation::BinaryArithmetic>(inputs, outputs, param));
+}
+
+TEST(Graph, OneOpGraphFinish)
+{
+ // Simple Graph with just one Add operation
+
+ Graph graph;
+
+ // Add tensors
+ Shape shape{1, 2, 2, 1};
+ TypeInfo type{DataType::FLOAT32};
+ auto lhs = graph.addOperand(shape, type);
+ auto rhs = graph.addOperand(shape, type);
+ auto res = graph.addOperand(shape, type);
+
+ addAddOperation(graph, {lhs, rhs}, {res});
+
+ // Set model inputs/outputs
+ graph.addInput(lhs);
+ graph.addInput(rhs);
+ graph.addOutput(res);
+
+ graph.finishBuilding();
+
+ SUCCEED();
+}
+
+TEST(Graph, neg_InvalidGraphFinish_BadInput)
+{
+ Graph graph;
+
+ // Add tensors
+ Shape shape{1, 2, 2, 1};
+ TypeInfo type{DataType::FLOAT32};
+ auto in = graph.addOperand(shape, type);
+ auto out = graph.addOperand(shape, type);
+
+ // Set model inputs/outputs
+ graph.addInput(in);
+ graph.addOutput(out);
+ graph.addInput(OperandIndex{89}); // Non-exisiting operand!
+
+ EXPECT_ANY_THROW(graph.finishBuilding());
+}
+
+TEST(Graph, neg_InvalidGraphFinish_BadOutput)
+{
+ Graph graph;
+
+ // Add tensors
+ Shape shape{1, 2, 2, 1};
+ TypeInfo type{DataType::FLOAT32};
+ auto in = graph.addOperand(shape, type);
+ auto out = graph.addOperand(shape, type);
+
+ // Set model inputs/outputs
+ graph.addInput(in);
+ graph.addOutput(out);
+ graph.addOutput(OperandIndex{12}); // Non-exisiting operand!
+
+ EXPECT_ANY_THROW(graph.finishBuilding());
+}
+
+TEST(Graph, neg_InvalidGraphFinish_BadInputOutputForOp)
+{
+ Graph graph;
+
+ // Add tensors
+ Shape shape{1, 2, 2, 1};
+ TypeInfo type{DataType::FLOAT32};
+ auto lhs = graph.addOperand(shape, type);
+ auto rhs = graph.addOperand(shape, type);
+ auto res = graph.addOperand(shape, type);
+
+ addAddOperation(graph, {lhs, OperandIndex{99}}, {res});
+
+ // Set model inputs/outputs
+ graph.addInput(lhs);
+ graph.addInput(rhs);
+ graph.addOutput(res);
+
+ EXPECT_ANY_THROW(graph.finishBuilding());
+}
diff --git a/runtime/onert/test/graph/Index.cc b/runtime/onert/test/graph/Index.cc
new file mode 100644
index 000000000..2d110e326
--- /dev/null
+++ b/runtime/onert/test/graph/Index.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "util/Index.h"
+
+using Index = ::onert::util::Index<uint32_t, struct TestTag>;
+
+TEST(Index, neg_index_test)
+{
+ Index idx1{1u};
+ Index idx2{2u};
+ Index idx3{idx1};
+
+ ASSERT_EQ(idx1, 1);
+ ASSERT_EQ(idx1, 1u);
+ ASSERT_EQ(idx1.value(), 1u);
+ ASSERT_NE(idx1, idx2);
+ ASSERT_EQ(idx1, idx3);
+}
diff --git a/runtime/onert/test/graph/MockNode.h b/runtime/onert/test/graph/MockNode.h
new file mode 100644
index 000000000..60b4719ed
--- /dev/null
+++ b/runtime/onert/test/graph/MockNode.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ONERT_TEST_GRAPH_MOCK_NODE_H__
+#define __ONERT_TEST_GRAPH_MOCK_NODE_H__
+
+#include "ir/Operation.h"
+#include "ir/OperandIndexSequence.h"
+
+namespace onert_test
+{
+namespace ir
+{
+
+class SimpleMock : public onert::ir::Operation
+{
+public:
+ SimpleMock(const onert::ir::OperandIndexSequence &inputs,
+ const onert::ir::OperandIndexSequence &outputs)
+ : Operation{onert::ir::OperandConstraint::createAny()}
+ {
+ setInputs(inputs);
+ setOutputs(outputs);
+ }
+
+public:
+ void accept(onert::ir::OperationVisitor &) const override {}
+ onert::ir::OpCode opcode() const final { return onert::ir::OpCode::Invalid; }
+};
+
+} // namespace ir
+} // namespace onert_test
+
+#endif // __ONERT_TEST_GRAPH_MOCK_NODE_H__
diff --git a/runtime/onert/test/graph/operand/IndexSet.cc b/runtime/onert/test/graph/operand/IndexSet.cc
new file mode 100644
index 000000000..c363e5472
--- /dev/null
+++ b/runtime/onert/test/graph/operand/IndexSet.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ir/OperandIndexSequence.h"
+
+using onert::ir::OperandIndex;
+using onert::ir::OperandIndexSequence;
+
+TEST(ir_OperandIndexSequence, neg_append)
+{
+ OperandIndexSequence iset{0, 2, 4, 8};
+
+ ASSERT_EQ(iset.size(), 4);
+
+ iset.append(OperandIndex{10});
+
+ ASSERT_EQ(iset.size(), 5);
+
+ onert::ir::IOIndex index1{1};
+ onert::ir::IOIndex index2{4};
+
+ ASSERT_EQ(iset.at(index1), 2);
+ ASSERT_EQ(iset.at(index2), 10);
+
+ ASSERT_TRUE(iset.contains(OperandIndex{2}));
+ ASSERT_TRUE(iset.contains(OperandIndex{10}));
+ ASSERT_FALSE(iset.contains(OperandIndex{11}));
+}
+
+TEST(graph_OperandIndexSequence, neg_replace)
+{
+ OperandIndexSequence iset{0, 1, 2, 3};
+
+ iset.replace(OperandIndex{1}, OperandIndex{9});
+ ASSERT_FALSE(iset.contains(OperandIndex{1}));
+ ASSERT_TRUE(iset.contains(OperandIndex{9}));
+}
diff --git a/runtime/onert/test/graph/operand/LayoutSet.cc b/runtime/onert/test/graph/operand/LayoutSet.cc
new file mode 100644
index 000000000..6aa01b9f1
--- /dev/null
+++ b/runtime/onert/test/graph/operand/LayoutSet.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ir/LayoutSet.h"
+
+using onert::ir::Layout;
+using onert::ir::LayoutSet;
+
+TEST(ir_LayoutSet, neg_add_remove)
+{
+ LayoutSet set{Layout::NCHW};
+ set.remove(Layout::NHWC);
+ ASSERT_EQ(set.size(), 1);
+ set.add(Layout::NHWC);
+ ASSERT_EQ(set.size(), 2);
+ set.remove(Layout::NHWC);
+ ASSERT_EQ(set.size(), 1);
+ set.remove(Layout::NCHW);
+ ASSERT_EQ(set.size(), 0);
+ set.remove(Layout::NCHW);
+ ASSERT_EQ(set.size(), 0);
+}
+
+TEST(ir_LayoutSet, set_operators)
+{
+ LayoutSet set1{Layout::NCHW};
+ LayoutSet set2{Layout::NHWC};
+ LayoutSet set3 = set1 | set2;
+
+ ASSERT_EQ(set3.size(), 2);
+
+ ASSERT_EQ((set3 - set1).size(), 1);
+ ASSERT_EQ((set3 - set1).contains(Layout::NHWC), true);
+ ASSERT_EQ((set3 - set2).size(), 1);
+ ASSERT_EQ((set3 - set2).contains(Layout::NCHW), true);
+ ASSERT_EQ((set3 - set3).size(), 0);
+
+ ASSERT_EQ((set3 & set1).size(), 1);
+ ASSERT_EQ((set3 & set1).contains(Layout::NCHW), true);
+ ASSERT_EQ((set3 & set2).size(), 1);
+ ASSERT_EQ((set3 & set2).contains(Layout::NHWC), true);
+ ASSERT_EQ((set1 & set2).size(), 0);
+}
diff --git a/runtime/onert/test/graph/operand/Set.cc b/runtime/onert/test/graph/operand/Set.cc
new file mode 100644
index 000000000..6cf9c8842
--- /dev/null
+++ b/runtime/onert/test/graph/operand/Set.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ir/Operands.h"
+
+TEST(ir_Operands, neg_set_test)
+{
+ onert::ir::Operands set;
+
+ onert::ir::Shape shape0{1, 2, 3};
+
+ onert::ir::Shape shape1(4);
+ shape1.dim(0) = 10;
+ shape1.dim(1) = 20;
+ shape1.dim(2) = 30;
+ shape1.dim(3) = 40;
+
+ onert::ir::TypeInfo type{onert::ir::DataType::INT32};
+
+ set.emplace(shape0, type);
+ set.emplace(shape1, type);
+
+ ASSERT_EQ(set.exist(onert::ir::OperandIndex{0u}), true);
+ ASSERT_EQ(set.exist(onert::ir::OperandIndex{1u}), true);
+ ASSERT_EQ(set.exist(onert::ir::OperandIndex{2u}), false);
+
+ ASSERT_EQ(set.at(onert::ir::OperandIndex{0u}).shape().dim(0), 1);
+ ASSERT_EQ(set.at(onert::ir::OperandIndex{0u}).shape().dim(1), 2);
+ ASSERT_EQ(set.at(onert::ir::OperandIndex{0u}).shape().dim(2), 3);
+}
diff --git a/runtime/onert/test/graph/operand/UseDef.cc b/runtime/onert/test/graph/operand/UseDef.cc
new file mode 100644
index 000000000..206e402ed
--- /dev/null
+++ b/runtime/onert/test/graph/operand/UseDef.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ir/Graph.h"
+#include "ir/verifier/Verifier.h"
+#include <memory>
+#include "../MockNode.h"
+
+#include <typeindex>
+
+namespace
+{
+
+using IndexSet = onert::ir::OperandIndexSequence;
+using Mock = onert_test::ir::SimpleMock;
+
+} // namespace
+
+TEST(ir_Operand, neg_usedef)
+{
+ onert::ir::Graph graph;
+ onert::ir::verifier::DAGChecker verifier;
+
+ onert::ir::Shape shape(3);
+ onert::ir::TypeInfo type{onert::ir::DataType::INT32};
+
+ // Model Input/Output
+ auto input_operand = graph.addOperand(shape, type);
+ auto output_operand = graph.addOperand(shape, type);
+
+ graph.addInput(input_operand);
+ graph.addOutput(output_operand);
+
+ // MockNode1
+ auto operand_index1 = graph.addOperand(shape, type);
+ auto mocknode_index1 =
+ graph.addOperation(std::make_unique<Mock>(IndexSet{input_operand}, IndexSet{operand_index1}));
+
+ // MockNode2
+ auto operand_index2 = graph.addOperand(shape, type);
+ auto mocknode_index2 =
+ graph.addOperation(std::make_unique<Mock>(IndexSet{input_operand}, IndexSet{operand_index2}));
+
+ // MockNode3(two input)
+ auto multiinput_index = graph.addOperation(
+ std::make_unique<Mock>(IndexSet{operand_index1, operand_index2}, IndexSet{output_operand}));
+
+ graph.finishBuilding();
+
+ ASSERT_TRUE(verifier.verify(graph));
+
+ // Check def
+ ASSERT_EQ(graph.operands().at(operand_index1).getDef(), mocknode_index1);
+ ASSERT_EQ(graph.operands().at(operand_index2).getDef(), mocknode_index2);
+ ASSERT_EQ(graph.operands().at(output_operand).getDef(), multiinput_index);
+
+ ASSERT_NE(graph.operands().at(operand_index1).getDef(), mocknode_index2);
+ ASSERT_NE(graph.operands().at(operand_index1).getDef(), multiinput_index);
+
+ // Check use
+ ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(mocknode_index1), true);
+ ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(mocknode_index2), true);
+ ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(multiinput_index), false);
+ ASSERT_EQ(graph.operands().at(operand_index1).getUses().contains(multiinput_index), true);
+ ASSERT_EQ(graph.operands().at(operand_index2).getUses().contains(multiinput_index), true);
+
+ ASSERT_EQ(graph.operands().at(input_operand).getUses().size(), 2);
+ ASSERT_EQ(graph.operands().at(operand_index1).getUses().size(), 1);
+ ASSERT_EQ(graph.operands().at(output_operand).getUses().size(), 0);
+}
diff --git a/runtime/onert/test/graph/operation/Set.cc b/runtime/onert/test/graph/operation/Set.cc
new file mode 100644
index 000000000..50c3b304d
--- /dev/null
+++ b/runtime/onert/test/graph/operation/Set.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "../MockNode.h"
+#include "ir/Operations.h"
+
+using onert::ir::Operation;
+using onert::ir::OperationIndex;
+using onert::ir::Operations;
+
+TEST(ir_Operations, basic)
+{
+ Operations ops;
+ ops.push(std::unique_ptr<Operation>(new onert_test::ir::SimpleMock({1, 2, 3, 4}, {5, 6, 7})));
+ OperationIndex idx{0u};
+ ASSERT_EQ(ops.at(idx).getInputs().size(), 4);
+ ASSERT_EQ(ops.at(idx).getOutputs().size(), 3);
+}
+
+TEST(ir_Operations, neg_at)
+{
+ Operations ops;
+ ops.push(std::unique_ptr<Operation>(new onert_test::ir::SimpleMock({1, 2, 3, 4}, {5, 6, 7})));
+ OperationIndex idx{99u};
+ EXPECT_THROW(ops.at(idx), std::out_of_range);
+}
diff --git a/runtime/onert/test/graph/operation/SetIO.cc b/runtime/onert/test/graph/operation/SetIO.cc
new file mode 100644
index 000000000..68b477347
--- /dev/null
+++ b/runtime/onert/test/graph/operation/SetIO.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ir/Graph.h"
+#include "ir/Index.h"
+#include "ir/OperandIndexSequence.h"
+#include "ir/operation/Conv2D.h"
+#include "ir/operation/Concat.h"
+
+#include <memory>
+
+#include <stdexcept>
+
+using Index = onert::ir::IOIndex;
+using IndexSet = onert::ir::OperandIndexSequence;
+
+TEST(ir_Operation_setIO, operation_setIO_conv)
+{
+ onert::ir::Graph graph;
+
+ onert::ir::Shape shape{3};
+ onert::ir::TypeInfo type{onert::ir::DataType::INT32};
+
+ // Add Conv
+ using Graph = onert::ir::operation::Conv2D;
+
+ auto input_operand = graph.addOperand(shape, type);
+ auto kernel_operand = graph.addOperand(shape, type);
+ auto bias_operand = graph.addOperand(shape, type);
+ IndexSet inputs{input_operand, kernel_operand, bias_operand};
+
+ Graph::Param conv_params;
+ conv_params.padding.type = onert::ir::PaddingType::SAME;
+ conv_params.stride.horizontal = 1;
+ conv_params.stride.vertical = 1;
+ conv_params.activation = onert::ir::Activation::NONE;
+
+ auto output_operand = graph.addOperand(shape, type).value();
+ IndexSet outputs{output_operand};
+
+ auto conv = std::make_unique<Graph>(inputs, outputs, conv_params);
+
+ ASSERT_NE(conv, nullptr);
+ ASSERT_EQ(conv->getInputs().at(Index{0}).value(), inputs.at(0).value());
+ conv->setInputs({8, 9, 10});
+ ASSERT_NE(conv->getInputs().at(Index{0}).value(), inputs.at(0).value());
+ ASSERT_EQ(conv->getInputs().at(Index{0}).value(), 8);
+}
+
+TEST(ir_Operation_setIO, neg_operation_setIO_concat)
+{
+ onert::ir::Graph graph;
+
+ onert::ir::Shape shape{3};
+
+ onert::ir::TypeInfo type{onert::ir::DataType::INT32};
+
+ using Graph = onert::ir::operation::Concat;
+
+ // Add Concat
+ IndexSet inputs;
+ for (int i = 0; i < 6; ++i)
+ {
+ inputs.append(graph.addOperand(shape, type));
+ }
+
+ Graph::Param concat_params{0};
+
+ auto output_operand = graph.addOperand(shape, type).value();
+ IndexSet outputs{output_operand};
+
+ auto concat = std::make_unique<Graph>(inputs, outputs, concat_params);
+
+ ASSERT_NE(concat, nullptr);
+ ASSERT_EQ(concat->getInputs().size(), 6);
+ ASSERT_EQ(concat->getInputs().at(Index{0}).value(), inputs.at(0).value());
+
+ concat->setInputs({80, 6, 9, 11});
+ ASSERT_EQ(concat->getInputs().size(), 4);
+ ASSERT_NE(concat->getInputs().at(Index{0}).value(), inputs.at(0).value());
+ ASSERT_EQ(concat->getInputs().at(Index{0}).value(), 80);
+ ASSERT_EQ(concat->getInputs().at(Index{2}).value(), 9);
+ ASSERT_THROW(concat->getInputs().at(Index{5}), std::out_of_range);
+}
diff --git a/runtime/onert/test/graph/verifier/Verifier.cc b/runtime/onert/test/graph/verifier/Verifier.cc
new file mode 100644
index 000000000..3bce2746c
--- /dev/null
+++ b/runtime/onert/test/graph/verifier/Verifier.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ir/Operation.h"
+#include "ir/Graph.h"
+#include "ir/verifier/Verifier.h"
+#include <memory>
+#include "ir/Operand.h"
+#include "../MockNode.h"
+
+using IndexSet = onert::ir::OperandIndexSequence;
+using Mock = onert_test::ir::SimpleMock;
+
+TEST(Verifier, dag_checker)
+{
+ onert::ir::Graph graph;
+
+ onert::ir::Shape shape{3};
+ onert::ir::TypeInfo type{onert::ir::DataType::INT32};
+
+ auto operand1 = graph.addOperand(shape, type);
+ auto operand2 = graph.addOperand(shape, type);
+
+ graph.addInput(operand1);
+ graph.addOutput(operand2);
+
+ graph.addOperation(std::make_unique<Mock>(IndexSet{operand1}, IndexSet{operand2}));
+
+ graph.finishBuilding();
+
+ onert::ir::verifier::DAGChecker verifier;
+
+ ASSERT_TRUE(verifier.verify(graph));
+}
+
+TEST(Verifier, neg_edge_consistency_checker_1)
+{
+ onert::ir::Graph graph;
+
+ onert::ir::Shape shape{3};
+ onert::ir::TypeInfo type{onert::ir::DataType::INT32};
+
+ auto operand1 = graph.addOperand(shape, type);
+ auto operand2 = graph.addOperand(shape, type);
+
+ graph.addInput(operand1);
+ graph.addOutput(operand2);
+
+ auto mock_op = std::make_unique<Mock>(IndexSet{operand1}, IndexSet{operand2});
+ auto op_ind = graph.addOperation(std::move(mock_op));
+
+ graph.finishBuilding();
+
+ graph.operands().at(operand1).removeUse(op_ind); // Manipulate the operand alone
+
+ onert::ir::verifier::EdgeConsistencyChecker verifier;
+ ASSERT_FALSE(verifier.verify(graph));
+}
+
+TEST(Verifier, neg_edge_consistency_checker_2)
+{
+ onert::ir::Graph graph;
+
+ onert::ir::Shape shape{3};
+ onert::ir::TypeInfo type{onert::ir::DataType::INT32};
+
+ auto operand1 = graph.addOperand(shape, type);
+ auto operand2 = graph.addOperand(shape, type);
+
+ graph.addInput(operand1);
+ graph.addOutput(operand2);
+
+ auto mock_op = std::make_unique<Mock>(IndexSet{operand1}, IndexSet{operand2});
+ auto mock_op_ptr = mock_op.get();
+ auto op_ind = graph.addOperation(std::move(mock_op));
+
+ graph.finishBuilding();
+
+ mock_op_ptr->setInputs({operand2}); // Manipulate the operation alone
+
+ onert::ir::verifier::EdgeConsistencyChecker verifier;
+ ASSERT_FALSE(verifier.verify(graph));
+}
diff --git a/runtime/onert/test/ir/Shape.cc b/runtime/onert/test/ir/Shape.cc
new file mode 100644
index 000000000..c24aeda8d
--- /dev/null
+++ b/runtime/onert/test/ir/Shape.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ir/Shape.h>
+
+#include <gtest/gtest.h>
+
+TEST(ShapeTest, basic_test)
+{
+ {
+ onert::ir::Shape shape(3);
+
+ shape.dim(0) = 1;
+ shape.dim(1) = 2;
+ shape.dim(2) = 3;
+
+ ASSERT_EQ(shape.rank(), 3);
+ ASSERT_EQ(shape.num_elements(), 6);
+ ASSERT_EQ(onert::ir::rankMaybeUnspecified(shape), false);
+ ASSERT_EQ(shape.hasUnspecifiedDims(), false);
+ }
+ {
+ onert::ir::Shape shape; // scalar or rank is unspecified
+
+ ASSERT_EQ(shape.rank(), 0);
+ ASSERT_EQ(shape.num_elements(), 1);
+ ASSERT_EQ(onert::ir::rankMaybeUnspecified(shape), true);
+ ASSERT_EQ(shape.hasUnspecifiedDims(), false);
+ }
+}
+
+TEST(ShapeTest, neg_basic_test)
+{
+ {
+ onert::ir::Shape shape(2);
+
+ shape.dim(0) = 1;
+ shape.dim(1) = onert::ir::Shape::UNSPECIFIED_DIM;
+
+ ASSERT_EQ(shape.rank(), 2);
+ ASSERT_EQ(onert::ir::rankMaybeUnspecified(shape), false);
+ ASSERT_EQ(shape.hasUnspecifiedDims(), true);
+ EXPECT_ANY_THROW(shape.num_elements());
+ }
+}
diff --git a/runtime/onert/test/util/ObjectManager.cc b/runtime/onert/test/util/ObjectManager.cc
new file mode 100644
index 000000000..24bb9b0c1
--- /dev/null
+++ b/runtime/onert/test/util/ObjectManager.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "util/ObjectManager.h"
+#include "util/Index.h"
+
+using namespace onert;
+
+struct TestTag;
+using Index = typename util::Index<uint32_t, TestTag>;
+
+TEST(ObjectManager, emplace)
+{
+ util::ObjectManager<Index, int> man;
+
+ auto index = man.emplace(100);
+ ASSERT_EQ(man.at(index), 100);
+}
+
+TEST(ObjectManager, neg_remove_1)
+{
+ util::ObjectManager<Index, int> man;
+
+ Index index = man.emplace(100);
+ ASSERT_TRUE(man.exist(index));
+ ASSERT_EQ(man.at(index), 100);
+
+ man.remove(index);
+ ASSERT_FALSE(man.exist(index));
+}
+
+TEST(ObjectManager, neg_remove_2)
+{
+ util::ObjectManager<Index, int> man;
+
+ auto index0 = man.emplace(100);
+ auto index1 = man.emplace(200);
+ ASSERT_TRUE(man.exist(index0));
+ ASSERT_EQ(man.at(index0), 100);
+ ASSERT_TRUE(man.exist(index1));
+ ASSERT_EQ(man.at(index1), 200);
+
+ man.remove(index0);
+ ASSERT_FALSE(man.exist(index0));
+ ASSERT_TRUE(man.exist(index1));
+ ASSERT_EQ(man.at(index1), 200);
+}
+
+TEST(ObjectManager, push)
+{
+ util::ObjectManager<Index, int> man;
+
+ auto index = man.push(std::unique_ptr<int>{new int{100}});
+ ASSERT_EQ(man.at(index), 100);
+}
+
+TEST(ObjectManager, const_iterate)
+{
+ util::ObjectManager<Index, int> man;
+
+ auto index0 = man.emplace(100);
+ auto index1 = man.emplace(200);
+ auto index2 = man.emplace(300);
+
+ int sum = 0;
+ man.iterate([&](const Index &index, const int &val) { sum += val; });
+ ASSERT_EQ(sum, 600);
+}
+
+TEST(ObjectManager, non_const_iterate)
+{
+ util::ObjectManager<Index, int> man;
+
+ auto index0 = man.emplace(100);
+ auto index1 = man.emplace(200);
+ auto index2 = man.emplace(300);
+
+ man.iterate([&](const Index &index, int &val) { val += 1; });
+ ASSERT_EQ(man.at(index0), 101);
+ ASSERT_EQ(man.at(index1), 201);
+ ASSERT_EQ(man.at(index2), 301);
+}
diff --git a/runtime/onert/test/util/ShapeInference.cc b/runtime/onert/test/util/ShapeInference.cc
new file mode 100644
index 000000000..f1cbfd692
--- /dev/null
+++ b/runtime/onert/test/util/ShapeInference.cc
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ir/Layout.h"
+#include "util/ShapeInference.h"
+
+using namespace onert::ir;
+
+TEST(ShapeInference, Elementwise)
+{
+ Shape lhs_shape{1, 299, 299, 3};
+ Shape rhs_shape{3};
+ auto infered_out_shape = onert::shape_inference::inferEltwiseShape(lhs_shape, rhs_shape);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.dim(0), 1);
+ ASSERT_EQ(infered_out_shape.dim(1), 299);
+ ASSERT_EQ(infered_out_shape.dim(2), 299);
+ ASSERT_EQ(infered_out_shape.dim(3), 3);
+}
+
+TEST(ShapeInference, neg_Elementwise)
+{
+ Shape lhs_shape{1, 299, 299, 3};
+ Shape rhs_shape{5, 3};
+ ASSERT_THROW(onert::shape_inference::inferEltwiseShape(lhs_shape, rhs_shape), std::runtime_error);
+}
+
+TEST(ShapeInference, Pool2DNodeSame)
+{
+ Shape in_shape{10, 6, 12, 20};
+ Stride stride{3, 7};
+ Padding padding{PaddingType::SAME};
+
+ operation::Pool2D::Param avg_pool_param{
+ operation::Pool2D::PoolType::AVG, 3, 6, stride, padding, Activation::NONE};
+ auto infered_out_shape = onert::shape_inference::inferPoolShape(in_shape, avg_pool_param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20);
+
+ operation::Pool2D::Param max_pool_param{
+ operation::Pool2D::PoolType::MAX, 3, 6, stride, padding, Activation::NONE};
+ infered_out_shape = onert::shape_inference::inferPoolShape(in_shape, max_pool_param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20);
+}
+
+TEST(ShapeInference, Pool2DNodeValid)
+{
+ Shape in_shape{10, 6, 12, 20};
+ Stride stride{3, 7};
+ Padding padding{PaddingType::VALID};
+
+ operation::Pool2D::Param avg_pool_param{
+ operation::Pool2D::PoolType::AVG, 3, 6, stride, padding, Activation::NONE};
+ auto infered_out_shape = onert::shape_inference::inferPoolShape(in_shape, avg_pool_param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20);
+
+ operation::Pool2D::Param max_pool_param{
+ operation::Pool2D::PoolType::MAX, 3, 6, stride, padding, Activation::NONE};
+ infered_out_shape = onert::shape_inference::inferPoolShape(in_shape, max_pool_param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20);
+}
+
+TEST(ShapeInference, Pool2DNodeExplicit)
+{
+ Shape in_shape{10, 3, 5, 20};
+
+ Stride stride{3, 7};
+ Padding padding{4, 3, 2, 1};
+
+ operation::Pool2D::Param avg_pool_param{
+ operation::Pool2D::PoolType::AVG, 3, 6, stride, padding, Activation::NONE};
+ auto infered_out_shape = onert::shape_inference::inferPoolShape(in_shape, avg_pool_param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20);
+
+ operation::Pool2D::Param max_pool_param{
+ operation::Pool2D::PoolType::MAX, 3, 6, stride, padding, Activation::NONE};
+ infered_out_shape = onert::shape_inference::inferPoolShape(in_shape, max_pool_param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20);
+}
+
+TEST(ShapeInference, neg_Pool2DNode_InvalidStride)
+{
+ Shape in_shape{10, 6, 12, 20};
+ Stride stride{0, 7};
+ Padding padding{PaddingType::SAME};
+
+ operation::Pool2D::Param avg_pool_param{
+ operation::Pool2D::PoolType::AVG, 3, 6, stride, padding, Activation::NONE};
+ ASSERT_THROW(onert::shape_inference::inferPoolShape(in_shape, avg_pool_param),
+ std::runtime_error);
+}
+
+TEST(ShapeInference, Conv2D)
+{
+ Shape in_shape{10, 6, 12, 20};
+ Shape ker_shape{30, 3, 6, 20};
+
+ operation::Conv2D::Param param{Stride{3, 7}, Padding{PaddingType::VALID}, Activation::NONE,
+ Dilation{1, 1}};
+ auto infered_out_shape = onert::shape_inference::inferConv2DShape(in_shape, ker_shape, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 30);
+
+ param = operation::Conv2D::Param{Stride{3, 7}, Padding{PaddingType::SAME}, Activation::NONE,
+ Dilation{1, 1}};
+ infered_out_shape = onert::shape_inference::inferConv2DShape(in_shape, ker_shape, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 30);
+
+ param =
+ operation::Conv2D::Param{Stride{3, 7}, Padding{4, 3, 2, 1}, Activation::NONE, Dilation{1, 1}};
+ infered_out_shape = onert::shape_inference::inferConv2DShape(in_shape, ker_shape, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 3);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 30);
+}
+
+TEST(ShapeInference, neg_Conv2D_InvalidStride)
+{
+ Shape in_shape{10, 6, 12, 20};
+ Shape ker_shape{30, 3, 6, 20};
+
+ operation::Conv2D::Param param{Stride{0, 0}, Padding{PaddingType::VALID}, Activation::NONE,
+ Dilation{1, 1}};
+ ASSERT_THROW(onert::shape_inference::inferConv2DShape(in_shape, ker_shape, param),
+ std::runtime_error);
+}
+
+TEST(ShapeInference, DepthwiseConv2D)
+{
+ Shape in_shape{10, 6, 12, 20};
+ Shape ker_shape{1, 3, 6, 60};
+
+ operation::DepthwiseConv2D::Param param{Stride{3, 7}, Padding{PaddingType::VALID}, 3,
+ Activation::NONE, Dilation{1, 1}};
+ auto infered_out_shape =
+ onert::shape_inference::inferDepthwiseConv2DShape(in_shape, ker_shape, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 60);
+
+ param = operation::DepthwiseConv2D::Param{Stride{3, 7}, Padding{PaddingType::SAME}, 3,
+ Activation::NONE, Dilation{1, 1}};
+ infered_out_shape = onert::shape_inference::inferDepthwiseConv2DShape(in_shape, ker_shape, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 60);
+
+ param = operation::DepthwiseConv2D::Param{Stride{3, 7}, Padding{4, 3, 2, 1}, 3, Activation::NONE,
+ Dilation{1, 1}};
+ infered_out_shape = onert::shape_inference::inferDepthwiseConv2DShape(in_shape, ker_shape, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 4);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 3);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2);
+ ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 60);
+}
+
+TEST(ShapeInference, neg_DepthwiseConv2D_InvalidSride)
+{
+ Shape in_shape{10, 6, 12, 20};
+ Shape ker_shape{1, 3, 6, 60};
+
+ operation::DepthwiseConv2D::Param param{Stride{3, 0}, Padding{PaddingType::VALID}, 3,
+ Activation::NONE, Dilation{1, 1}};
+ ASSERT_THROW(onert::shape_inference::inferDepthwiseConv2DShape(in_shape, ker_shape, param),
+ std::runtime_error);
+}
+
+TEST(ShapeInference, Concat)
+{
+ {
+ Shape in1{10, 20, 30, 3, 50};
+ Shape in2{10, 20, 30, 2, 50};
+ Shape in3{10, 20, 30, 2, 50};
+
+ operation::Concat::Param param{3};
+ auto infered_out_shape = onert::shape_inference::inferConcatShape({in1, in2, in3}, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 5);
+ ASSERT_EQ(infered_out_shape.dim(0), 10);
+ ASSERT_EQ(infered_out_shape.dim(1), 20);
+ ASSERT_EQ(infered_out_shape.dim(2), 30);
+ ASSERT_EQ(infered_out_shape.dim(3), 7);
+ ASSERT_EQ(infered_out_shape.dim(4), 50);
+ }
+ {
+ // case 1. when axis < 0
+ Shape in1{10, 20, 2};
+ Shape in2{10, 20, 3};
+
+ operation::Concat::Param param{-1};
+ auto infered_out_shape = onert::shape_inference::inferConcatShape({in1, in2}, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 3);
+ ASSERT_EQ(infered_out_shape.dim(0), 10);
+ ASSERT_EQ(infered_out_shape.dim(1), 20);
+ ASSERT_EQ(infered_out_shape.dim(2), 5);
+ }
+ {
+ // case 2. when axis < 0
+ Shape in1{2, 20, 2};
+ Shape in2{3, 20, 2};
+
+ operation::Concat::Param param{-3};
+ auto infered_out_shape = onert::shape_inference::inferConcatShape({in1, in2}, param);
+
+ ASSERT_EQ(infered_out_shape.rank(), 3);
+ ASSERT_EQ(infered_out_shape.dim(0), 5);
+ ASSERT_EQ(infered_out_shape.dim(1), 20);
+ ASSERT_EQ(infered_out_shape.dim(2), 2);
+ }
+}
+
+TEST(ShapeInference, neg_Concat)
+{
+ {
+ operation::Concat::Param param{2};
+ Shape in1{10, 1, 3};
+ Shape in2{10, 2, 4}; // dim[1] should be 1 but 2
+
+ EXPECT_ANY_THROW(onert::shape_inference::inferConcatShape({in1, in2}, param));
+ }
+ { // wrong rank
+ operation::Concat::Param param{2};
+ Shape in1{10, 2, 3, 4};
+ Shape in2{10, 2, 4}; // rank should be 4
+
+ EXPECT_ANY_THROW(onert::shape_inference::inferConcatShape({in1, in2}, param));
+ }
+}
+
+TEST(ShapeInference, ExpandDims)
+{
+ Shape in_shape{30, 40};
+
+ auto check = [&](int32_t axis, Shape &expected) {
+ auto actual = onert::shape_inference::inferExpandDimsShape(in_shape, axis);
+
+ ASSERT_EQ(actual.rank(), 3);
+ for (int32_t dim = 0; dim < expected.rank(); dim++)
+ ASSERT_EQ(actual.dim(dim), expected.dim(dim));
+ };
+
+ { // boundary
+ int32_t axis = 0;
+ Shape expected{1, 30, 40};
+ check(axis, expected);
+ }
+ { // boundary
+ int32_t axis = 2;
+ Shape expected{30, 40, 1};
+ check(axis, expected);
+ }
+ { // inside
+ int32_t axis = 1;
+ Shape expected{30, 1, 40};
+ check(axis, expected);
+ }
+ { // negative boundary
+ int32_t axis = -1;
+ Shape expected{30, 40, 1};
+ check(axis, expected);
+ }
+ { // negative boundary
+ int32_t axis = -3;
+ Shape expected{1, 30, 40};
+ check(axis, expected);
+ }
+}
+
+TEST(ShapeInference, neg_ExpandDims)
+{
+ Shape in_shape{30, 40};
+
+ { // over boundary
+ int32_t axis = 3;
+ ASSERT_THROW(onert::shape_inference::inferExpandDimsShape(in_shape, axis), std::runtime_error);
+ }
+ { // over boundary
+ int32_t axis = -4;
+ ASSERT_THROW(onert::shape_inference::inferExpandDimsShape(in_shape, axis), std::runtime_error);
+ }
+}
+
+TEST(ShapeInference, FullyConnected)
+{
+ Shape in_shape{3, 4, 5, 6};
+ Shape ker_shape{3, 10};
+ auto infered_out_shape = onert::shape_inference::inferFullyConnectedShape(in_shape, ker_shape);
+
+ ASSERT_EQ(infered_out_shape.rank(), 2);
+ ASSERT_EQ(infered_out_shape.dim(0), 36);
+ ASSERT_EQ(infered_out_shape.dim(1), 3);
+}
+
+TEST(ShapeInference, Transpose)
+{
+ auto check = [&](Shape &in_shape, std::vector<int> perm, Shape &expected) {
+ // pre-conditions
+ ASSERT_EQ(in_shape.rank(), perm.size());
+ ASSERT_EQ(expected.rank(), perm.size());
+ auto inferred_out_shape =
+ onert::shape_inference::inferTransposeShape(in_shape, perm.data(), perm.size());
+ // post-conditions
+ ASSERT_EQ(inferred_out_shape.rank(), perm.size());
+ for (int32_t dim = 0; dim < expected.rank(); dim++)
+ {
+ ASSERT_EQ(inferred_out_shape.dim(dim), expected.dim(dim));
+ }
+ };
+ // check for 2-D
+ {
+ Shape in_shape{2, 3};
+ std::vector<int> perm = {1, 0};
+ Shape expected{3, 2};
+ // int32_t rank = 2;
+ check(in_shape, perm, expected);
+ }
+ // check for 3-D
+ {
+ Shape in_shape{1, 2, 3};
+ std::vector<int> perm = {2, 0, 1};
+ Shape expected{3, 1, 2};
+ // int32_t rank = 3;
+ check(in_shape, perm, expected);
+ }
+ // check for 4-D
+ {
+ Shape in_shape{1, 2, 3, 4};
+ std::vector<int> perm = {1, 3, 0, 2};
+ Shape expected{2, 4, 1, 3};
+ // int32_t rank = 4;
+ check(in_shape, perm, expected);
+ }
+}
+
+TEST(ShapeInference, neg_Transpose)
+{
+ Shape in_shape{1, 2, 3};
+ // Invalid parameter size
+ {
+ std::vector<int> perm = {2, 0, 1, 0};
+ // int32_t rank = 3;
+ ASSERT_THROW(onert::shape_inference::inferTransposeShape(in_shape, perm.data(), perm.size()),
+ std::runtime_error);
+ }
+ // Invalid parameter value
+ {
+ std::vector<int> perm = {2, 0, 3};
+ // int32_t rank = 3;
+ ASSERT_THROW(onert::shape_inference::inferTransposeShape(in_shape, perm.data(), perm.size()),
+ std::runtime_error);
+ }
+}
+
+TEST(ShapeInference, Gather)
+{
+ auto check = [&](Shape &input, Shape &indices, Shape &expected, int32_t axis) {
+ int rank = input.rank();
+ auto actual = onert::shape_inference::inferGatherShape(input, indices, axis, rank);
+
+ ASSERT_EQ(actual.rank(), expected.rank());
+
+ for (int32_t dim = 0; dim < expected.rank(); dim++)
+ ASSERT_EQ(actual.dim(dim), expected.dim(dim));
+ };
+
+ // check for 2-D, 3-D, axis 0
+ {
+ Shape input{3, 4};
+ Shape indices{1, 1, 2};
+ int32_t axis = 0;
+ Shape expected{1, 1, 2, 4};
+ check(input, indices, expected, axis);
+ }
+
+ // check for 2-D, 3-D, axis 1
+ {
+ Shape input{3, 4};
+ Shape indices{1, 2, 1};
+ int32_t axis = 1;
+ Shape expected{3, 1, 2, 1};
+ check(input, indices, expected, axis);
+ }
+
+ // check for 3-D, 2-D, axis 0
+ {
+ Shape input{2, 3, 4};
+ Shape indices{1, 2};
+ int32_t axis = 0;
+ Shape expected{1, 2, 3, 4};
+ check(input, indices, expected, axis);
+ }
+
+ // check for 3-D, 2-D, axis 2
+ {
+ Shape input{2, 3, 4};
+ Shape indices{2, 1};
+ int32_t axis = 2;
+ Shape expected{2, 3, 2, 1};
+ check(input, indices, expected, axis);
+ }
+
+ // check for 4D, axis 0
+ {
+ Shape input{1, 2, 3, 4};
+ Shape indices{2};
+ int32_t axis = 0;
+ Shape expected{2, 2, 3, 4};
+ check(input, indices, expected, axis);
+ }
+}
+
+TEST(ShapeInference, BCQFullyConnected)
+{
+ auto check = [&](Shape &in_shape, Shape &cluster_shape, std::vector<int> cluster,
+ Shape &expected) {
+ auto actual = onert::shape_inference::inferBCQFullyConnectedShape(in_shape, cluster_shape,
+ cluster.data());
+ ASSERT_EQ(actual.rank(), expected.rank());
+
+ for (int32_t dim = 0; dim < expected.rank(); dim++)
+ ASSERT_EQ(actual.dim(dim), expected.dim(dim));
+ };
+
+ {
+ Shape in_shape{10, 1};
+ Shape cluster_shape{3, 2};
+ std::vector<int> cluster = {1, 10, 2, 10, 3, 10};
+
+ Shape expected{30, 1};
+ check(in_shape, cluster_shape, cluster, expected);
+ }
+
+ {
+ Shape in_shape{1, 1};
+ Shape cluster_shape{1, 2};
+ std::vector<int> cluster = {3, 50};
+
+ Shape expected{50, 1};
+ check(in_shape, cluster_shape, cluster, expected);
+ }
+}
+
+TEST(ShapeInference, BCQGather)
+{
+ auto check = [&](Shape &indices_shape, Shape &cluster_shape, std::vector<int> cluster,
+ uint32_t hidden_size, uint32_t axis, int rank, Shape &expected) {
+ operation::BCQGather::Param param{hidden_size, axis};
+ auto actual = onert::shape_inference::inferBCQGatherShape(indices_shape, cluster_shape,
+ cluster.data(), rank, param);
+ ASSERT_EQ(actual.rank(), expected.rank());
+
+ for (int32_t dim = 0; dim < expected.rank(); dim++)
+ ASSERT_EQ(actual.dim(dim), expected.dim(dim));
+ };
+
+ {
+ Shape indices_shape{5, 1};
+ Shape cluster_shape{3, 2};
+ std::vector<int> cluster = {1, 10, 2, 10, 3, 10};
+ uint32_t hidden_size = 10;
+ uint32_t axis = 0;
+ int rank = 2;
+
+ Shape expected{5, 1, 10};
+ check(indices_shape, cluster_shape, cluster, hidden_size, axis, rank, expected);
+ }
+
+ {
+ Shape indices_shape{5, 1};
+ Shape cluster_shape{3, 2};
+ std::vector<int> cluster = {1, 10, 2, 10, 3, 10};
+ uint32_t hidden_size = 10;
+ uint32_t axis = 1;
+ int rank = 2;
+
+ Shape expected{30, 5, 1};
+ check(indices_shape, cluster_shape, cluster, hidden_size, axis, rank, expected);
+ }
+}