summaryrefslogtreecommitdiff
path: root/runtime/onert/core
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/onert/core')
-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
413 files changed, 40309 insertions, 0 deletions
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;
+}