summaryrefslogtreecommitdiff
path: root/runtime/neurun/core
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/neurun/core')
-rw-r--r--runtime/neurun/core/CMakeLists.txt18
-rw-r--r--runtime/neurun/core/include/backend/Backend.h67
-rw-r--r--runtime/neurun/core/include/backend/CustomKernelBuilder.h69
-rw-r--r--runtime/neurun/core/include/backend/ExecTime.h111
-rw-r--r--runtime/neurun/core/include/backend/IConfig.h47
-rw-r--r--runtime/neurun/core/include/backend/IConstantInitializer.h288
-rw-r--r--runtime/neurun/core/include/backend/IKernelGenerator.h63
-rw-r--r--runtime/neurun/core/include/backend/IMemoryManager.h49
-rw-r--r--runtime/neurun/core/include/backend/IShapeFixer.h55
-rw-r--r--runtime/neurun/core/include/backend/ITensorBuilder.h89
-rw-r--r--runtime/neurun/core/include/backend/ITensorManager.h56
-rw-r--r--runtime/neurun/core/include/backend/ITensorRegister.h164
-rw-r--r--runtime/neurun/core/include/backend/JSONExecTime.h96
-rw-r--r--runtime/neurun/core/include/backend/operand/ITensor.h54
-rw-r--r--runtime/neurun/core/include/compiler/Compiler.h91
-rw-r--r--runtime/neurun/core/include/compiler/IExecutionBuilder.h39
-rw-r--r--runtime/neurun/core/include/compiler/SubTensorInfo.h83
-rw-r--r--runtime/neurun/core/include/exec/Execution.h144
-rw-r--r--runtime/neurun/core/include/exec/ExecutionObservers.h83
-rw-r--r--runtime/neurun/core/include/exec/IExecutor.h72
-rw-r--r--runtime/neurun/core/include/exec/IFunction.h37
-rw-r--r--runtime/neurun/core/include/exec/IODescription.h66
-rw-r--r--runtime/neurun/core/include/exec/NopFunction.h54
-rw-r--r--runtime/neurun/core/include/ir/BackendSet.h40
-rw-r--r--runtime/neurun/core/include/ir/Data.h75
-rw-r--r--runtime/neurun/core/include/ir/DataType.h62
-rw-r--r--runtime/neurun/core/include/ir/Graph.h153
-rw-r--r--runtime/neurun/core/include/ir/Index.h42
-rw-r--r--runtime/neurun/core/include/ir/InternalType.h68
-rw-r--r--runtime/neurun/core/include/ir/Layout.h67
-rw-r--r--runtime/neurun/core/include/ir/LowerInfoMap.h42
-rw-r--r--runtime/neurun/core/include/ir/OpCode.h56
-rw-r--r--runtime/neurun/core/include/ir/OpSequence.h106
-rw-r--r--runtime/neurun/core/include/ir/Operand.h130
-rw-r--r--runtime/neurun/core/include/ir/OperandConstraint.h58
-rw-r--r--runtime/neurun/core/include/ir/OperandIndexMap.h34
-rw-r--r--runtime/neurun/core/include/ir/OperandIndexSequence.h60
-rw-r--r--runtime/neurun/core/include/ir/OperandInfo.h90
-rw-r--r--runtime/neurun/core/include/ir/Operands.h39
-rw-r--r--runtime/neurun/core/include/ir/Operation.h71
-rw-r--r--runtime/neurun/core/include/ir/OperationIndexList.h59
-rw-r--r--runtime/neurun/core/include/ir/OperationIndexMap.h34
-rw-r--r--runtime/neurun/core/include/ir/OperationVisitor.h52
-rw-r--r--runtime/neurun/core/include/ir/Operations.Include.h83
-rw-r--r--runtime/neurun/core/include/ir/Operations.h36
-rw-r--r--runtime/neurun/core/include/ir/Operations.lst86
-rw-r--r--runtime/neurun/core/include/ir/Shape.h84
-rw-r--r--runtime/neurun/core/include/ir/Subgraphs.h87
-rw-r--r--runtime/neurun/core/include/ir/TypeInfo.h59
-rw-r--r--runtime/neurun/core/include/ir/operand/LowerInfo.h93
-rw-r--r--runtime/neurun/core/include/ir/operand/ParentInfo.h77
-rw-r--r--runtime/neurun/core/include/ir/operand/PermuteFactor.h130
-rw-r--r--runtime/neurun/core/include/ir/operation/Abs.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/Add.h62
-rw-r--r--runtime/neurun/core/include/ir/operation/ArgMax.h62
-rw-r--r--runtime/neurun/core/include/ir/operation/AvgPool2D.h69
-rw-r--r--runtime/neurun/core/include/ir/operation/BatchToSpaceND.h50
-rw-r--r--runtime/neurun/core/include/ir/operation/Cast.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/Comparison.h72
-rw-r--r--runtime/neurun/core/include/ir/operation/Concat.h59
-rw-r--r--runtime/neurun/core/include/ir/operation/Conv2D.h68
-rw-r--r--runtime/neurun/core/include/ir/operation/Custom.h66
-rw-r--r--runtime/neurun/core/include/ir/operation/DepthToSpace.h63
-rw-r--r--runtime/neurun/core/include/ir/operation/DepthwiseConv2D.h69
-rw-r--r--runtime/neurun/core/include/ir/operation/Dequantize.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/Div.h62
-rw-r--r--runtime/neurun/core/include/ir/operation/EmbeddingLookup.h50
-rw-r--r--runtime/neurun/core/include/ir/operation/Exp.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/Floor.h51
-rw-r--r--runtime/neurun/core/include/ir/operation/FullyConnected.h66
-rw-r--r--runtime/neurun/core/include/ir/operation/Gather.h65
-rw-r--r--runtime/neurun/core/include/ir/operation/HashtableLookup.h57
-rw-r--r--runtime/neurun/core/include/ir/operation/InstanceNorm.h65
-rw-r--r--runtime/neurun/core/include/ir/operation/L2Normalization.h62
-rw-r--r--runtime/neurun/core/include/ir/operation/L2Pool2D.h68
-rw-r--r--runtime/neurun/core/include/ir/operation/LSTM.h89
-rw-r--r--runtime/neurun/core/include/ir/operation/LocalResponseNormalization.h66
-rw-r--r--runtime/neurun/core/include/ir/operation/LogicalAnd.h50
-rw-r--r--runtime/neurun/core/include/ir/operation/LogicalNot.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/LogicalOr.h50
-rw-r--r--runtime/neurun/core/include/ir/operation/Logistic.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/LowerInfo.h54
-rw-r--r--runtime/neurun/core/include/ir/operation/Max.h50
-rw-r--r--runtime/neurun/core/include/ir/operation/MaxPool2D.h68
-rw-r--r--runtime/neurun/core/include/ir/operation/Mean.h62
-rw-r--r--runtime/neurun/core/include/ir/operation/Min.h50
-rw-r--r--runtime/neurun/core/include/ir/operation/Mul.h62
-rw-r--r--runtime/neurun/core/include/ir/operation/Neg.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/OneHot.h60
-rw-r--r--runtime/neurun/core/include/ir/operation/PReLU.h50
-rw-r--r--runtime/neurun/core/include/ir/operation/Pack.h53
-rw-r--r--runtime/neurun/core/include/ir/operation/Pad.h63
-rw-r--r--runtime/neurun/core/include/ir/operation/Permute.h78
-rw-r--r--runtime/neurun/core/include/ir/operation/RNN.h70
-rw-r--r--runtime/neurun/core/include/ir/operation/RSQRT.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/ReLU.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/ReLU1.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/ReLU6.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/ReduceMax.h65
-rw-r--r--runtime/neurun/core/include/ir/operation/ReduceMin.h65
-rw-r--r--runtime/neurun/core/include/ir/operation/ReduceSum.h63
-rw-r--r--runtime/neurun/core/include/ir/operation/Reshape.h51
-rw-r--r--runtime/neurun/core/include/ir/operation/ResizeBilinear.h64
-rw-r--r--runtime/neurun/core/include/ir/operation/SQRT.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/Slice.h64
-rw-r--r--runtime/neurun/core/include/ir/operation/Softmax.h63
-rw-r--r--runtime/neurun/core/include/ir/operation/SpaceToBatchND.h53
-rw-r--r--runtime/neurun/core/include/ir/operation/SpaceToDepth.h63
-rw-r--r--runtime/neurun/core/include/ir/operation/Split.h59
-rw-r--r--runtime/neurun/core/include/ir/operation/SquaredDifference.h50
-rw-r--r--runtime/neurun/core/include/ir/operation/Squeeze.h62
-rw-r--r--runtime/neurun/core/include/ir/operation/StridedSlice.h69
-rw-r--r--runtime/neurun/core/include/ir/operation/Sub.h62
-rw-r--r--runtime/neurun/core/include/ir/operation/Tanh.h49
-rw-r--r--runtime/neurun/core/include/ir/operation/TopKV2.h69
-rw-r--r--runtime/neurun/core/include/ir/operation/Transpose.h64
-rw-r--r--runtime/neurun/core/include/ir/operation/TransposeConv.h67
-rw-r--r--runtime/neurun/core/include/ir/operation/Unpack.h59
-rw-r--r--runtime/neurun/core/include/util/Config.lst43
-rw-r--r--runtime/neurun/core/include/util/ConfigSource.h55
-rw-r--r--runtime/neurun/core/include/util/Coordinates.h103
-rw-r--r--runtime/neurun/core/include/util/EnvConfigSource.h41
-rw-r--r--runtime/neurun/core/include/util/EventCollectorGlobal.h155
-rw-r--r--runtime/neurun/core/include/util/GeneralConfigSource.h44
-rw-r--r--runtime/neurun/core/include/util/IConfigSource.h46
-rw-r--r--runtime/neurun/core/include/util/ITimer.h59
-rw-r--r--runtime/neurun/core/include/util/Index.h154
-rw-r--r--runtime/neurun/core/include/util/ObjectManager.h144
-rw-r--r--runtime/neurun/core/include/util/Padding.h41
-rw-r--r--runtime/neurun/core/include/util/Set.h166
-rw-r--r--runtime/neurun/core/include/util/ShapeInference.h59
-rw-r--r--runtime/neurun/core/include/util/Utils.h51
-rw-r--r--runtime/neurun/core/include/util/feature/Coordinate4D.h111
-rw-r--r--runtime/neurun/core/include/util/feature/nchw/Reader.h120
-rw-r--r--runtime/neurun/core/include/util/feature/nchw/View.h138
-rw-r--r--runtime/neurun/core/include/util/feature/nhwc/Reader.h121
-rw-r--r--runtime/neurun/core/include/util/feature/nhwc/View.h140
-rw-r--r--runtime/neurun/core/include/util/logging.h63
-rw-r--r--runtime/neurun/core/src/backend/Backend.cc30
-rw-r--r--runtime/neurun/core/src/backend/BackendManager.cc150
-rw-r--r--runtime/neurun/core/src/backend/BackendManager.h82
-rw-r--r--runtime/neurun/core/src/backend/ExecTime.cc133
-rw-r--r--runtime/neurun/core/src/backend/JSONExecTime.cc231
-rw-r--r--runtime/neurun/core/src/compiler/BackendResolver.cc47
-rw-r--r--runtime/neurun/core/src/compiler/BackendResolver.h102
-rw-r--r--runtime/neurun/core/src/compiler/CodeWithInfo.h44
-rw-r--r--runtime/neurun/core/src/compiler/Compiler.cc143
-rw-r--r--runtime/neurun/core/src/compiler/ExecutorFactory.cc379
-rw-r--r--runtime/neurun/core/src/compiler/ExecutorFactory.h52
-rw-r--r--runtime/neurun/core/src/compiler/HEScheduler.cc628
-rw-r--r--runtime/neurun/core/src/compiler/HEScheduler.h175
-rw-r--r--runtime/neurun/core/src/compiler/IScheduler.h38
-rw-r--r--runtime/neurun/core/src/compiler/Linear.cc317
-rw-r--r--runtime/neurun/core/src/compiler/Linear.h81
-rw-r--r--runtime/neurun/core/src/compiler/ManualScheduler.cc142
-rw-r--r--runtime/neurun/core/src/compiler/ManualScheduler.h36
-rw-r--r--runtime/neurun/core/src/compiler/OperandContext.cc45
-rw-r--r--runtime/neurun/core/src/compiler/OperandContext.h60
-rw-r--r--runtime/neurun/core/src/compiler/OperationValidator.cc985
-rw-r--r--runtime/neurun/core/src/compiler/OperationValidator.h86
-rw-r--r--runtime/neurun/core/src/compiler/ParamChecker.cc33
-rw-r--r--runtime/neurun/core/src/compiler/ParamChecker.h73
-rw-r--r--runtime/neurun/core/src/compiler/SubTensorAnalyzer.cc96
-rw-r--r--runtime/neurun/core/src/compiler/SubTensorAnalyzer.h59
-rw-r--r--runtime/neurun/core/src/dumper/dot/DotBuilder.cc83
-rw-r--r--runtime/neurun/core/src/dumper/dot/DotBuilder.h62
-rw-r--r--runtime/neurun/core/src/dumper/dot/DotDumper.cc199
-rw-r--r--runtime/neurun/core/src/dumper/dot/DotDumper.h60
-rw-r--r--runtime/neurun/core/src/dumper/dot/DotSubgraphInfo.cc56
-rw-r--r--runtime/neurun/core/src/dumper/dot/DotSubgraphInfo.h59
-rw-r--r--runtime/neurun/core/src/dumper/dot/Node.cc56
-rw-r--r--runtime/neurun/core/src/dumper/dot/Node.h127
-rw-r--r--runtime/neurun/core/src/dumper/dot/OperandNode.cc60
-rw-r--r--runtime/neurun/core/src/dumper/dot/OperandNode.h79
-rw-r--r--runtime/neurun/core/src/dumper/dot/OperationNode.cc46
-rw-r--r--runtime/neurun/core/src/dumper/dot/OperationNode.h62
-rw-r--r--runtime/neurun/core/src/exec/DataflowExecutor.cc176
-rw-r--r--runtime/neurun/core/src/exec/DataflowExecutor.h97
-rw-r--r--runtime/neurun/core/src/exec/Execution.cc135
-rw-r--r--runtime/neurun/core/src/exec/ExecutionObservee.cc64
-rw-r--r--runtime/neurun/core/src/exec/ExecutionObservee.h56
-rw-r--r--runtime/neurun/core/src/exec/ExecutionObservers.cc130
-rw-r--r--runtime/neurun/core/src/exec/ExecutorBase.cc145
-rw-r--r--runtime/neurun/core/src/exec/ExecutorBase.h127
-rw-r--r--runtime/neurun/core/src/exec/FunctionSequence.cc62
-rw-r--r--runtime/neurun/core/src/exec/FunctionSequence.h56
-rw-r--r--runtime/neurun/core/src/exec/Job.cc33
-rw-r--r--runtime/neurun/core/src/exec/Job.h69
-rw-r--r--runtime/neurun/core/src/exec/LinearExecutor.cc39
-rw-r--r--runtime/neurun/core/src/exec/LinearExecutor.h64
-rw-r--r--runtime/neurun/core/src/exec/ParallelExecutor.cc147
-rw-r--r--runtime/neurun/core/src/exec/ParallelExecutor.h69
-rw-r--r--runtime/neurun/core/src/exec/ParallelScheduler.cc55
-rw-r--r--runtime/neurun/core/src/exec/ParallelScheduler.h60
-rw-r--r--runtime/neurun/core/src/exec/Sink.h205
-rw-r--r--runtime/neurun/core/src/exec/Source.h211
-rw-r--r--runtime/neurun/core/src/exec/ThreadPool.cc65
-rw-r--r--runtime/neurun/core/src/exec/ThreadPool.h73
-rw-r--r--runtime/neurun/core/src/exec/WorkQueue.cc104
-rw-r--r--runtime/neurun/core/src/exec/WorkQueue.h87
-rw-r--r--runtime/neurun/core/src/exec/interp/Buffer.h94
-rw-r--r--runtime/neurun/core/src/exec/interp/ExecEnv.h165
-rw-r--r--runtime/neurun/core/src/exec/interp/ExecManager.cc125
-rw-r--r--runtime/neurun/core/src/exec/interp/ExecManager.h71
-rw-r--r--runtime/neurun/core/src/exec/interp/Interpreter.cc210
-rw-r--r--runtime/neurun/core/src/exec/interp/Interpreter.h67
-rw-r--r--runtime/neurun/core/src/exec/interp/Registration.h63
-rw-r--r--runtime/neurun/core/src/exec/interp/Tensor.cc59
-rw-r--r--runtime/neurun/core/src/exec/interp/Tensor.h180
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/AvgPool2D.cc129
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/BinaryArithmeticOps.cc202
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/Concat.cc150
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/Conv2D.cc152
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/DepthwiseConv.cc159
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/FullyConnected.cc137
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/Gather.cc141
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/InstanceNorm.cc124
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/Logistic.cc102
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/MaxPool2D.cc128
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/OperationUtil.h177
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/Pad.cc109
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/Reshape.cc66
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/SoftMax.cc163
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/TransposeConv.cc145
-rw-r--r--runtime/neurun/core/src/exec/interp/operations/UnaryActivations.cc156
-rw-r--r--runtime/neurun/core/src/ir/Graph.cc551
-rw-r--r--runtime/neurun/core/src/ir/GraphIterator.cc84
-rw-r--r--runtime/neurun/core/src/ir/GraphIterator.h74
-rw-r--r--runtime/neurun/core/src/ir/LayoutSet.cc66
-rw-r--r--runtime/neurun/core/src/ir/LayoutSet.h58
-rw-r--r--runtime/neurun/core/src/ir/OpCode.cc37
-rw-r--r--runtime/neurun/core/src/ir/OpSequence.cc83
-rw-r--r--runtime/neurun/core/src/ir/Operand.cc70
-rw-r--r--runtime/neurun/core/src/ir/OperandIndexSequence.cc58
-rw-r--r--runtime/neurun/core/src/ir/Operation.cc55
-rw-r--r--runtime/neurun/core/src/ir/OperationIndexList.cc37
-rw-r--r--runtime/neurun/core/src/ir/Shape.cc85
-rw-r--r--runtime/neurun/core/src/ir/Subgraphs.cc87
-rw-r--r--runtime/neurun/core/src/ir/TypeInfo.cc47
-rw-r--r--runtime/neurun/core/src/ir/dumper/Dumper.cc633
-rw-r--r--runtime/neurun/core/src/ir/dumper/Dumper.h102
-rw-r--r--runtime/neurun/core/src/ir/operand/Shape4DConvert.h57
-rw-r--r--runtime/neurun/core/src/ir/operation/Abs.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/Add.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/ArgMax.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/AvgPool2D.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/BatchToSpaceND.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Cast.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/Comparison.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Concat.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Conv2D.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Custom.cc46
-rw-r--r--runtime/neurun/core/src/ir/operation/DepthToSpace.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/DepthwiseConv2D.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Dequantize.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/Div.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/EmbeddingLookup.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Exp.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/Floor.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/FullyConnected.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Gather.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/HashtableLookup.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/InstanceNorm.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/L2Normalization.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/L2Pool2D.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/LSTM.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/LocalResponseNormalization.cc41
-rw-r--r--runtime/neurun/core/src/ir/operation/LogicalAnd.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/LogicalNot.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/LogicalOr.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/Logistic.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/LowerInfo.cc34
-rw-r--r--runtime/neurun/core/src/ir/operation/Max.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/MaxPool2D.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Mean.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Min.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/Mul.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Neg.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/OneHot.cc37
-rw-r--r--runtime/neurun/core/src/ir/operation/PReLU.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/Pack.cc33
-rw-r--r--runtime/neurun/core/src/ir/operation/Pad.cc38
-rw-r--r--runtime/neurun/core/src/ir/operation/Permute.cc44
-rw-r--r--runtime/neurun/core/src/ir/operation/RNN.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/RSQRT.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/ReLU.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/ReLU1.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/ReLU6.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/ReduceMax.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/ReduceMin.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/ReduceSum.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Reshape.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/ResizeBilinear.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/SQRT.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/Slice.cc37
-rw-r--r--runtime/neurun/core/src/ir/operation/Softmax.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/SpaceToBatchND.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/SpaceToDepth.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Split.cc33
-rw-r--r--runtime/neurun/core/src/ir/operation/SquaredDifference.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Squeeze.cc37
-rw-r--r--runtime/neurun/core/src/ir/operation/StridedSlice.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Sub.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Tanh.cc39
-rw-r--r--runtime/neurun/core/src/ir/operation/TopKV2.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Transpose.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/TransposeConv.cc40
-rw-r--r--runtime/neurun/core/src/ir/operation/Unpack.cc33
-rw-r--r--runtime/neurun/core/src/ir/pass/ConstantInsertionPass.cc104
-rw-r--r--runtime/neurun/core/src/ir/pass/ConstantInsertionPass.h75
-rw-r--r--runtime/neurun/core/src/ir/pass/OperandPass.cc36
-rw-r--r--runtime/neurun/core/src/ir/pass/OperandPass.h53
-rw-r--r--runtime/neurun/core/src/ir/pass/OperationPass.cc38
-rw-r--r--runtime/neurun/core/src/ir/pass/OperationPass.h76
-rw-r--r--runtime/neurun/core/src/ir/pass/Pass.h55
-rw-r--r--runtime/neurun/core/src/ir/pass/PermutationEliminationPass.cc195
-rw-r--r--runtime/neurun/core/src/ir/pass/PermutationEliminationPass.h86
-rw-r--r--runtime/neurun/core/src/ir/pass/PermutationInsertionPass.cc209
-rw-r--r--runtime/neurun/core/src/ir/pass/PermutationInsertionPass.h59
-rw-r--r--runtime/neurun/core/src/ir/pass/PermutationOperationPass.cc230
-rw-r--r--runtime/neurun/core/src/ir/pass/PermutationOperationPass.h54
-rw-r--r--runtime/neurun/core/src/ir/verifier/Verifier.cc96
-rw-r--r--runtime/neurun/core/src/ir/verifier/Verifier.h68
-rw-r--r--runtime/neurun/core/src/library_info.cc17
-rw-r--r--runtime/neurun/core/src/util/ConfigSource.cc116
-rw-r--r--runtime/neurun/core/src/util/EnvConfigSource.cc40
-rw-r--r--runtime/neurun/core/src/util/EventCollectorGlobal.cc86
-rw-r--r--runtime/neurun/core/src/util/GeneralConfigSource.cc45
-rw-r--r--runtime/neurun/core/src/util/Padding.cc119
-rw-r--r--runtime/neurun/core/src/util/ShapeInference.cc200
-rw-r--r--runtime/neurun/core/src/util/Utils.cc68
-rw-r--r--runtime/neurun/core/src/util/logging.cc7
332 files changed, 27440 insertions, 0 deletions
diff --git a/runtime/neurun/core/CMakeLists.txt b/runtime/neurun/core/CMakeLists.txt
new file mode 100644
index 000000000..422d292bb
--- /dev/null
+++ b/runtime/neurun/core/CMakeLists.txt
@@ -0,0 +1,18 @@
+file(GLOB_RECURSE SOURCES "src/*.cc")
+
+add_library(neurun_core SHARED ${SOURCES})
+set_target_properties(neurun_core PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(neurun_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_include_directories(neurun_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
+target_link_libraries(neurun_core PUBLIC nnfw_lib_misc)
+target_link_libraries(neurun_core PUBLIC nnfw_lib_cpp14)
+target_link_libraries(neurun_core PRIVATE nnfw_lib_cker)
+target_link_libraries(neurun_core PRIVATE nnfw_common)
+target_link_libraries(neurun_core PRIVATE nnfw_coverage)
+target_link_libraries(neurun_core PRIVATE dl ${LIB_PTHREAD})
+
+if(ENVVAR_NEURUN_CONFIG)
+ target_compile_definitions(neurun_core PRIVATE ENVVAR_FOR_DEFAULT_CONFIG)
+endif(ENVVAR_NEURUN_CONFIG)
+
+install(TARGETS neurun_core DESTINATION lib)
diff --git a/runtime/neurun/core/include/backend/Backend.h b/runtime/neurun/core/include/backend/Backend.h
new file mode 100644
index 000000000..9c4484fca
--- /dev/null
+++ b/runtime/neurun/core/include/backend/Backend.h
@@ -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.
+ */
+
+#ifndef __NEURUN_BACKEND_BACKEND_H__
+#define __NEURUN_BACKEND_BACKEND_H__
+
+#include <memory>
+
+#include "ir/Operands.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+namespace custom
+{
+class IKernelBuilder;
+}
+
+class Backend;
+struct IConfig;
+class IConstantInitializer;
+class IKernelGenerator;
+class IShapeFixer;
+class ITensorRegister;
+struct ITensorBuilder;
+
+class BackendContext
+{
+public:
+ const Backend *backend;
+ std::shared_ptr<ITensorBuilder> tensor_builder;
+ std::shared_ptr<IConstantInitializer> constant_initializer;
+ std::shared_ptr<IKernelGenerator> kernel_gen;
+ std::shared_ptr<IShapeFixer> shape_fixer;
+ std::shared_ptr<ITensorRegister> tensor_register;
+};
+
+class Backend
+{
+public:
+ virtual ~Backend() = default;
+ virtual std::shared_ptr<neurun::backend::IConfig> config() const = 0;
+
+ virtual std::unique_ptr<BackendContext>
+ newContext(const ir::Operands &operands,
+ const std::shared_ptr<backend::custom::IKernelBuilder> &kb) const = 0;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_BACKEND_H__
diff --git a/runtime/neurun/core/include/backend/CustomKernelBuilder.h b/runtime/neurun/core/include/backend/CustomKernelBuilder.h
new file mode 100644
index 000000000..848ebd595
--- /dev/null
+++ b/runtime/neurun/core/include/backend/CustomKernelBuilder.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 __NEURUN_BACKEND_CUSTOM_KERNEL_BUILDER_H__
+#define __NEURUN_BACKEND_CUSTOM_KERNEL_BUILDER_H__
+
+#include "exec/IFunction.h"
+
+#include "misc/tensor/Shape.h"
+#include "ir/DataType.h"
+
+#include <vector>
+#include <memory>
+
+namespace neurun
+{
+namespace backend
+{
+namespace custom
+{
+
+using Shape = nnfw::misc::tensor::Shape;
+
+struct TypeInfo
+{
+ Shape shape;
+ ir::DataType dtype;
+};
+
+struct CustomKernelConfigParams
+{
+ std::vector<void *> input_allocations;
+ std::vector<TypeInfo> input_types;
+
+ std::vector<void *> output_allocations;
+ 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 neurun
+
+#endif // __NEURUN_BACKEND_CUSTOM_KERNEL_BUILDER_H__
diff --git a/runtime/neurun/core/include/backend/ExecTime.h b/runtime/neurun/core/include/backend/ExecTime.h
new file mode 100644
index 000000000..4eaf49fab
--- /dev/null
+++ b/runtime/neurun/core/include/backend/ExecTime.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_BACKEND_EXEC_TIME_H__
+#define __NEURUN_BACKEND_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 neurun
+{
+namespace backend
+{
+class ExecTime
+{
+public:
+ explicit ExecTime(const std::vector<const 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, 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, 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 *from_backend, const 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 *from_backend, const 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 backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_EXEC_TIME_H__
diff --git a/runtime/neurun/core/include/backend/IConfig.h b/runtime/neurun/core/include/backend/IConfig.h
new file mode 100644
index 000000000..855f31ef9
--- /dev/null
+++ b/runtime/neurun/core/include/backend/IConfig.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 __NEURUN_BACKEND_ICONFIG_H__
+#define __NEURUN_BACKEND_ICONFIG_H__
+
+#include "util/ITimer.h"
+#include <memory>
+#include <string>
+
+namespace neurun
+{
+namespace backend
+{
+
+struct IConfig
+{
+ virtual ~IConfig() = default;
+
+ virtual std::string id() = 0;
+ virtual bool initialize() = 0;
+ // Support permute kernel
+ virtual bool SupportPermutation() = 0;
+ // Support subtensor allocation
+ virtual bool SupportSubTensorAlloc() = 0;
+
+ // Timer is used for backend profiling. In case of default (nullptr) timer profiler won't work.
+ virtual std::unique_ptr<util::ITimer> timer() { return nullptr; }
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ICONFIG_H__
diff --git a/runtime/neurun/core/include/backend/IConstantInitializer.h b/runtime/neurun/core/include/backend/IConstantInitializer.h
new file mode 100644
index 000000000..3cc770b29
--- /dev/null
+++ b/runtime/neurun/core/include/backend/IConstantInitializer.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_BACKEND_ICONSTANT_INITIALIZER_H__
+#define __NEURUN_BACKEND_ICONSTANT_INITIALIZER_H__
+
+#include <unordered_map>
+#include <functional>
+
+#include "ITensorBuilder.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"
+#include "util/Utils.h"
+
+namespace
+{
+template <typename T>
+static void Init(const neurun::ir::Operand &model_obj, neurun::backend::operand::ITensor &obj,
+ const bool copy,
+ const neurun::ir::Layout frontend_layout = neurun::ir::Layout::UNKNOWN)
+{
+ const auto shape = model_obj.shape();
+ auto base = reinterpret_cast<const T *>(model_obj.data().base());
+
+ obj.access([&](::neurun::backend::operand::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)
+ {
+ neurun::util::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)
+ {
+ neurun::util::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)
+ {
+ neurun::util::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 = neurun::util::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 neurun::ir::Operand &model_obj, neurun::backend::operand::ITensor &obj)
+{
+ Init<T>(model_obj, obj, true);
+}
+
+template <typename T>
+void permuteInit(const neurun::ir::Operand &model_obj, neurun::backend::operand::ITensor &obj,
+ const neurun::ir::Layout frontend_layout)
+{
+ const bool copy = frontend_layout == obj.layout();
+ Init<T>(model_obj, obj, copy, frontend_layout);
+}
+
+} // namespace
+
+namespace neurun
+{
+namespace backend
+{
+
+class IConstantInitializer : ir::OperationVisitor
+{
+public:
+ virtual ~IConstantInitializer() = default;
+
+public:
+ void run()
+ {
+ assert(tensor_builder().get());
+ 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_builder()->tensorAt(ind);
+ fn(model_obj, *tensor_obj);
+ VERBOSE(FillOperandData) << "Fill data for operand " << ind.value() << std::endl;
+ }
+ _init_map.clear();
+ }
+
+public:
+ using Initializer = std::function<void(const ir::Operand &, backend::operand::ITensor &)>;
+
+ void generate(const ir::OpSequence &subg, const ir::Operands &operands)
+ {
+ _current_subg_layout = subg.getLayout();
+ subg.accept(*this);
+ for (const auto &e : subg.operations())
+ {
+ for (const auto &ind : e.node->getInputs())
+ {
+ const auto &obj = operands.at(ind);
+ if (obj.isConstant() && !exist(ind))
+ {
+ registerPermuteInitializer(ind, obj);
+ }
+ }
+ }
+ }
+
+protected:
+ using OperationVisitor::visit;
+
+protected:
+ virtual const ir::Operands &operands() const = 0;
+ virtual std::shared_ptr<ITensorBuilder> tensor_builder() const = 0;
+
+protected:
+ void 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::QUANT8_ASYMM:
+ _init_map[index] = copyInit<uint8_t>;
+ break;
+ case DataType::QUANT8_SYMM:
+ _init_map[index] = copyInit<int8_t>;
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+ }
+
+protected:
+ void 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_subg_layout);
+ break;
+ case DataType::INT32:
+ _init_map[index] = std::bind(permuteInit<int32_t>, _1, _2, _current_subg_layout);
+ break;
+ case DataType::UINT32:
+ _init_map[index] = std::bind(permuteInit<uint32_t>, _1, _2, _current_subg_layout);
+ break;
+ case DataType::BOOL8:
+ case DataType::QUANT8_ASYMM:
+ _init_map[index] = std::bind(permuteInit<uint8_t>, _1, _2, _current_subg_layout);
+ break;
+ case DataType::QUANT8_SYMM:
+ _init_map[index] = std::bind(permuteInit<int8_t>, _1, _2, _current_subg_layout);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+ }
+
+private:
+ bool exist(const ir::OperandIndex &ind) { return _init_map.find(ind) != _init_map.end(); }
+
+protected:
+ std::unordered_map<ir::OperandIndex, Initializer> _init_map;
+ ir::Layout _current_subg_layout;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ICONSTANT_INITIALIZER_H__
diff --git a/runtime/neurun/core/include/backend/IKernelGenerator.h b/runtime/neurun/core/include/backend/IKernelGenerator.h
new file mode 100644
index 000000000..4540e81d2
--- /dev/null
+++ b/runtime/neurun/core/include/backend/IKernelGenerator.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 __NEURUN_BACKEND_IKERNEL_GENERATOR_H__
+#define __NEURUN_BACKEND_IKERNEL_GENERATOR_H__
+
+#include <memory>
+#include <functional>
+
+#include "ITensorBuilder.h"
+#include "compiler/IExecutionBuilder.h"
+#include "ir/OperationVisitor.h"
+#include "ir/OpSequence.h"
+#include "cpp14/memory.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+class IKernelGenerator : public ir::OperationVisitor
+{
+public:
+ virtual ~IKernelGenerator() = default;
+
+ void generate(const ir::OpSequence &subg, neurun::compiler::IExecutionBuilder *executionBuilder)
+ {
+ _execution_builder = executionBuilder;
+ subg.accept(*this);
+ }
+
+protected:
+ using OperationVisitor::visit;
+
+#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:
+ neurun::compiler::IExecutionBuilder *_execution_builder;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_IKERNEL_GENERATOR_H__
diff --git a/runtime/neurun/core/include/backend/IMemoryManager.h b/runtime/neurun/core/include/backend/IMemoryManager.h
new file mode 100644
index 000000000..b06bab872
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_BACKEND_IMEMORY_MANAGER_H__
+#define __NEURUN_BACKEND_IMEMORY_MANAGER_H__
+
+namespace neurun
+{
+namespace backend
+{
+
+struct IMemoryManager
+{
+ virtual ~IMemoryManager() = default;
+
+ virtual void allocate(void) = 0;
+ virtual void deallocate(void) = 0;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#include <unordered_set>
+#include <memory>
+
+namespace neurun
+{
+namespace backend
+{
+
+using MemoryManagerSet = std::unordered_set<std::unique_ptr<backend::IMemoryManager>>;
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_IMEMORY_MANAGER_H__
diff --git a/runtime/neurun/core/include/backend/IShapeFixer.h b/runtime/neurun/core/include/backend/IShapeFixer.h
new file mode 100644
index 000000000..8168e2a11
--- /dev/null
+++ b/runtime/neurun/core/include/backend/IShapeFixer.h
@@ -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.
+ */
+
+#ifndef __NEURUN_BACKEND_ISHAPE_FIXER_H__
+#define __NEURUN_BACKEND_ISHAPE_FIXER_H__
+
+#include <memory>
+#include <functional>
+
+#include "ir/LowerInfoMap.h"
+#include "ITensorBuilder.h"
+#include "ir/OperationVisitor.h"
+#include "ir/OpSequence.h"
+#include "cpp14/memory.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+class IShapeFixer : public ir::OperationVisitor
+{
+public:
+ virtual ~IShapeFixer() = default;
+
+protected:
+#define OP(InternalName) \
+ void visit(const ir::operation::InternalName &) override \
+ { \
+ throw std::runtime_error("ShapeFixer: NYI for operation '" #InternalName "'"); \
+ }
+#include "ir/Operations.lst"
+#undef OP
+
+public:
+ void fix(const ir::OpSequence &op_seq) { op_seq.accept(*this); };
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ISHAPE_FIXER_H__
diff --git a/runtime/neurun/core/include/backend/ITensorBuilder.h b/runtime/neurun/core/include/backend/ITensorBuilder.h
new file mode 100644
index 000000000..5eb4ab2d8
--- /dev/null
+++ b/runtime/neurun/core/include/backend/ITensorBuilder.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_BACKEND_ITENSOR_BUILDER_H__
+#define __NEURUN_BACKEND_ITENSOR_BUILDER_H__
+
+#include <map>
+
+#include "ir/Index.h"
+#include "ir/OperandInfo.h"
+#include "ir/Operation.h"
+#include "ir/Layout.h"
+#include "operand/ITensor.h"
+#include "compiler/SubTensorInfo.h"
+#include "ITensorManager.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+struct ITensorBuilder
+{
+ using IterateFunction = std::function<void(const ir::OperandIndex &)>;
+
+ virtual ~ITensorBuilder(void) = default;
+
+ // TODO Merge registerTensorInfo and registerSubTensorInfo using abstraction by internal class
+ /**
+ * @brief Register tensor information to allocate on backend
+ */
+ virtual void registerTensorInfo(const ir::OperandIndex &, const ir::OperandInfo &,
+ ir::Layout backend_layout, bool as_const) = 0;
+ /**
+ * @brief Register subtensor information to allocate on backend
+ */
+ virtual void registerSubTensorInfo(const ir::OperandIndex &, const compiler::SubTensorInfo &) = 0;
+
+ virtual void notifyFirstUse(const ir::OperandIndex &) = 0;
+ virtual void notifyLastUse(const ir::OperandIndex &) = 0;
+
+ virtual bool isRegistered(const ir::OperandIndex &) const = 0;
+
+ virtual void prepare(void) = 0;
+ virtual void allocateConsts() = 0;
+ virtual void allocateNonconsts() = 0;
+ virtual void postFunctionPrepare() = 0;
+ virtual void finalize() = 0;
+
+ virtual std::shared_ptr<::neurun::backend::operand::ITensor>
+ tensorAt(const ir::OperandIndex &ind) = 0;
+ virtual void iterate(const IterateFunction &fn) = 0;
+
+ virtual void preVisit(const ir::Operation &) = 0;
+ virtual void postVisit(const ir::Operation &) = 0;
+
+ virtual std::unique_ptr<ITensorManager> releaseTensorManager(void) = 0;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#include <unordered_set>
+#include <memory>
+
+namespace neurun
+{
+namespace backend
+{
+
+using TensorBuilderSet = std::unordered_set<std::shared_ptr<backend::ITensorBuilder>>;
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ITENSOR_BUILDER_H__
diff --git a/runtime/neurun/core/include/backend/ITensorManager.h b/runtime/neurun/core/include/backend/ITensorManager.h
new file mode 100644
index 000000000..74506ef59
--- /dev/null
+++ b/runtime/neurun/core/include/backend/ITensorManager.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 __NEURUN_BACKEND_ITENSOR_MANAGER_H__
+#define __NEURUN_BACKEND_ITENSOR_MANAGER_H__
+
+namespace neurun
+{
+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
+ */
+struct ITensorManager
+{
+ virtual ~ITensorManager() = default;
+
+ virtual void allocateConsts(void) = 0;
+ virtual void allocateNonconsts(void) = 0;
+ virtual void deallocateConsts(void) = 0;
+ virtual void deallocateNonconsts(void) = 0;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#include <unordered_set>
+#include <memory>
+
+namespace neurun
+{
+namespace backend
+{
+
+using TensorManagerSet = std::unordered_set<std::unique_ptr<backend::ITensorManager>>;
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ITENSOR_MANAGER_H__
diff --git a/runtime/neurun/core/include/backend/ITensorRegister.h b/runtime/neurun/core/include/backend/ITensorRegister.h
new file mode 100644
index 000000000..9e554ab77
--- /dev/null
+++ b/runtime/neurun/core/include/backend/ITensorRegister.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_BACKEND_ITENSOR_REGISTER_H__
+#define __NEURUN_BACKEND_ITENSOR_REGISTER_H__
+
+#include "compiler/SubTensorInfo.h"
+#include "ir/LowerInfoMap.h"
+#include "ir/operand/ParentInfo.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
+{
+
+neurun::ir::Shape permuteTensorShape(const neurun::ir::Shape &shape,
+ neurun::ir::Layout frontend_layout,
+ neurun::ir::Layout backend_layout)
+{
+ assert(shape.rank() <= 4);
+ neurun::ir::Shape backend_shape{shape};
+ if (shape.rank() == 4 && frontend_layout == neurun::ir::Layout::NHWC &&
+ backend_layout == neurun::ir::Layout::NCHW)
+ {
+ 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 == neurun::ir::Layout::NCHW &&
+ backend_layout == neurun::ir::Layout::NHWC)
+ {
+ 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
+
+namespace neurun
+{
+namespace backend
+{
+
+class ITensorRegister : public ir::OperationVisitor
+{
+public:
+ virtual ~ITensorRegister() = default;
+
+public:
+ void registerTensors(const ir::OpSequence &subg, const ir::LowerInfoMap *lower_info_map)
+ {
+ _current_subg_layout = subg.getLayout();
+ _lower_info_map = lower_info_map;
+ assert(_lower_info_map != nullptr);
+ assert(tensor_builder().get() != nullptr);
+ subg.accept(*this);
+ }
+
+protected:
+ virtual const ir::Operands &operands() const = 0;
+ virtual std::shared_ptr<ITensorBuilder> tensor_builder() const = 0;
+ virtual bool supportSubTensor() const = 0;
+
+protected:
+#define OP(InternalName) \
+ void visit(const ir::operation::InternalName &node) override \
+ { \
+ ir::OperandIndexSequence indices{node.getInputs()}; \
+ indices.append(node.getOutputs()); \
+ for (const auto &index : indices) \
+ { \
+ defaultRegisterTensorInfo(index); \
+ } \
+ }
+#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);
+ if (supportSubTensor() && obj.parent_info() != nullptr)
+ {
+ tensor_builder()->registerSubTensorInfo(
+ index, generateSubTensorInfo(obj, frontend_layout, backend_layout));
+ }
+ else
+ {
+ ir::OperandInfo backend_info{permuteTensorShape(obj.shape(), frontend_layout, backend_layout),
+ obj.typeInfo()};
+ tensor_builder()->registerTensorInfo(index, backend_info, backend_layout, obj.isConstant());
+ }
+ }
+
+protected:
+ ir::Layout frontendLayout() const { return _current_subg_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:
+ compiler::SubTensorInfo generateSubTensorInfo(const ir::Operand &obj, ir::Layout frontend_layout,
+ ir::Layout backend_layout) const
+ {
+ assert(obj.shape().rank() <= 4);
+ const auto parent_index = obj.parent_info()->parent();
+ auto shape = obj.shape();
+ auto offset = obj.parent_info()->offset();
+ if (operands().at(parent_index).shape().rank() == 4 && frontend_layout == ir::Layout::NHWC &&
+ backend_layout == ir::Layout::NCHW)
+ {
+ shape.extendRank(4);
+ offset = {offset[0], offset[3], offset[1], offset[2]};
+ }
+ else if (operands().at(parent_index).shape().rank() == 4 &&
+ frontend_layout == ir::Layout::NHWC && backend_layout == ir::Layout::NCHW)
+ {
+ shape.extendRank(4);
+ offset = {offset[0], offset[2], offset[3], offset[1]};
+ }
+ ir::Operand subtensor_obj{permuteTensorShape(shape, frontend_layout, backend_layout),
+ obj.typeInfo()};
+ subtensor_obj.parent_info(
+ nnfw::cpp14::make_unique<ir::operand::ParentInfo>(parent_index, offset));
+ return compiler::SubTensorInfo{subtensor_obj};
+ }
+
+private:
+ ir::Layout _current_subg_layout;
+ const ir::LowerInfoMap *_lower_info_map{nullptr};
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ITENSOR_REGISTER_H__
diff --git a/runtime/neurun/core/include/backend/JSONExecTime.h b/runtime/neurun/core/include/backend/JSONExecTime.h
new file mode 100644
index 000000000..84505e10f
--- /dev/null
+++ b/runtime/neurun/core/include/backend/JSONExecTime.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 __NEURUN_BACKEND_JSON_EXEC_TIME_H__
+#define __NEURUN_BACKEND_JSON_EXEC_TIME_H__
+
+#include <fstream>
+#include <unordered_map>
+#include <map>
+#include <vector>
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+/**
+ * @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 *,
+ 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 *> &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 *> _backends;
+ std::unordered_map<
+ const 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 backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_JSON_EXEC_TIME_H__
diff --git a/runtime/neurun/core/include/backend/operand/ITensor.h b/runtime/neurun/core/include/backend/operand/ITensor.h
new file mode 100644
index 000000000..c278b01a0
--- /dev/null
+++ b/runtime/neurun/core/include/backend/operand/ITensor.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 __NEURUN_BACKEND_OPERAND_I_TENSOR_H__
+#define __NEURUN_BACKEND_OPERAND_I_TENSOR_H__
+
+#include <cstring>
+#include <cstdint>
+#include <functional>
+
+#include "ir/Layout.h"
+#include "util/Coordinates.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace operand
+{
+
+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 neurun::util::Coordinates &coords) const = 0;
+ virtual ir::Layout layout() const = 0;
+ virtual bool has_padding() const = 0;
+ virtual void access(const std::function<void(ITensor &tensor)> &fn) = 0;
+};
+
+} // namespace operand
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_OPERAND_I_TENSOR_H__
diff --git a/runtime/neurun/core/include/compiler/Compiler.h b/runtime/neurun/core/include/compiler/Compiler.h
new file mode 100644
index 000000000..797fc77ad
--- /dev/null
+++ b/runtime/neurun/core/include/compiler/Compiler.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __NEURUN_COMPILER_COMPILE_H_
+#define __NEURUN_COMPILER_COMPILE_H_
+
+#include "ir/Graph.h"
+#include "exec/IExecutor.h"
+
+namespace neurun
+{
+
+namespace compiler
+{
+
+enum class State
+{
+ CREATED, // Before compilation
+ STARTED, // Compile is started
+ LOWERED, // Backend is decided
+ COMPILED // Success compilation
+};
+
+/**
+ * @brief Class to compile graph model
+ */
+class Compiler
+{
+public:
+ /**
+ * @brief Construct a new Compiler object
+ * @param[in] model Graph model
+ */
+ Compiler(const std::shared_ptr<ir::Graph> &graph)
+ : _graph{graph}, _executor{nullptr}, _state{State::CREATED}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Run compilation. Compilation result will be saved in _plan
+ */
+ void compile(void);
+ /**
+ * @brief Pass plan reference
+ * @param[out] plan Plan reference to return\n
+ * Set nullptr if compile is not run yet
+ */
+ void release(std::shared_ptr<exec::IExecutor> &executor) { executor = _executor; }
+
+ void state(State state) { _state = state; }
+ 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();
+
+private:
+ std::shared_ptr<ir::Graph> _graph;
+ std::shared_ptr<exec::IExecutor> _executor;
+ State _state;
+};
+
+} // namespace compiler
+
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_COMPILE_H_
diff --git a/runtime/neurun/core/include/compiler/IExecutionBuilder.h b/runtime/neurun/core/include/compiler/IExecutionBuilder.h
new file mode 100644
index 000000000..c5a06fec0
--- /dev/null
+++ b/runtime/neurun/core/include/compiler/IExecutionBuilder.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_COMPILER_I_EXECUTION_BUILDER_H__
+#define __NEURUN_COMPILER_I_EXECUTION_BUILDER_H__
+
+#include <memory>
+
+#include "exec/IFunction.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+struct IExecutionBuilder
+{
+ virtual ~IExecutionBuilder() = default;
+
+ virtual void append(std::unique_ptr<::neurun::exec::IFunction> &&f) = 0;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_I_EXECUTION_BUILDER_H__
diff --git a/runtime/neurun/core/include/compiler/SubTensorInfo.h b/runtime/neurun/core/include/compiler/SubTensorInfo.h
new file mode 100644
index 000000000..18cab466b
--- /dev/null
+++ b/runtime/neurun/core/include/compiler/SubTensorInfo.h
@@ -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.
+ */
+
+/**
+ * @file SubTensorInfo.h
+ * @brief This file contains SubTensorInfo to represent subsumption between tensors
+ * for backend tensor allocation
+ */
+#ifndef __NEURUN_COMPILER_SUBTENSOR_INFO_H__
+#define __NEURUN_COMPILER_SUBTENSOR_INFO_H__
+
+#include "ir/Operand.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+/**
+ * @brief Class to represent information of subtensor
+ */
+class SubTensorInfo
+{
+public:
+ SubTensorInfo() = delete;
+
+ /**
+ * @brief Construct a new SubTensorInfo object
+ * @param[in] obj SubTensor object
+ */
+ SubTensorInfo(const ir::Operand &obj)
+ : _parent{obj.parent_info()->parent()}, _shape{obj.shape()}, _type{obj.typeInfo()},
+ _offset{obj.parent_info()->offset()}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return parent tensor index
+ * @return Parent tensor index
+ */
+ const ir::OperandIndex parent(void) const { return _parent; }
+ /**
+ * @brief Return tensor shape
+ * @return Tensor shape
+ */
+ const ir::Shape &shape(void) const { return _shape; }
+ /**
+ * @brief Return tensor type
+ * @return Tensor type
+ */
+ const ir::TypeInfo &type(void) const { return _type; }
+ /**
+ * @brief Return tensor's offset in parent tensor
+ * @return Tensor offset
+ */
+ const neurun::util::Coordinates offset(void) const { return _offset; }
+
+private:
+ const ir::OperandIndex _parent;
+ const ir::Shape _shape;
+ const ir::TypeInfo _type;
+ const neurun::util::Coordinates _offset;
+};
+
+} // compiler
+} // neurun
+
+#endif // __NEURUN_COMPILER_SUBTENSOR_INFO_H__
diff --git a/runtime/neurun/core/include/exec/Execution.h b/runtime/neurun/core/include/exec/Execution.h
new file mode 100644
index 000000000..7304f8aab
--- /dev/null
+++ b/runtime/neurun/core/include/exec/Execution.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __NEURUN_EXEC_EXECUTION_H__
+#define __NEURUN_EXEC_EXECUTION_H__
+
+#include "ir/Layout.h"
+#include "exec/IExecutor.h"
+#include "IODescription.h"
+
+#include <thread>
+
+namespace neurun
+{
+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<IExecutor> &executor);
+
+public:
+ /**
+ * @brief Returns graph object
+ * @return Graph object
+ */
+ const ir::Graph &graph() const { return _executor->graph(); }
+ /**
+ * @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;
+
+private:
+ const std::shared_ptr<IExecutor> _executor;
+ IODescription _io_desc;
+ std::unique_ptr<std::thread> _exec_thread;
+ bool finished{false};
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_EXECUTION_H__
diff --git a/runtime/neurun/core/include/exec/ExecutionObservers.h b/runtime/neurun/core/include/exec/ExecutionObservers.h
new file mode 100644
index 000000000..ca658c706
--- /dev/null
+++ b/runtime/neurun/core/include/exec/ExecutionObservers.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_EXEC_OBSREVERS_H__
+#define __NEURUN_EXEC_OBSREVERS_H__
+
+#include "exec/IFunction.h"
+#include "ir/OpSequence.h"
+#include "backend/ExecTime.h"
+#include "util/ITimer.h"
+#include "IExecutor.h"
+#include "misc/EventCollector.h"
+#include "misc/EventRecorder.h"
+
+namespace neurun
+{
+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<backend::ExecTime> et) : _et(std::move(et)) {}
+ 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<backend::ExecTime> _et;
+};
+
+class ChromeTracingObserver : public IExecutionObserver
+{
+public:
+ ChromeTracingObserver(const std::string &filepath);
+ ~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 subgraphTag(const ir::OpSequence *op_seq);
+
+private:
+ std::ofstream _ofs;
+ EventRecorder _recorder;
+ EventCollector _collector;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_OBSREVERS_H__
diff --git a/runtime/neurun/core/include/exec/IExecutor.h b/runtime/neurun/core/include/exec/IExecutor.h
new file mode 100644
index 000000000..de3291388
--- /dev/null
+++ b/runtime/neurun/core/include/exec/IExecutor.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 IExecutor.h
+ * @brief This file defines interface of Executor
+ */
+#ifndef __NEURUN_EXEC_I_EXECUTOR_H_
+#define __NEURUN_EXEC_I_EXECUTOR_H_
+
+#include "ir/Graph.h"
+#include "IFunction.h"
+#include "IODescription.h"
+#include "ir/OperationIndexMap.h"
+
+namespace neurun
+{
+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;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_I_EXECUTOR_H_
diff --git a/runtime/neurun/core/include/exec/IFunction.h b/runtime/neurun/core/include/exec/IFunction.h
new file mode 100644
index 000000000..5cc29ea75
--- /dev/null
+++ b/runtime/neurun/core/include/exec/IFunction.h
@@ -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.
+ */
+
+#ifndef __NEURUN_EXEC_I_FUNCTION_H__
+#define __NEURUN_EXEC_I_FUNCTION_H__
+
+namespace neurun
+{
+namespace exec
+{
+
+class IFunction
+{
+public:
+ virtual ~IFunction() = default;
+ virtual void run() = 0;
+ virtual void runSync() = 0;
+ virtual void prepare() {}
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_I_FUNCTION_H__
diff --git a/runtime/neurun/core/include/exec/IODescription.h b/runtime/neurun/core/include/exec/IODescription.h
new file mode 100644
index 000000000..bdcc78176
--- /dev/null
+++ b/runtime/neurun/core/include/exec/IODescription.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 __NEURUN_EXEC_IO_DESCRIPTION_H__
+#define __NEURUN_EXEC_IO_DESCRIPTION_H__
+
+#include <vector>
+
+#include "ir/OperandInfo.h"
+
+namespace neurun
+{
+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
+{
+ const 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;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_IO_DESCRIPTION_H__
diff --git a/runtime/neurun/core/include/exec/NopFunction.h b/runtime/neurun/core/include/exec/NopFunction.h
new file mode 100644
index 000000000..5cbd7e5ce
--- /dev/null
+++ b/runtime/neurun/core/include/exec/NopFunction.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file NopFunction.h
+ * @brief This file defines NopFunction
+ */
+#ifndef __NEURUN_EXEC_NOP_FUNCTION_H_
+#define __NEURUN_EXEC_NOP_FUNCTION_H_
+
+#include "IFunction.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+/**
+ * @brief A derivative of IFunction tha does nothing
+ *
+ */
+class NopFunction : public IFunction
+{
+public:
+ NopFunction() = default;
+ void run() override
+ {
+ // DO NOTHING
+ }
+ void runSync() override
+ {
+ // this abstract method is used just for profiling and called for
+ // backend::acl_common::AclFunction
+ run();
+ }
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_NOP_FUNCTION_H_
diff --git a/runtime/neurun/core/include/ir/BackendSet.h b/runtime/neurun/core/include/ir/BackendSet.h
new file mode 100644
index 000000000..4979286df
--- /dev/null
+++ b/runtime/neurun/core/include/ir/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 __NEURUN_IR_BACKEND_SET_H__
+#define __NEURUN_IR_BACKEND_SET_H__
+
+#include "util/Set.h"
+
+namespace neurun
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+
+using BackendSet = util::Set<const backend::Backend *>;
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_BACKEND_SET_H__
diff --git a/runtime/neurun/core/include/ir/Data.h b/runtime/neurun/core/include/ir/Data.h
new file mode 100644
index 000000000..a0a489553
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Data.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_DATA_H__
+#define __NEURUN_IR_DATA_H__
+
+#include <algorithm>
+
+namespace neurun
+{
+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 final : 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;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_DATA_H__
diff --git a/runtime/neurun/core/include/ir/DataType.h b/runtime/neurun/core/include/ir/DataType.h
new file mode 100644
index 000000000..6eca6eb27
--- /dev/null
+++ b/runtime/neurun/core/include/ir/DataType.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 __NEURUN_IR_DATATYPE_H__
+#define __NEURUN_IR_DATATYPE_H__
+
+#include <stdexcept>
+
+namespace neurun
+{
+namespace ir
+{
+
+enum class DataType
+{
+ FLOAT32 = 0,
+ INT32 = 1,
+ UINT32 = 2,
+ QUANT8_ASYMM = 3,
+ BOOL8 = 4,
+ UINT8 = 5,
+ QUANT8_SYMM = 6,
+};
+
+inline 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::QUANT8_ASYMM:
+ case DataType::UINT8:
+ return sizeof(uint8_t);
+ case DataType::QUANT8_SYMM:
+ return sizeof(int8_t);
+ default:
+ throw std::runtime_error{"Unsupported type size"};
+ }
+}
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_DATATYPE_H__
diff --git a/runtime/neurun/core/include/ir/Graph.h b/runtime/neurun/core/include/ir/Graph.h
new file mode 100644
index 000000000..5105c3a42
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Graph.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_GRAPH_H__
+#define __NEURUN_IR_GRAPH_H__
+
+#include <functional>
+
+#include "ir/Operands.h"
+#include "ir/Operations.h"
+#include "ir/LowerInfoMap.h"
+#include "ir/OpSequence.h"
+#include "ir/Subgraphs.h"
+
+namespace neurun
+{
+namespace compiler
+{
+class BackendResolver;
+} // namespace compiler
+} // namespace neurun
+
+namespace neurun
+{
+namespace backend
+{
+namespace custom
+{
+class IKernelBuilder;
+} // namespace custom
+} // namespace backend
+} // namespace neurun
+
+namespace neurun
+{
+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::unique_ptr<Data> &&data);
+ void addInput(const OperandIndex &ind);
+ void addOutput(const OperandIndex &ind);
+ void finishBuilding(void);
+ void lower(void);
+ void removeOperand(const OperandIndex &ind) { _operands.remove(ind); }
+ bool isBuildingPhase(void) const { return _phase == Phase::BUILDING; }
+
+private:
+ void initializeUseDef();
+
+ // Custom operations support
+public:
+ void
+ bindKernelBuilder(const std::shared_ptr<neurun::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; }
+ 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 compiler::BackendResolver *backend_resolver() const { return _backend_resolver.get(); }
+
+private:
+ Phase _phase{Phase::BUILDING};
+ Operations _operations;
+ Operands _operands;
+ OperandIndexSequence _inputs;
+ OperandIndexSequence _outputs;
+
+ // For LOWERED phase
+public:
+ const LowerInfoMap *getLowerInfo() const { return _lower_info_map.get(); }
+ const operation::LowerInfo *getLowerInfo(const SubgraphIndex &subg_index) const;
+ void setLowerInfo(const SubgraphIndex &subg_index,
+ std::unique_ptr<operation::LowerInfo> &&lower_info);
+ void removeLowerInfo(const SubgraphIndex &subg_index);
+ const operand::LowerInfo *getLowerInfo(const OperandIndex &index) const;
+ operand::LowerInfo *getLowerInfo(const OperandIndex &index);
+ void setLowerInfo(const OperandIndex &index, std::unique_ptr<operand::LowerInfo> &&lower_info);
+ void removeLowerInfo(const OperandIndex &index);
+ Subgraphs &subgraphs()
+ {
+ assert(_op_seqs);
+ return *_op_seqs;
+ }
+ const Subgraphs *subgraphs() const { return _op_seqs.get(); }
+ void setBackendResolver(std::unique_ptr<compiler::BackendResolver> &&br);
+
+private:
+ void makeSubgraphs(OperandIndexMap<std::unique_ptr<operand::LowerInfo>> &operands_lower_info);
+ void
+ manipulateLowerInfo(OperandIndexMap<std::unique_ptr<operand::LowerInfo>> &operands_lower_info);
+ void dumpLowerInfo();
+ bool mergeable(const SubgraphIndex &subg_index, const OperationIndex &node_index, Layout layout);
+ SubgraphIndex appendFreshSingleOpSubgraph(const OperationIndex &node_index, const Operation &node,
+ Layout layout);
+
+private:
+ std::unique_ptr<compiler::BackendResolver> _backend_resolver;
+ std::unique_ptr<LowerInfoMap> _lower_info_map;
+ // Pass(for Perm) can accept only graph so that Graph has Subgraphs as a member
+ std::unique_ptr<Subgraphs> _op_seqs;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_GRAPH_H__
diff --git a/runtime/neurun/core/include/ir/Index.h b/runtime/neurun/core/include/ir/Index.h
new file mode 100644
index 000000000..aebc64dcd
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Index.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERAND_INDEX_H__
+#define __NEURUN_IR_OPERAND_INDEX_H__
+
+#include "util/Index.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+struct OperationIndexTag;
+using OperationIndex = ::neurun::util::Index<uint32_t, OperationIndexTag>;
+
+struct OperandIndexTag;
+using OperandIndex = ::neurun::util::Index<uint32_t, OperandIndexTag>;
+
+struct IOIndexTag;
+using IOIndex = ::neurun::util::Index<uint32_t, IOIndexTag>;
+
+struct SubgraphIndexTag;
+using SubgraphIndex = ::neurun::util::Index<uint32_t, SubgraphIndexTag>;
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERAND_INDEX_H__
diff --git a/runtime/neurun/core/include/ir/InternalType.h b/runtime/neurun/core/include/ir/InternalType.h
new file mode 100644
index 000000000..91085f2f3
--- /dev/null
+++ b/runtime/neurun/core/include/ir/InternalType.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 __NEURUN_IR_INTERNAL_TYPE_H__
+#define __NEURUN_IR_INTERNAL_TYPE_H__
+
+#include <cstdint>
+
+namespace neurun
+{
+namespace ir
+{
+
+enum class Activation
+{
+ NONE = 0,
+ RELU = 1,
+ RELU1 = 2,
+ RELU6 = 3,
+ TANH = 4,
+ SIGMOID = 5
+};
+
+enum class PaddingType
+{
+ EXPLICIT = 0,
+ SAME = 1,
+ VALID = 2
+};
+
+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
+{
+ PaddingType type;
+ ExplicitPadding param;
+};
+
+struct Stride
+{
+ uint32_t vertical;
+ uint32_t horizontal;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_INTERNAL_TYPE_H__
diff --git a/runtime/neurun/core/include/ir/Layout.h b/runtime/neurun/core/include/ir/Layout.h
new file mode 100644
index 000000000..c4edb70db
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_LAYOUT_H__
+#define __NEURUN_IR_LAYOUT_H__
+
+#include <functional>
+#include <string>
+
+namespace neurun
+{
+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 neurun
+
+namespace std
+{
+
+template <> struct hash<neurun::ir::Layout>
+{
+ size_t operator()(neurun::ir::Layout value) const noexcept
+ {
+ using type = typename std::underlying_type<neurun::ir::Layout>::type;
+ return hash<type>()(static_cast<type>(value));
+ }
+};
+
+} // namespace std
+
+#endif // __NEURUN_IR_LAYOUT_H__
diff --git a/runtime/neurun/core/include/ir/LowerInfoMap.h b/runtime/neurun/core/include/ir/LowerInfoMap.h
new file mode 100644
index 000000000..a8fd818b8
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_LOWER_INFO_MAP_H__
+#define __NEURUN_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 neurun
+{
+namespace ir
+{
+
+struct LowerInfoMap
+{
+ std::unordered_map<SubgraphIndex, std::unique_ptr<operation::LowerInfo>> operation;
+ OperandIndexMap<std::unique_ptr<operand::LowerInfo>> operand;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_LOWER_INFO_MAP_H__
diff --git a/runtime/neurun/core/include/ir/OpCode.h b/runtime/neurun/core/include/ir/OpCode.h
new file mode 100644
index 000000000..2b466a212
--- /dev/null
+++ b/runtime/neurun/core/include/ir/OpCode.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 __NEURUN_IR_OP_CODE_H__
+#define __NEURUN_IR_OP_CODE_H__
+
+#include <functional>
+#include <stdint.h>
+
+namespace neurun
+{
+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);
+
+} // namespace ir
+} // namespace neurun
+
+namespace std
+{
+
+template <> struct hash<neurun::ir::OpCode>
+{
+ size_t operator()(neurun::ir::OpCode value) const noexcept
+ {
+ using type = typename std::underlying_type<neurun::ir::OpCode>::type;
+ return hash<type>()(static_cast<type>(value));
+ }
+};
+
+} // namespace std
+
+#endif // __NEURUN_IR_OP_CODE_H__
diff --git a/runtime/neurun/core/include/ir/OpSequence.h b/runtime/neurun/core/include/ir/OpSequence.h
new file mode 100644
index 000000000..68632e589
--- /dev/null
+++ b/runtime/neurun/core/include/ir/OpSequence.h
@@ -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.
+ */
+
+#ifndef __NEURUN_IR_OP_SEQUENCE_H__
+#define __NEURUN_IR_OP_SEQUENCE_H__
+
+#include <vector>
+#include <string>
+#include <memory>
+
+#include "ir/Layout.h"
+#include "ir/Index.h"
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+// To support ValueSwappable, Element doesn't have members which are classes
+// as value(or can have members which are classes as value and the classes
+// support Swappable)
+struct Element
+{
+ OperationIndex index;
+ const Operation *node;
+
+ Element(const OperationIndex *i, const Operation *n) : index{*i}, node{n}
+ {
+ // DO NOTHING
+ }
+};
+
+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 replaceInput(const OperandIndex &from, const OperandIndex &to) { _inputs.replace(from, to); }
+ void replaceOutput(const OperandIndex &from, const OperandIndex &to)
+ {
+ _outputs.replace(from, to);
+ }
+
+ void appendOperation(const OperationIndex &index, const Operation &node)
+ {
+ _operations.emplace_back(&index, &node);
+ }
+
+ std::vector<Element> &operations(void) { return _operations; }
+
+ const std::vector<Element> &operations(void) const { return _operations; }
+
+ uint32_t size(void) const { return _operations.size(); }
+
+ // TODO: Impl Dumper instead of this method
+ std::string getStr(void) const;
+
+public:
+ void remove(const OperationIndex &index);
+
+public:
+ Layout getLayout() const { return _layout; }
+
+public:
+ std::vector<Element>::const_iterator begin() const { return _operations.begin(); }
+ std::vector<Element>::const_iterator end() const { return _operations.end(); }
+
+private:
+ bool exist(const OperationIndex &index) const;
+
+private:
+ OperandIndexSequence _inputs;
+ OperandIndexSequence _outputs;
+ std::vector<Element> _operations;
+
+private:
+ Layout _layout;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OP_SEQUENCE_H__
diff --git a/runtime/neurun/core/include/ir/Operand.h b/runtime/neurun/core/include/ir/Operand.h
new file mode 100644
index 000000000..b1f28de48
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Operand.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERAND_H__
+#define __NEURUN_IR_OPERAND_H__
+
+#include <cassert>
+#include <cstdint>
+#include <cpp14/memory.h>
+#include <algorithm>
+
+#include "ir/Data.h"
+#include "ir/DataType.h"
+#include "ir/OperandInfo.h"
+#include "ir/operand/ParentInfo.h" // TODO Remove this dependency
+#include "ir/OperationIndexList.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+class Operand
+{
+public:
+ explicit Operand(const Shape &shape, const TypeInfo &type) : _info{shape, type}
+ {
+ // DO NOTHING
+ }
+
+public:
+ const Shape &shape(void) const { return _info.shape(); }
+ const TypeInfo &typeInfo(void) const { return _info.typeInfo(); }
+ const OperandInfo &info(void) const { return _info; }
+ size_t operandSize(void) const;
+
+ const OperationIndexList &getUses() const { return _uses; }
+ const OperationIndexList &getDef() const { return _def; }
+ void appendUse(const OperationIndex &idx);
+ void removeUse(const OperationIndex &idx);
+ void appendDef(const OperationIndex &idx);
+ void removeDef(const OperationIndex &idx);
+
+public:
+ void type(const DataType type) { _info.type(type); };
+
+public:
+ void data(std::unique_ptr<Data> &&data) { _data = std::move(data); }
+ const Data &data(void) const
+ {
+ assert(_data);
+ return *_data;
+ }
+
+ /**
+ * @brief Get true if Operand has data, otherwise @c false
+ a @return @c true if Operand has data, otherwise @c false
+ */
+ bool isConstant(void) const { return _data != nullptr; }
+
+public:
+ template <typename T, typename... Args> void data(Args &&... args)
+ {
+ data(nnfw::cpp14::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(isConstant());
+ 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);
+ }
+
+public:
+ /**
+ * @brief Set parent information
+ * @param[in] parent_info Parent information
+ */
+ void parent_info(std::unique_ptr<operand::ParentInfo> &&parent_info);
+ /**
+ * @brief Return parent information pointer as constant
+ * @return Parent information pointer
+ */
+ const operand::ParentInfo *parent_info() const;
+ /**
+ * @brief Return parent information pointer
+ * @return Perent information pointer
+ */
+ operand::ParentInfo *parent_info();
+
+private:
+ OperandInfo _info;
+ std::shared_ptr<Data> _data;
+
+ OperationIndexList _uses;
+ OperationIndexList _def; // size is 0 (constant) or 1 (from def operation)
+
+ std::shared_ptr<operand::ParentInfo> _parent_info;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERAND_H__
diff --git a/runtime/neurun/core/include/ir/OperandConstraint.h b/runtime/neurun/core/include/ir/OperandConstraint.h
new file mode 100644
index 000000000..de6f21634
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_MODEL_OPERAND_CONSTRAINT_H__
+#define __NEURUN_MODEL_OPERAND_CONSTRAINT_H__
+
+#include <stdint.h>
+#include <limits>
+#include <set>
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_MODEL_OPERAND_CONSTRAINT_H__
diff --git a/runtime/neurun/core/include/ir/OperandIndexMap.h b/runtime/neurun/core/include/ir/OperandIndexMap.h
new file mode 100644
index 000000000..c9234128e
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERAND_INDEX_MAP_H__
+#define __NEURUN_IR_OPERAND_INDEX_MAP_H__
+
+#include <unordered_map>
+
+#include "ir/Index.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+template <typename T> using OperandIndexMap = std::unordered_map<OperandIndex, T>;
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERAND_INDEX_MAP_H__
diff --git a/runtime/neurun/core/include/ir/OperandIndexSequence.h b/runtime/neurun/core/include/ir/OperandIndexSequence.h
new file mode 100644
index 000000000..7f8cec844
--- /dev/null
+++ b/runtime/neurun/core/include/ir/OperandIndexSequence.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 __NEURUN_MODEL_OPERAND_INDEX_SEQUENCE_H__
+#define __NEURUN_MODEL_OPERAND_INDEX_SEQUENCE_H__
+
+#include <initializer_list>
+#include <vector>
+
+#include "ir/Index.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+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) { _set.emplace_back(index); }
+ void append(const OperandIndexSequence &l) { _set.insert(_set.end(), l.begin(), l.end()); }
+
+public:
+ uint32_t size() const { return static_cast<uint32_t>(_set.size()); }
+ const OperandIndex &at(IOIndex set_index) const { return _set.at(set_index.value()); }
+ const OperandIndex &at(uint32_t index) const { return _set.at(index); }
+ bool contains(const OperandIndex &index) const;
+ void replace(const OperandIndex &from, const OperandIndex &to);
+
+public:
+ std::vector<OperandIndex>::const_iterator begin(void) const { return _set.begin(); }
+ std::vector<OperandIndex>::const_iterator end(void) const { return _set.end(); }
+
+private:
+ std::vector<OperandIndex> _set;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_MODEL_OPERAND_INDEX_SET_H__
diff --git a/runtime/neurun/core/include/ir/OperandInfo.h b/runtime/neurun/core/include/ir/OperandInfo.h
new file mode 100644
index 000000000..82ad7ef0f
--- /dev/null
+++ b/runtime/neurun/core/include/ir/OperandInfo.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file OperandInfo.h
+ * @brief This file contains OperandInfo class
+ */
+#ifndef __NEURUN_IR_OPERAND_INFO_H__
+#define __NEURUN_IR_OPERAND_INFO_H__
+
+#include "ir/Shape.h"
+#include "ir/TypeInfo.h"
+#include "ir/Layout.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+/**
+ * @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
+ */
+ OperandInfo(const Shape &shape, const TypeInfo &typeInfo) : _shape(shape), _typeInfo(typeInfo)
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct a new OperandInfo object
+ * @param[in] origin info for copy
+ */
+ OperandInfo(const OperandInfo &origin) : _shape(origin.shape()), _typeInfo(origin.typeInfo())
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return tensor shape
+ * @return Tensor shape
+ */
+ const Shape &shape() const { return _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()); }
+
+private:
+ Shape _shape;
+ TypeInfo _typeInfo;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERAND_INFO_H__
diff --git a/runtime/neurun/core/include/ir/Operands.h b/runtime/neurun/core/include/ir/Operands.h
new file mode 100644
index 000000000..c8d68c088
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Operands.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERANDS_H__
+#define __NEURUN_IR_OPERANDS_H__
+
+#include <memory>
+#include <unordered_map>
+
+#include "ir/Operand.h"
+#include "ir/Index.h"
+#include "util/ObjectManager.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+class Operands : public util::ObjectManager<OperandIndex, Operand>
+{
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_MODEL_OPERAND_SET_H__
diff --git a/runtime/neurun/core/include/ir/Operation.h b/runtime/neurun/core/include/ir/Operation.h
new file mode 100644
index 000000000..a02f980a5
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Operation.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 __NEURUN_IR_OPERATION_H__
+#define __NEURUN_IR_OPERATION_H__
+
+#include <memory>
+
+#include "ir/OpCode.h"
+#include "ir/Operand.h"
+#include "ir/OperandIndexSequence.h"
+#include "ir/OperandConstraint.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+struct OperationVisitor;
+
+class Operation
+{
+public:
+ Operation(OperandConstraint input_constr, const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs);
+ explicit Operation(OperandConstraint input_constr);
+
+ Operation(const Operation &) = delete;
+ Operation(Operation &&) = default;
+ Operation &operator=(const Operation &) = delete;
+ 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 replaceInput(const OperandIndex &from, const OperandIndex &to);
+ void replaceOutput(const OperandIndex &from, const OperandIndex &to);
+ 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;
+ OperandIndexSequence _inputs;
+ OperandIndexSequence _outputs;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_H__
diff --git a/runtime/neurun/core/include/ir/OperationIndexList.h b/runtime/neurun/core/include/ir/OperationIndexList.h
new file mode 100644
index 000000000..bf3ea3d6b
--- /dev/null
+++ b/runtime/neurun/core/include/ir/OperationIndexList.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_MODEL_OPERATION_INDEX_LIST_H__
+#define __NEURUN_MODEL_OPERATION_INDEX_LIST_H__
+
+#include <algorithm>
+#include <cassert>
+#include <initializer_list>
+#include <list>
+
+#include "ir/Index.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+class OperationIndexList
+{
+public:
+ OperationIndexList(void) = default;
+ OperationIndexList(std::initializer_list<OperationIndex> list);
+
+public:
+ void append(const OperationIndex &index) { _list.push_back(index); }
+ void remove(const OperationIndex &index)
+ {
+ auto itr = std::find(_list.begin(), _list.end(), index);
+ assert(itr != _list.end());
+ _list.erase(itr);
+ }
+
+public:
+ uint32_t size() const { return static_cast<uint32_t>(_list.size()); }
+ const std::list<OperationIndex> &list() const { return _list; }
+ bool contains(const OperationIndex &index) const;
+
+private:
+ std::list<OperationIndex> _list;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_MODEL_OPERATION_INDEX_LIST_H__
diff --git a/runtime/neurun/core/include/ir/OperationIndexMap.h b/runtime/neurun/core/include/ir/OperationIndexMap.h
new file mode 100644
index 000000000..50b1db527
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_INDEX_MAP_H__
+#define __NEURUN_IR_OPERATION_INDEX_MAP_H__
+
+#include <unordered_map>
+
+#include "ir/Index.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+template <typename T> using OperationIndexMap = std::unordered_map<OperationIndex, T>;
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_INDEX_MAP_H__
diff --git a/runtime/neurun/core/include/ir/OperationVisitor.h b/runtime/neurun/core/include/ir/OperationVisitor.h
new file mode 100644
index 000000000..0eb6de2d3
--- /dev/null
+++ b/runtime/neurun/core/include/ir/OperationVisitor.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERATION_VISITOR_H__
+#define __NEURUN_IR_OPERATION_VISITOR_H__
+
+#include "ir/Operations.Include.h"
+#include "ir/OpSequence.h"
+
+namespace neurun
+{
+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 &op_seq)
+ {
+ for (const auto &e : op_seq.operations())
+ {
+ e.node->accept(*this);
+ }
+ }
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_VISITOR_H__
diff --git a/runtime/neurun/core/include/ir/Operations.Include.h b/runtime/neurun/core/include/ir/Operations.Include.h
new file mode 100644
index 000000000..e14e18cc1
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Operations.Include.h
@@ -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.
+ */
+
+// This file has no ifdef guard intentionally
+
+#include "ir/operation/BatchToSpaceND.h"
+#include "ir/operation/Conv2D.h"
+#include "ir/operation/MaxPool2D.h"
+#include "ir/operation/AvgPool2D.h"
+#include "ir/operation/Concat.h"
+#include "ir/operation/Reshape.h"
+#include "ir/operation/FullyConnected.h"
+#include "ir/operation/Softmax.h"
+#include "ir/operation/Transpose.h"
+#include "ir/operation/Permute.h"
+#include "ir/operation/ReduceSum.h"
+#include "ir/operation/Add.h"
+#include "ir/operation/Sub.h"
+#include "ir/operation/DepthwiseConv2D.h"
+#include "ir/operation/Slice.h"
+#include "ir/operation/StridedSlice.h"
+#include "ir/operation/Mul.h"
+#include "ir/operation/Squeeze.h"
+#include "ir/operation/Tanh.h"
+#include "ir/operation/Logistic.h"
+#include "ir/operation/Cast.h"
+#include "ir/operation/Div.h"
+#include "ir/operation/Exp.h"
+#include "ir/operation/ReduceMax.h"
+#include "ir/operation/Comparison.h"
+#include "ir/operation/LogicalAnd.h"
+#include "ir/operation/LogicalOr.h"
+#include "ir/operation/LogicalNot.h"
+#include "ir/operation/LSTM.h"
+#include "ir/operation/RSQRT.h"
+#include "ir/operation/ReLU.h"
+#include "ir/operation/ResizeBilinear.h"
+#include "ir/operation/ReLU1.h"
+#include "ir/operation/ReLU6.h"
+#include "ir/operation/RNN.h"
+#include "ir/operation/Floor.h"
+#include "ir/operation/SpaceToBatchND.h"
+#include "ir/operation/SpaceToDepth.h"
+#include "ir/operation/L2Pool2D.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/SQRT.h"
+#include "ir/operation/SquaredDifference.h"
+#include "ir/operation/TopKV2.h"
+#include "ir/operation/Gather.h"
+#include "ir/operation/Neg.h"
+#include "ir/operation/Abs.h"
+#include "ir/operation/ArgMax.h"
+#include "ir/operation/Dequantize.h"
+#include "ir/operation/Mean.h"
+#include "ir/operation/LocalResponseNormalization.h"
+#include "ir/operation/DepthToSpace.h"
+#include "ir/operation/Pack.h"
+#include "ir/operation/ReduceMin.h"
+#include "ir/operation/Split.h"
+#include "ir/operation/Unpack.h"
+#include "ir/operation/Pad.h"
+#include "ir/operation/Min.h"
+#include "ir/operation/Max.h"
+#include "ir/operation/Custom.h"
+#include "ir/operation/OneHot.h"
diff --git a/runtime/neurun/core/include/ir/Operations.h b/runtime/neurun/core/include/ir/Operations.h
new file mode 100644
index 000000000..9e2aecb43
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Operations.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 __NEURUN_IR_OPERATIONS_H__
+#define __NEURUN_IR_OPERATIONS_H__
+
+#include "ir/Index.h"
+#include "ir/Operation.h"
+#include "util/ObjectManager.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+class Operations : public util::ObjectManager<OperationIndex, Operation>
+{
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_MODEL_OPERATION_MANAGER_H__
diff --git a/runtime/neurun/core/include/ir/Operations.lst b/runtime/neurun/core/include/ir/Operations.lst
new file mode 100644
index 000000000..8c02857d9
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Operations.lst
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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(Add)
+OP(Sub)
+OP(BatchToSpaceND)
+OP(Cast)
+OP(Conv2D)
+OP(DepthwiseConv2D)
+OP(AvgPool2D)
+OP(MaxPool2D)
+OP(Concat)
+OP(FullyConnected)
+OP(ReduceSum)
+OP(Reshape)
+OP(Mul)
+OP(Softmax)
+OP(Squeeze)
+OP(Slice)
+OP(StridedSlice)
+OP(Tanh)
+OP(Logistic)
+OP(Div)
+OP(Transpose)
+OP(Exp)
+OP(ReduceMax)
+OP(Comparison)
+OP(LogicalAnd)
+OP(LogicalOr)
+OP(LogicalNot)
+OP(LSTM)
+OP(RSQRT)
+OP(ReLU)
+OP(ResizeBilinear)
+OP(ReLU1)
+OP(ReLU6)
+OP(RNN)
+OP(Floor)
+OP(SpaceToBatchND)
+OP(SpaceToDepth)
+OP(L2Pool2D)
+OP(EmbeddingLookup)
+OP(L2Normalization)
+OP(HashtableLookup)
+OP(InstanceNorm)
+OP(PReLU)
+OP(TransposeConv)
+OP(SQRT)
+OP(SquaredDifference)
+OP(TopKV2)
+OP(Gather)
+OP(Neg)
+OP(Abs)
+OP(ArgMax)
+OP(Dequantize)
+OP(Mean)
+OP(LocalResponseNormalization)
+OP(DepthToSpace)
+OP(Pack)
+OP(ReduceMin)
+OP(Split)
+OP(Unpack)
+OP(Pad)
+OP(Custom)
+OP(Permute)
+OP(Min)
+OP(Max)
+OP(OneHot)
diff --git a/runtime/neurun/core/include/ir/Shape.h b/runtime/neurun/core/include/ir/Shape.h
new file mode 100644
index 000000000..a58af38ad
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Shape.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_SHAPE_H__
+#define __NEURUN_IR_SHAPE_H__
+
+#include "ir/Layout.h"
+#include "misc/feature/Shape.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace neurun
+{
+namespace ir
+{
+
+// TODO Remove this dependency.
+using FeatureShape = nnfw::misc::feature::Shape;
+
+struct Shape
+{
+public:
+ 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 { return _dimensions.at(i); }
+
+ int32_t &dim(int i) { return _dimensions.at(i); }
+
+ 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);
+
+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(); }
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_SHAPE_H__
diff --git a/runtime/neurun/core/include/ir/Subgraphs.h b/runtime/neurun/core/include/ir/Subgraphs.h
new file mode 100644
index 000000000..716f09bcf
--- /dev/null
+++ b/runtime/neurun/core/include/ir/Subgraphs.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 __NEURUN_IR_SUBGRAPHS_H__
+#define __NEURUN_IR_SUBGRAPHS_H__
+
+#include "ir/Index.h"
+#include "ir/OpSequence.h"
+#include "util/ObjectManager.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+/**
+ * @brief Class that manages OpSequence objects
+ */
+class Subgraphs : public util::ObjectManager<SubgraphIndex, 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] op Operation that is emplaced
+ * @param[in] layout OpSequence's layout
+ * @return SubgraphIndex
+ */
+ SubgraphIndex emplace(const OperationIndex &op_index, const Operation &op, Layout layout);
+
+ /**
+ * @brief Push an instance of OpSequence to objects
+ *
+ * @param[in] subg An instance of OpSequence
+ * @return SubgraphIndex
+ */
+ SubgraphIndex emplace(std::unique_ptr<OpSequence> &&subg);
+
+ /**
+ * @brief Check if an operation does exist in any subgraphs
+ *
+ * @param operation_index Operation index to find
+ * @return true If such operation exists in any subgraphs otherwise false
+ */
+ bool containsOperation(const OperationIndex &operation_index) const;
+ /**
+ * @brief Find an operation from all subgraphs
+ *
+ * @param operation_index Operation index to find
+ * @return SubgraphIndex Index of OpSequence that contains given operation index
+ */
+ SubgraphIndex getOperation(const OperationIndex &operation_index) const;
+ /**
+ * @brief Dump subgraphs
+ *
+ * @param msg Message that will be displayed
+ */
+ void dump(const std::string &msg) const;
+ /**
+ * @brief Remove an operation from OpSequence
+ *
+ * @param operation_index Operation index to be removed
+ */
+ void removeFromSubgraph(const OperationIndex &operation_index);
+
+private:
+ SubgraphIndex findOperation(const OperationIndex &operation_index) const;
+};
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_SUBGRAPHS_H__
diff --git a/runtime/neurun/core/include/ir/TypeInfo.h b/runtime/neurun/core/include/ir/TypeInfo.h
new file mode 100644
index 000000000..5b35046bb
--- /dev/null
+++ b/runtime/neurun/core/include/ir/TypeInfo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_TYPEINFO_H__
+#define __NEURUN_IR_TYPEINFO_H__
+
+#include <cstdint>
+
+#include "ir/DataType.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+class TypeInfo
+{
+public:
+ TypeInfo() = delete;
+
+ explicit TypeInfo(DataType type, float scale = 0, int32_t offset = 0)
+ : _type(type), _scale(scale), _offset(offset)
+ {
+ }
+
+public:
+ DataType type() const { return _type; }
+ float scale() const { return _scale; }
+ int32_t offset() const { return _offset; }
+
+public:
+ void type(const DataType type) { _type = type; }
+
+private:
+ DataType _type;
+ float _scale;
+ int32_t _offset;
+};
+
+bool operator==(const TypeInfo &lhs, const TypeInfo &rhs);
+bool operator!=(const TypeInfo &lhs, const TypeInfo &rhs);
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_TYPEINFO_H__
diff --git a/runtime/neurun/core/include/ir/operand/LowerInfo.h b/runtime/neurun/core/include/ir/operand/LowerInfo.h
new file mode 100644
index 000000000..e0fb2c5c8
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operand/LowerInfo.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERAND_LOWER_INFO_H__
+#define __NEURUN_IR_OPERAND_LOWER_INFO_H__
+
+#include <functional>
+#include <stdint.h>
+
+#include "ir/operand/PermuteFactor.h"
+#include "util/Set.h"
+
+namespace neurun
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+namespace operand
+{
+using PermuteFactorSet = util::Set<PermuteFactor>;
+
+class LowerInfo
+{
+public:
+ class Shape4D
+ {
+ public:
+ Shape4D(uint32_t n, uint32_t h, uint32_t w, uint32_t c) : _n{n}, _h{h}, _w{w}, _c{c}
+ {
+ // DO NOTHING
+ }
+
+ public:
+ uint32_t n(void) const { return _n; }
+ uint32_t h(void) const { return _h; }
+ uint32_t w(void) const { return _w; }
+ uint32_t c(void) const { return _c; }
+
+ private:
+ uint32_t _n;
+ uint32_t _h;
+ uint32_t _w;
+ uint32_t _c;
+ };
+
+public:
+ LowerInfo(const Shape4D &shape) : _shape{shape}
+ {
+ // DO NOTHING
+ }
+
+public:
+ const Shape4D &shape(void) const { return _shape; }
+ 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:
+ Shape4D _shape;
+ PermuteFactorSet _def_factors;
+ PermuteFactorSet _use_factors;
+};
+
+} // namespace operand
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERAND_LOWER_INFO_H__
diff --git a/runtime/neurun/core/include/ir/operand/ParentInfo.h b/runtime/neurun/core/include/ir/operand/ParentInfo.h
new file mode 100644
index 000000000..92dac2b63
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operand/ParentInfo.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 ParentInfo.h
+ * @brief This file contains ParentInfo class and internal Coordinate4D class
+ * to represent subsumption between operand
+ */
+
+#ifndef __NEURUN_IR_OPERAND_PARENT_INFO_H__
+#define __NEURUN_IR_OPERAND_PARENT_INFO_H__
+
+#include <stdint.h>
+
+#include "ir/Index.h"
+#include "util/Coordinates.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operand
+{
+
+/**
+ * @brief Class to represent parent operand in child operand
+ */
+class ParentInfo
+{
+public:
+ /**
+ * @brief Construct a new ParentInfo object
+ * @param[in] parent Index of parent operand
+ * @param[in] coordinate Offset of child operand in parent operand
+ * @return
+ */
+ ParentInfo(const OperandIndex parent, const util::Coordinates &coordinate)
+ : _parent{parent}, _coordinate{coordinate}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return parent index
+ * @return Parent index
+ */
+ OperandIndex parent(void) const { return _parent; }
+ /**
+ * @brief Retern offset in parent
+ * @return Offset
+ */
+ util::Coordinates offset(void) const { return _coordinate; }
+
+private:
+ OperandIndex _parent;
+ util::Coordinates _coordinate;
+};
+
+} // namespace operand
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERAND_PARENT_INFO_H__
diff --git a/runtime/neurun/core/include/ir/operand/PermuteFactor.h b/runtime/neurun/core/include/ir/operand/PermuteFactor.h
new file mode 100644
index 000000000..60d926b2d
--- /dev/null
+++ b/runtime/neurun/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 neurun::ir::operand::PermuteFactor class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NEURUN_IR_OPERAND_PERMUTE_FACTOR_H__
+#define __NEURUN_IR_OPERAND_PERMUTE_FACTOR_H__
+
+#include <functional>
+
+#include "ir/Layout.h"
+
+namespace neurun
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+namespace operand
+{
+
+/**
+ * @brief Class that has factors of permutation
+ */
+class PermuteFactor
+{
+public:
+ /**
+ * @brief Construct PermuteFactor object.
+ * @param backend The backend factor
+ * @param backend 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 neurun
+
+namespace std
+{
+
+/**
+ * @brief Structure that provides hash value of PermuteFactor
+ */
+template <> struct hash<neurun::ir::operand::PermuteFactor>
+{
+ size_t operator()(const neurun::ir::operand::PermuteFactor &factor) const noexcept
+ {
+ hash<const neurun::backend::Backend *> b_hash{};
+ hash<neurun::ir::Layout> l_hash{};
+ return b_hash(factor.backend()) ^ (l_hash(factor.layout()) << 1);
+ }
+};
+
+} // namespace std
+
+#endif // __NEURUN_IR_OPERAND_PERMUTE_FACTOR_H__
diff --git a/runtime/neurun/core/include/ir/operation/Abs.h b/runtime/neurun/core/include/ir/operation/Abs.h
new file mode 100644
index 000000000..97293823b
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Abs.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 __NEURUN_IR_OPERATION_ABS_H__
+#define __NEURUN_IR_OPERATION_ABS_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Abs : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Abs(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Abs; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_ABS_H__
diff --git a/runtime/neurun/core/include/ir/operation/Add.h b/runtime/neurun/core/include/ir/operation/Add.h
new file mode 100644
index 000000000..fc4d6a7e7
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Add.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 __NEURUN_IR_OPERATION_ADD_H__
+#define __NEURUN_IR_OPERATION_ADD_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Add : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+ struct Param
+ {
+ Activation activation;
+ };
+
+public:
+ Add(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Add; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_ADD_H__
diff --git a/runtime/neurun/core/include/ir/operation/ArgMax.h b/runtime/neurun/core/include/ir/operation/ArgMax.h
new file mode 100644
index 000000000..23f52710f
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_ARG_MAX_H__
+#define __NEURUN_IR_OPERATION_ARG_MAX_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class ArgMax : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT
+ };
+
+ struct Param
+ {
+ int axis;
+ int rank;
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_ARG_MAX_H__
diff --git a/runtime/neurun/core/include/ir/operation/AvgPool2D.h b/runtime/neurun/core/include/ir/operation/AvgPool2D.h
new file mode 100644
index 000000000..a03628184
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/AvgPool2D.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 __NEURUN_IR_OPERATION_AVGPOOL2D_H__
+#define __NEURUN_IR_OPERATION_AVGPOOL2D_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class AvgPool2D : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ uint32_t kh;
+ uint32_t kw;
+
+ Stride stride;
+ Padding padding;
+ Activation activation;
+ };
+
+public:
+ AvgPool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::AvgPool2D; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_AVGPOOL2D_H__
diff --git a/runtime/neurun/core/include/ir/operation/BatchToSpaceND.h b/runtime/neurun/core/include/ir/operation/BatchToSpaceND.h
new file mode 100644
index 000000000..b90d2871d
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/BatchToSpaceND.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 __NEURUN_IR_OPERATION_BATCH_TO_SPACE_ND_H__
+#define __NEURUN_IR_OPERATION_BATCH_TO_SPACE_ND_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class BatchToSpaceND : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ BLOCK_SIZE = 1
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_BATCH_TO_SPACE_ND_H__
diff --git a/runtime/neurun/core/include/ir/operation/Cast.h b/runtime/neurun/core/include/ir/operation/Cast.h
new file mode 100644
index 000000000..a71087dd0
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Cast.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 __NEURUN_IR_OPERATION_CAST_H__
+#define __NEURUN_IR_OPERATION_CAST_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Cast : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Cast(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Cast; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_CAST_H__
diff --git a/runtime/neurun/core/include/ir/operation/Comparison.h b/runtime/neurun/core/include/ir/operation/Comparison.h
new file mode 100644
index 000000000..23c775c42
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Comparison.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 __NEURUN_IR_OPERATION_COMPARISON_H__
+#define __NEURUN_IR_OPERATION_COMPARISON_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_COMPARISON_H__
diff --git a/runtime/neurun/core/include/ir/operation/Concat.h b/runtime/neurun/core/include/ir/operation/Concat.h
new file mode 100644
index 000000000..8628ed398
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Concat.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERATION_CONCAT_H__
+#define __NEURUN_IR_OPERATION_CONCAT_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Concat : public Operation
+{
+public:
+ struct Param
+ {
+ int32_t axis;
+ int32_t rank;
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_CONCAT_H__
diff --git a/runtime/neurun/core/include/ir/operation/Conv2D.h b/runtime/neurun/core/include/ir/operation/Conv2D.h
new file mode 100644
index 000000000..1215666e9
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Conv2D.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERATION_CONV2D_H__
+#define __NEURUN_IR_OPERATION_CONV2D_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Conv2D : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ KERNEL,
+ BIAS
+ };
+
+ struct Param
+ {
+ Stride stride;
+ Padding padding;
+ Activation activation;
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_CONV2D_H__
diff --git a/runtime/neurun/core/include/ir/operation/Custom.h b/runtime/neurun/core/include/ir/operation/Custom.h
new file mode 100644
index 000000000..03501e8ef
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Custom.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 __NEURUN_IR_OPERATION_CUSTOM_H__
+#define __NEURUN_IR_OPERATION_CUSTOM_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Custom : public Operation
+{
+public:
+ struct Userdata
+ {
+ char *data;
+ size_t size;
+ };
+
+ 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;
+
+ ~Custom() override;
+
+private:
+ std::string _id;
+ Userdata _userdata;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+#endif // __NEURUN_IR_OPERATION_CUSTOM_H__
diff --git a/runtime/neurun/core/include/ir/operation/DepthToSpace.h b/runtime/neurun/core/include/ir/operation/DepthToSpace.h
new file mode 100644
index 000000000..6e7aaf249
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_DEPTH_TO_SPACE_H__
+#define __NEURUN_IR_OPERATION_DEPTH_TO_SPACE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_DEPTH_TO_SPACE_H__
diff --git a/runtime/neurun/core/include/ir/operation/DepthwiseConv2D.h b/runtime/neurun/core/include/ir/operation/DepthwiseConv2D.h
new file mode 100644
index 000000000..1f0926fa8
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/DepthwiseConv2D.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 __NEURUN_IR_OPERATION_DEPTHWISECONV2D_H__
+#define __NEURUN_IR_OPERATION_DEPTHWISECONV2D_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+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;
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_DEPTHWISECONV2D_H__
diff --git a/runtime/neurun/core/include/ir/operation/Dequantize.h b/runtime/neurun/core/include/ir/operation/Dequantize.h
new file mode 100644
index 000000000..dfca278cd
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Dequantize.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 __NEURUN_IR_OPERATION_DEQUANTIZE_H__
+#define __NEURUN_IR_OPERATION_DEQUANTIZE_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Dequantize : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Dequantize(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Dequantize; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_DEQUANTIZE_H__
diff --git a/runtime/neurun/core/include/ir/operation/Div.h b/runtime/neurun/core/include/ir/operation/Div.h
new file mode 100644
index 000000000..d3e744472
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Div.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 __NEURUN_IR_OPERATION_DIV_H__
+#define __NEURUN_IR_OPERATION_DIV_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Div : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+ struct Param
+ {
+ Activation activation;
+ };
+
+public:
+ Div(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Div; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_DIV_H__
diff --git a/runtime/neurun/core/include/ir/operation/EmbeddingLookup.h b/runtime/neurun/core/include/ir/operation/EmbeddingLookup.h
new file mode 100644
index 000000000..968b7b35a
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_EMBEDDING_LOOKUP_H__
+#define __NEURUN_IR_OPERATION_EMBEDDING_LOOKUP_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_EMBEDDING_LOOKUP_H__
diff --git a/runtime/neurun/core/include/ir/operation/Exp.h b/runtime/neurun/core/include/ir/operation/Exp.h
new file mode 100644
index 000000000..8e04f3f7f
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Exp.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 __NEURUN_IR_OPERATION_EXP_H__
+#define __NEURUN_IR_OPERATION_EXP_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Exp : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Exp(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Exp; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_EXP_H__
diff --git a/runtime/neurun/core/include/ir/operation/Floor.h b/runtime/neurun/core/include/ir/operation/Floor.h
new file mode 100644
index 000000000..ca4cf9881
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Floor.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 __NEURUN_IR_OPERATION_FLOOR_H__
+#define __NEURUN_IR_OPERATION_FLOOR_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Floor : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Floor(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Floor; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_FLOOR_H__
diff --git a/runtime/neurun/core/include/ir/operation/FullyConnected.h b/runtime/neurun/core/include/ir/operation/FullyConnected.h
new file mode 100644
index 000000000..1ffa1318d
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/FullyConnected.h
@@ -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.
+ */
+
+#ifndef __NEURUN_IR_OPERATION_FULLYCONNECTED_H__
+#define __NEURUN_IR_OPERATION_FULLYCONNECTED_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class FullyConnected : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ WEIGHT,
+ BIAS
+ };
+
+ struct Param
+ {
+ Activation activation;
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_FULLYCONNECTED_H__
diff --git a/runtime/neurun/core/include/ir/operation/Gather.h b/runtime/neurun/core/include/ir/operation/Gather.h
new file mode 100644
index 000000000..13540d413
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Gather.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 __NEURUN_IR_OPERATION_GATHER_H__
+#define __NEURUN_IR_OPERATION_GATHER_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Gather : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ INDICES,
+ };
+
+ struct Param
+ {
+ int32_t axis;
+ int32_t rank;
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_GATHER_H__
diff --git a/runtime/neurun/core/include/ir/operation/HashtableLookup.h b/runtime/neurun/core/include/ir/operation/HashtableLookup.h
new file mode 100644
index 000000000..fb6c97607
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_HASHTABLE_LOOKUP_H__
+#define __NEURUN_IR_OPERATION_HASHTABLE_LOOKUP_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_HASHTABLE_LOOKUP_H__
diff --git a/runtime/neurun/core/include/ir/operation/InstanceNorm.h b/runtime/neurun/core/include/ir/operation/InstanceNorm.h
new file mode 100644
index 000000000..cbd03ad1f
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_INSTANCE_NORM_H__
+#define __NEURUN_IR_OPERATION_INSTANCE_NORM_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_INSTANCE_NORM_H__
diff --git a/runtime/neurun/core/include/ir/operation/L2Normalization.h b/runtime/neurun/core/include/ir/operation/L2Normalization.h
new file mode 100644
index 000000000..e2c1f4eee
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/L2Normalization.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 __NEURUN_IR_OPERATION_L2_NORMALIZATION_H__
+#define __NEURUN_IR_OPERATION_L2_NORMALIZATION_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class L2Normalization : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ struct Param
+ {
+ int32_t rank;
+ };
+
+public:
+ L2Normalization(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::L2Normalization; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_L2_NORMALIZATION_H__
diff --git a/runtime/neurun/core/include/ir/operation/L2Pool2D.h b/runtime/neurun/core/include/ir/operation/L2Pool2D.h
new file mode 100644
index 000000000..6d4d72ee2
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/L2Pool2D.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 __NEURUN_IR_OPERATION_L2_POOL_2D_H__
+#define __NEURUN_IR_OPERATION_L2_POOL_2D_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class L2Pool2D : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ };
+
+ struct Param
+ {
+ Padding padding;
+ Stride stride;
+ uint32_t kw;
+ uint32_t kh;
+ Activation activation;
+ };
+
+public:
+ L2Pool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::L2Pool2D; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_L2_POOL_2D_H__
diff --git a/runtime/neurun/core/include/ir/operation/LSTM.h b/runtime/neurun/core/include/ir/operation/LSTM.h
new file mode 100644
index 000000000..2ea09b1b7
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/LSTM.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __NEURUN_IR_OPERATION_LSTM_H__
+#define __NEURUN_IR_OPERATION_LSTM_H__
+
+#include "ir/InternalType.h"
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+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,
+ };
+
+ 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;
+ };
+
+public:
+ LSTM(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::LSTM; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_LSTM_H__
diff --git a/runtime/neurun/core/include/ir/operation/LocalResponseNormalization.h b/runtime/neurun/core/include/ir/operation/LocalResponseNormalization.h
new file mode 100644
index 000000000..3fbf2e4ae
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__
+#define __NEURUN_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__
diff --git a/runtime/neurun/core/include/ir/operation/LogicalAnd.h b/runtime/neurun/core/include/ir/operation/LogicalAnd.h
new file mode 100644
index 000000000..f7b03d62d
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/LogicalAnd.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 __NEURUN_IR_OPERATION_LOGICAL_AND_H__
+#define __NEURUN_IR_OPERATION_LOGICAL_AND_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class LogicalAnd : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT0 = 0,
+ INPUT1 = 1,
+ };
+
+public:
+ LogicalAnd(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::LogicalAnd; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_LOGICAL_AND_H__
diff --git a/runtime/neurun/core/include/ir/operation/LogicalNot.h b/runtime/neurun/core/include/ir/operation/LogicalNot.h
new file mode 100644
index 000000000..e689d57b2
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/LogicalNot.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 __NEURUN_IR_OPERATION_LOGICAL_NOT_H__
+#define __NEURUN_IR_OPERATION_LOGICAL_NOT_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class LogicalNot : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ };
+
+public:
+ LogicalNot(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::LogicalNot; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_LOGICAL_NOT_H__
diff --git a/runtime/neurun/core/include/ir/operation/LogicalOr.h b/runtime/neurun/core/include/ir/operation/LogicalOr.h
new file mode 100644
index 000000000..fda6b20d7
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/LogicalOr.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 __NEURUN_IR_OPERATION_LOGICAL_OR_H__
+#define __NEURUN_IR_OPERATION_LOGICAL_OR_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class LogicalOr : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT0 = 0,
+ INPUT1 = 1,
+ };
+
+public:
+ LogicalOr(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::LogicalOr; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_LOGICAL_OR_H__
diff --git a/runtime/neurun/core/include/ir/operation/Logistic.h b/runtime/neurun/core/include/ir/operation/Logistic.h
new file mode 100644
index 000000000..b23e7ef3f
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Logistic.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 __NEURUN_IR_OPERATION_LOGISTIC_H__
+#define __NEURUN_IR_OPERATION_LOGISTIC_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Logistic : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Logistic(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Logistic; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_LOGISTIC_H__
diff --git a/runtime/neurun/core/include/ir/operation/LowerInfo.h b/runtime/neurun/core/include/ir/operation/LowerInfo.h
new file mode 100644
index 000000000..856976a0c
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_LOWER_INFO_H__
+#define __NEURUN_IR_OPERATION_LOWER_INFO_H__
+
+#include <string>
+
+#include <ir/operand/PermuteFactor.h>
+
+namespace neurun
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace neurun
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_LOWER_INFO_H__
diff --git a/runtime/neurun/core/include/ir/operation/Max.h b/runtime/neurun/core/include/ir/operation/Max.h
new file mode 100644
index 000000000..1675f9f72
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Max.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 __NEURUN_IR_OPERATION_MAX_H__
+#define __NEURUN_IR_OPERATION_MAX_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Max : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+public:
+ Max(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Max; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_MAX_H__
diff --git a/runtime/neurun/core/include/ir/operation/MaxPool2D.h b/runtime/neurun/core/include/ir/operation/MaxPool2D.h
new file mode 100644
index 000000000..c0f0939aa
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/MaxPool2D.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERATION_MAXPOOL2D_H__
+#define __NEURUN_IR_OPERATION_MAXPOOL2D_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class MaxPool2D : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ uint32_t kh;
+ uint32_t kw;
+ Stride stride;
+ Padding padding;
+ Activation activation;
+ };
+
+public:
+ MaxPool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::MaxPool2D; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_MAXPOOL2D_H__
diff --git a/runtime/neurun/core/include/ir/operation/Mean.h b/runtime/neurun/core/include/ir/operation/Mean.h
new file mode 100644
index 000000000..cce8de377
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Mean.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 __NEURUN_IR_OPERATION_MEAN_H__
+#define __NEURUN_IR_OPERATION_MEAN_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Mean : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT
+ };
+
+ struct Param
+ {
+ std::vector<int> axes;
+ bool keep_dims;
+ int32_t rank;
+ };
+
+public:
+ Mean(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Mean; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_MEAN_H__
diff --git a/runtime/neurun/core/include/ir/operation/Min.h b/runtime/neurun/core/include/ir/operation/Min.h
new file mode 100644
index 000000000..fac901f21
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Min.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 __NEURUN_IR_OPERATION_MIN_H__
+#define __NEURUN_IR_OPERATION_MIN_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Min : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+public:
+ Min(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Min; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_MIN_H__
diff --git a/runtime/neurun/core/include/ir/operation/Mul.h b/runtime/neurun/core/include/ir/operation/Mul.h
new file mode 100644
index 000000000..f6cfe2afb
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Mul.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 __NEURUN_IR_OPERATION_MUL_H__
+#define __NEURUN_IR_OPERATION_MUL_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Mul : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+ struct Param
+ {
+ Activation activation;
+ };
+
+public:
+ Mul(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Mul; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_MUL_H__
diff --git a/runtime/neurun/core/include/ir/operation/Neg.h b/runtime/neurun/core/include/ir/operation/Neg.h
new file mode 100644
index 000000000..ec364f8ad
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Neg.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 __NEURUN_IR_OPERATION_NEG_H__
+#define __NEURUN_IR_OPERATION_NEG_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Neg : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Neg(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Neg; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_NEG_H__
diff --git a/runtime/neurun/core/include/ir/operation/OneHot.h b/runtime/neurun/core/include/ir/operation/OneHot.h
new file mode 100644
index 000000000..5fbc5d45f
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_ONEHOT_H__
+#define __NEURUN_IR_OPERATION_ONEHOT_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_ONEHOT_H__
diff --git a/runtime/neurun/core/include/ir/operation/PReLU.h b/runtime/neurun/core/include/ir/operation/PReLU.h
new file mode 100644
index 000000000..8c00c46fd
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_PRELU_H__
+#define __NEURUN_IR_OPERATION_PRELU_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_PRELU_H__
diff --git a/runtime/neurun/core/include/ir/operation/Pack.h b/runtime/neurun/core/include/ir/operation/Pack.h
new file mode 100644
index 000000000..ccf73fe5c
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Pack.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 __NEURUN_IR_OPERATION_PACK_H__
+#define __NEURUN_IR_OPERATION_PACK_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+class Pack : public Operation
+{
+public:
+ struct Param
+ {
+ int32_t num;
+ int32_t axis;
+ int32_t rank;
+ };
+
+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 neurun
+#endif // __NEURUN_IR_OPERATION_PACK_H__
diff --git a/runtime/neurun/core/include/ir/operation/Pad.h b/runtime/neurun/core/include/ir/operation/Pad.h
new file mode 100644
index 000000000..8e8304fae
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Pad.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 __NEURUN_IR_OPERATION_PAD_H__
+#define __NEURUN_IR_OPERATION_PAD_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Pad : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ PAD = 1,
+ // VALUE = 2 Not allow padding value operand yet
+ };
+
+public:
+ struct Param
+ {
+ int32_t rank;
+ };
+
+public:
+ Pad(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Pad; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_PAD_H__
diff --git a/runtime/neurun/core/include/ir/operation/Permute.h b/runtime/neurun/core/include/ir/operation/Permute.h
new file mode 100644
index 000000000..f91f9571b
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Permute.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERATION_PERMUTE_H__
+#define __NEURUN_IR_OPERATION_PERMUTE_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace backend
+{
+class BackendContext;
+} // namespace backend
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Permute : public Operation
+{
+public:
+ enum class Type
+ {
+ NHWC_TO_NCHW,
+ NCHW_TO_NHWC,
+ COPY
+ };
+
+ struct Param
+ {
+ const backend::BackendContext *input_backend_ctx;
+ const backend::BackendContext *output_backend_ctx;
+ };
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Permute; }
+
+public:
+ Permute(const OperandIndex &input, const OperandIndex &output,
+ const backend::BackendContext *input_backend_ctx,
+ const backend::BackendContext *output_backend_ctx, Type type,
+ DataType data_type = DataType::FLOAT32);
+
+public:
+ const Param &param() const { return _param; }
+ DataType getDataType() const { return _dataType; }
+ Type getPermuteType() const { return _type; }
+
+private:
+ Param _param;
+ Type _type;
+ DataType _dataType;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_PERMUTE_H__
diff --git a/runtime/neurun/core/include/ir/operation/RNN.h b/runtime/neurun/core/include/ir/operation/RNN.h
new file mode 100644
index 000000000..d812a6fc3
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_RNN_H__
+#define __NEURUN_IR_OPERATION_RNN_H__
+
+#include "ir/InternalType.h"
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_RNN_H__
diff --git a/runtime/neurun/core/include/ir/operation/RSQRT.h b/runtime/neurun/core/include/ir/operation/RSQRT.h
new file mode 100644
index 000000000..33648555a
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/RSQRT.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 __NEURUN_IR_OPERATION_RSQRT_H__
+#define __NEURUN_IR_OPERATION_RSQRT_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class RSQRT : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ RSQRT(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::RSQRT; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_RSQRT_H__
diff --git a/runtime/neurun/core/include/ir/operation/ReLU.h b/runtime/neurun/core/include/ir/operation/ReLU.h
new file mode 100644
index 000000000..b6c7fdf01
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/ReLU.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 __NEURUN_IR_OPERATION_RELU_H__
+#define __NEURUN_IR_OPERATION_RELU_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class ReLU : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ ReLU(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ReLU; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_RELU_H__
diff --git a/runtime/neurun/core/include/ir/operation/ReLU1.h b/runtime/neurun/core/include/ir/operation/ReLU1.h
new file mode 100644
index 000000000..ac45fda05
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/ReLU1.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 __NEURUN_IR_OPERATION_ReLU1_H__
+#define __NEURUN_IR_OPERATION_ReLU1_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class ReLU1 : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ ReLU1(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ReLU1; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_ReLU1_H__
diff --git a/runtime/neurun/core/include/ir/operation/ReLU6.h b/runtime/neurun/core/include/ir/operation/ReLU6.h
new file mode 100644
index 000000000..4d98dad55
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/ReLU6.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 __NEURUN_IR_OPERATION_ReLU6_H__
+#define __NEURUN_IR_OPERATION_ReLU6_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class ReLU6 : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ ReLU6(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ReLU6; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_ReLU6_H__
diff --git a/runtime/neurun/core/include/ir/operation/ReduceMax.h b/runtime/neurun/core/include/ir/operation/ReduceMax.h
new file mode 100644
index 000000000..da4d7c4cc
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/ReduceMax.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 __NEURUN_IR_OPERATION_REDUCEMAX_H__
+#define __NEURUN_IR_OPERATION_REDUCEMAX_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class ReduceMax : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ std::vector<int> axes;
+ bool keep_dims;
+ int32_t rank;
+ };
+
+public:
+ ReduceMax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ReduceMax; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_REDUCEMAX_H__
diff --git a/runtime/neurun/core/include/ir/operation/ReduceMin.h b/runtime/neurun/core/include/ir/operation/ReduceMin.h
new file mode 100644
index 000000000..f79fdeaea
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/ReduceMin.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 __NEURUN_IR_OPERATION_REDUCEMIN_H__
+#define __NEURUN_IR_OPERATION_REDUCEMIN_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class ReduceMin : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ std::vector<int> axes;
+ bool keep_dims;
+ int32_t rank;
+ };
+
+public:
+ ReduceMin(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ReduceMin; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_REDUCEMIN_H__
diff --git a/runtime/neurun/core/include/ir/operation/ReduceSum.h b/runtime/neurun/core/include/ir/operation/ReduceSum.h
new file mode 100644
index 000000000..b5ab8ee75
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/ReduceSum.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 __NEURUN_IR_OPERATION_REDUCE_SUM_H__
+#define __NEURUN_IR_OPERATION_REDUCE_SUM_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class ReduceSum : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ std::vector<int> axes;
+ bool keep_dims;
+ int32_t rank;
+ };
+
+public:
+ ReduceSum(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::ReduceSum; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_REDUCE_SUM_H__
diff --git a/runtime/neurun/core/include/ir/operation/Reshape.h b/runtime/neurun/core/include/ir/operation/Reshape.h
new file mode 100644
index 000000000..e476d7fe1
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Reshape.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_IR_OPERATION_RESHAPE_H__
+#define __NEURUN_IR_OPERATION_RESHAPE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Reshape : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Reshape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Reshape; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_RESHAPE_H__
diff --git a/runtime/neurun/core/include/ir/operation/ResizeBilinear.h b/runtime/neurun/core/include/ir/operation/ResizeBilinear.h
new file mode 100644
index 000000000..d937da00c
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/ResizeBilinear.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 __NEURUN_IR_OPERATION_RESIZE_BILINEAR_H__
+#define __NEURUN_IR_OPERATION_RESIZE_BILINEAR_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class ResizeBilinear : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ int32_t height_out;
+ int32_t width_out;
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_RESIZE_BILINEAR_H__
diff --git a/runtime/neurun/core/include/ir/operation/SQRT.h b/runtime/neurun/core/include/ir/operation/SQRT.h
new file mode 100644
index 000000000..5e21315b4
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/SQRT.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 __NEURUN_IR_OPERATION_SQRT_H__
+#define __NEURUN_IR_OPERATION_SQRT_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class SQRT : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ SQRT(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::SQRT; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_SQRT_H__
diff --git a/runtime/neurun/core/include/ir/operation/Slice.h b/runtime/neurun/core/include/ir/operation/Slice.h
new file mode 100644
index 000000000..4b79f42a6
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Slice.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 __NEURUN_IR_OPERATION_SLICE_H__
+#define __NEURUN_IR_OPERATION_SLICE_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Slice : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ BEGINS = 1,
+ SIZES = 2,
+ };
+
+public:
+ struct Param
+ {
+ int32_t rank;
+ };
+
+public:
+ Slice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Slice; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_SLICE_H__
diff --git a/runtime/neurun/core/include/ir/operation/Softmax.h b/runtime/neurun/core/include/ir/operation/Softmax.h
new file mode 100644
index 000000000..a3e896fed
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_SOFTMAX_H__
+#define __NEURUN_IR_OPERATION_SOFTMAX_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_SOFTMAX_H__
diff --git a/runtime/neurun/core/include/ir/operation/SpaceToBatchND.h b/runtime/neurun/core/include/ir/operation/SpaceToBatchND.h
new file mode 100644
index 000000000..4ca0978b0
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_SPACE_TO_BATCH_ND_H__
+#define __NEURUN_IR_OPERATION_SPACE_TO_BATCH_ND_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_SPACE_TO_BATCH_ND_H__
diff --git a/runtime/neurun/core/include/ir/operation/SpaceToDepth.h b/runtime/neurun/core/include/ir/operation/SpaceToDepth.h
new file mode 100644
index 000000000..9e77bdae0
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_SPACE_TO_DEPTH_H__
+#define __NEURUN_IR_OPERATION_SPACE_TO_DEPTH_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_SPACE_TO_DEPTH_H__
diff --git a/runtime/neurun/core/include/ir/operation/Split.h b/runtime/neurun/core/include/ir/operation/Split.h
new file mode 100644
index 000000000..7a2749e84
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Split.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 __NEURUN_IR_OPERATION_SPLIT_H__
+#define __NEURUN_IR_OPERATION_SPLIT_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+class Split : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ int axis;
+ int num_splits;
+ int rank;
+ };
+
+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 neurun
+#endif // __NEURUN_IR_OPERATION_SPLIT_H__
diff --git a/runtime/neurun/core/include/ir/operation/SquaredDifference.h b/runtime/neurun/core/include/ir/operation/SquaredDifference.h
new file mode 100644
index 000000000..46df419f5
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_SQUARED_DIFFERENCE_H__
+#define __NEURUN_IR_OPERATION_SQUARED_DIFFERENCE_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_SQUARED_DIFFERENCE_H__
diff --git a/runtime/neurun/core/include/ir/operation/Squeeze.h b/runtime/neurun/core/include/ir/operation/Squeeze.h
new file mode 100644
index 000000000..d27b315b5
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_SQUEEZE_H__
+#define __NEURUN_IR_OPERATION_SQUEEZE_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_SQUEEZE_H__
diff --git a/runtime/neurun/core/include/ir/operation/StridedSlice.h b/runtime/neurun/core/include/ir/operation/StridedSlice.h
new file mode 100644
index 000000000..868bda72c
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/StridedSlice.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 __NEURUN_IR_OPERATION_STRIDED_SLICE_H__
+#define __NEURUN_IR_OPERATION_STRIDED_SLICE_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class StridedSlice : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0,
+ STARTS = 1,
+ ENDS = 2,
+ STRIDES = 3
+ };
+
+ struct Param
+ {
+ std::int32_t begin_mask;
+ std::int32_t end_mask;
+ std::int32_t shrink_axis_mask;
+ int32_t rank;
+ };
+
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_STRIDED_SLICE_H__
diff --git a/runtime/neurun/core/include/ir/operation/Sub.h b/runtime/neurun/core/include/ir/operation/Sub.h
new file mode 100644
index 000000000..e5850af8c
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Sub.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 __NEURUN_IR_OPERATION_SUB_H__
+#define __NEURUN_IR_OPERATION_SUB_H__
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Sub : public Operation
+{
+public:
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+ struct Param
+ {
+ Activation activation;
+ };
+
+public:
+ Sub(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Sub; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_SUB_H__
diff --git a/runtime/neurun/core/include/ir/operation/Tanh.h b/runtime/neurun/core/include/ir/operation/Tanh.h
new file mode 100644
index 000000000..814ceec5a
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Tanh.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 __NEURUN_IR_OPERATION_TANH_H__
+#define __NEURUN_IR_OPERATION_TANH_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Tanh : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+public:
+ Tanh(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Tanh; }
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_TANH_H__
diff --git a/runtime/neurun/core/include/ir/operation/TopKV2.h b/runtime/neurun/core/include/ir/operation/TopKV2.h
new file mode 100644
index 000000000..a6971e843
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_OPERATION_TOPK_V2_H__
+#define __NEURUN_IR_OPERATION_TOPK_V2_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_TOPK_V2_H__
diff --git a/runtime/neurun/core/include/ir/operation/Transpose.h b/runtime/neurun/core/include/ir/operation/Transpose.h
new file mode 100644
index 000000000..b1e08a506
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Transpose.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 __NEURUN_IR_OPERATION_TRANSPOSE_H__
+#define __NEURUN_IR_OPERATION_TRANSPOSE_H__
+
+#include "ir/Operation.h"
+
+#include <utility>
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+class Transpose : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0, // for an n-D tensor, specifying the tensor to be transposed.
+ };
+
+ struct Param
+ {
+ std::vector<int> perm;
+ int32_t rank;
+ };
+
+public:
+ Transpose(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param);
+
+public:
+ void accept(OperationVisitor &v) const override;
+ OpCode opcode() const final { return OpCode::Transpose; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_OPERATION_TRANSPOSE_H__
diff --git a/runtime/neurun/core/include/ir/operation/TransposeConv.h b/runtime/neurun/core/include/ir/operation/TransposeConv.h
new file mode 100644
index 000000000..a561db4e4
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/TransposeConv.h
@@ -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.
+ */
+
+#ifndef __NEURUN_IR_OPERATION_TRANSPOSE_CONV_H__
+#define __NEURUN_IR_OPERATION_TRANSPOSE_CONV_H__
+
+#include <memory>
+
+#include "ir/Operation.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_OPERATION_TRANSPOSE_CONV_H__
diff --git a/runtime/neurun/core/include/ir/operation/Unpack.h b/runtime/neurun/core/include/ir/operation/Unpack.h
new file mode 100644
index 000000000..fa698d3af
--- /dev/null
+++ b/runtime/neurun/core/include/ir/operation/Unpack.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 __NEURUN_IR_OPERATION_UNPACK_H__
+#define __NEURUN_IR_OPERATION_UNPACK_H__
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+class Unpack : public Operation
+{
+public:
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ int32_t num;
+ int32_t axis;
+ int32_t rank;
+ };
+
+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 neurun
+#endif // __NEURUN_IR_OPERATION_UNPACK_H__
diff --git a/runtime/neurun/core/include/util/Config.lst b/runtime/neurun/core/include/util/Config.lst
new file mode 100644
index 000000000..046a0c4a8
--- /dev/null
+++ b/runtime/neurun/core/include/util/Config.lst
@@ -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 CONFIG
+#error Define CONFIG before including this file
+#endif
+
+// Name | Type | Default
+CONFIG(GRAPH_DOT_DUMP , int , "0")
+CONFIG(BACKENDS , std::string , "acl_cl;acl_neon;cpu;srcn")
+CONFIG(OP_BACKEND_ALLOPS , std::string , "")
+CONFIG(OP_BACKEND_MAP , std::string , "")
+CONFIG(DISABLE_COMPILE , bool , "0")
+CONFIG(NEURUN_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(SUBG_MAX_NODE , int , "0")
+CONFIG(TRACE_FILEPATH , std::string , "")
+
+// Auto-generate all operations
+
+#define OP(InternalName) \
+ CONFIG(OP_BACKEND_ ## InternalName, std::string, "")
+#include "ir/Operations.lst"
+#undef OP
+
diff --git a/runtime/neurun/core/include/util/ConfigSource.h b/runtime/neurun/core/include/util/ConfigSource.h
new file mode 100644
index 000000000..b1fa9a87d
--- /dev/null
+++ b/runtime/neurun/core/include/util/ConfigSource.h
@@ -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.
+ */
+
+#ifndef __NEURUN_UTIL_CONFIG_SOURCE_H__
+#define __NEURUN_UTIL_CONFIG_SOURCE_H__
+
+#include <memory>
+
+#include "IConfigSource.h"
+
+namespace neurun
+{
+namespace util
+{
+
+void config_source(std::unique_ptr<IConfigSource> &&source);
+
+bool getConfigBool(const std::string &key);
+int getConfigInt(const std::string &key);
+std::string getConfigString(const std::string &key);
+
+} // namespace util
+} // namespace neurun
+
+namespace neurun
+{
+namespace util
+{
+namespace config
+{
+
+#define CONFIG(Name, Type, Default) extern const char *Name;
+
+#include "Config.lst"
+
+#undef CONFIG
+
+} // namespace config
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_CONFIG_SOURCE_H__
diff --git a/runtime/neurun/core/include/util/Coordinates.h b/runtime/neurun/core/include/util/Coordinates.h
new file mode 100644
index 000000000..67947138f
--- /dev/null
+++ b/runtime/neurun/core/include/util/Coordinates.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_UTIL_COORDINATES_H__
+#define __NEURUN_UTIL_COORDINATES_H__
+
+#include <cassert>
+#include <stdint.h>
+#include <vector>
+
+namespace neurun
+{
+namespace util
+{
+
+/**
+ * @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
+ * @param[in] init The initialzer_list with coordinates
+ * @return
+ */
+ Coordinates(std::initializer_list<int32_t> init) : _coordinates{init}
+ {
+ assert(init.size() <= num_max_dimensions);
+ }
+
+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;
+};
+
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_COORDINATES_H__
diff --git a/runtime/neurun/core/include/util/EnvConfigSource.h b/runtime/neurun/core/include/util/EnvConfigSource.h
new file mode 100644
index 000000000..77be15c4e
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_UTIL_ENV_CONFIG_SOURCE_H__
+#define __NEURUN_UTIL_ENV_CONFIG_SOURCE_H__
+
+#include <unordered_map>
+
+#include "util/GeneralConfigSource.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_UTIL_ENV_CONFIG_SOURCE_H__
diff --git a/runtime/neurun/core/include/util/EventCollectorGlobal.h b/runtime/neurun/core/include/util/EventCollectorGlobal.h
new file mode 100644
index 000000000..15e40844e
--- /dev/null
+++ b/runtime/neurun/core/include/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 __NEURUN_UTIL_EVENT_COLLECTOR_GLOBAL_H__
+#define __NEURUN_UTIL_EVENT_COLLECTOR_GLOBAL_H__
+
+#include "misc/EventRecorder.h"
+#include "misc/EventCollector.h"
+
+namespace neurun
+{
+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 neurun
+
+/**
+ * Helper Macro Definitions
+ *
+ * HOW TO USE
+ *
+ * void f(args)
+ * {
+ * EVENT_DURATION_FUNCTION();
+ * ...
+ * if(cond)
+ * {
+ * EVENT_DURATION_REGION("if branch");
+ * ...
+ * }
+ * ...
+ * }
+ */
+
+#define EVENT_DURATION_FUNCTION() \
+ ::neurun::util::EventDurationBlock __event_duration__##__LINE__ { __FUNCTION__ }
+
+#define EVENT_DURATION_REGION(tag) \
+ ::neurun::util::EventDurationBlock __event_duration__##__LINE__ { tag }
+
+#endif // __NEURUN_UTIL_EVENT_COLLECTOR_GLOBAL_H__
diff --git a/runtime/neurun/core/include/util/GeneralConfigSource.h b/runtime/neurun/core/include/util/GeneralConfigSource.h
new file mode 100644
index 000000000..04e3332b3
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_UTIL_GLOBAL_CONFIG_SOURCE_H__
+#define __NEURUN_UTIL_GLOBAL_CONFIG_SOURCE_H__
+
+#include <unordered_map>
+
+#include "util/IConfigSource.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_UTIL_GLOBAL_CONFIG_SOURCE_H__
diff --git a/runtime/neurun/core/include/util/IConfigSource.h b/runtime/neurun/core/include/util/IConfigSource.h
new file mode 100644
index 000000000..a52d87097
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_UTIL_I_CONFIG_SOURCE_H__
+#define __NEURUN_UTIL_I_CONFIG_SOURCE_H__
+
+#include <string>
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_UTIL_I_CONFIG_SOURCE_H__
diff --git a/runtime/neurun/core/include/util/ITimer.h b/runtime/neurun/core/include/util/ITimer.h
new file mode 100644
index 000000000..79ecdd0ca
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_UTIL_ITIMER_H__
+#define __NEURUN_UTIL_ITIMER_H__
+
+#include <chrono>
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_UTIL_ITIMER_H__
diff --git a/runtime/neurun/core/include/util/Index.h b/runtime/neurun/core/include/util/Index.h
new file mode 100644
index 000000000..bd8eeb38c
--- /dev/null
+++ b/runtime/neurun/core/include/util/Index.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_UTIL_INDEX_H__
+#define __NEURUN_UTIL_INDEX_H__
+
+#include <functional>
+#include <limits>
+#include <stdint.h>
+
+namespace neurun
+{
+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 Return underlying value
+ *
+ * @return T Underlying value
+ */
+ T value() const { return _index; }
+
+private:
+ T _index;
+};
+
+} // namespace util
+} // namespace neurun
+
+namespace std
+{
+
+template <typename T, typename Tag> struct hash<::neurun::util::Index<T, Tag>>
+{
+ size_t operator()(const ::neurun::util::Index<T, Tag> &index) const noexcept
+ {
+ return hash<T>()(index.value());
+ }
+};
+
+} // namespace std
+
+#endif // __NEURUN_UTIL_INDEX_H__
diff --git a/runtime/neurun/core/include/util/ObjectManager.h b/runtime/neurun/core/include/util/ObjectManager.h
new file mode 100644
index 000000000..fd2c3f295
--- /dev/null
+++ b/runtime/neurun/core/include/util/ObjectManager.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_UTIL_OBJECT_MANAGER_H__
+#define __NEURUN_UTIL_OBJECT_MANAGER_H__
+
+#include <unordered_map>
+#include <memory>
+
+namespace neurun
+{
+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, nnfw::cpp14::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++}; }
+
+private:
+ std::unordered_map<Index, std::unique_ptr<Object>> _objects;
+ uint32_t _index_count;
+};
+
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_OBJECT_MANAGER_H__
diff --git a/runtime/neurun/core/include/util/Padding.h b/runtime/neurun/core/include/util/Padding.h
new file mode 100644
index 000000000..3c707b873
--- /dev/null
+++ b/runtime/neurun/core/include/util/Padding.h
@@ -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.
+ */
+
+#ifndef __NEURUN_UTIL_PADDING_H__
+#define __NEURUN_UTIL_PADDING_H__
+
+#include <stdint.h>
+
+#include "ir/Shape.h"
+#include "ir/InternalType.h"
+
+namespace neurun
+{
+namespace util
+{
+
+ir::ExplicitPadding validPadding(void);
+ir::ExplicitPadding samePadding(const ir::FeatureShape &ifm_shape,
+ const ir::FeatureShape &ofm_shape, const ir::Stride &stride,
+ uint32_t kw, uint32_t kh);
+ir::ExplicitPadding calculatePadding(const ir::Padding &padding, const ir::FeatureShape &ifm_shape,
+ const ir::FeatureShape &ofm_shape, const ir::Stride &stride,
+ uint32_t kw, uint32_t kh);
+
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_PADDING_H__
diff --git a/runtime/neurun/core/include/util/Set.h b/runtime/neurun/core/include/util/Set.h
new file mode 100644
index 000000000..13213511d
--- /dev/null
+++ b/runtime/neurun/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 neurun::util::Set class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NEURUN_UTIL_SET_H__
+#define __NEURUN_UTIL_SET_H__
+
+#include <cassert>
+#include <unordered_set>
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_UTIL_SET_H__
diff --git a/runtime/neurun/core/include/util/ShapeInference.h b/runtime/neurun/core/include/util/ShapeInference.h
new file mode 100644
index 000000000..097d61643
--- /dev/null
+++ b/runtime/neurun/core/include/util/ShapeInference.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 __NEURUN_GRAPH_SHAPE_INFERENCE_H__
+#define __NEURUN_GRAPH_SHAPE_INFERENCE_H__
+
+#include "ir/operation/AvgPool2D.h"
+#include "ir/operation/Concat.h"
+#include "ir/operation/MaxPool2D.h"
+#include "ir/operation/Conv2D.h"
+#include "ir/operation/DepthwiseConv2D.h"
+#include "ir/Operands.h"
+#include "ir/Index.h"
+#include "ir/Layout.h"
+
+namespace neurun
+{
+namespace shape_inference
+{
+
+using Shapes = std::vector<ir::Shape>;
+
+Shapes inferEltwiseShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape);
+
+Shapes inferAvgPoolShape(const ir::Shape &in_shape, const ir::operation::AvgPool2D::Param &param,
+ ir::Layout layout = ir::Layout::NHWC);
+
+Shapes inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param &param);
+
+Shapes inferMaxPoolShape(const ir::Shape &in_shape, const ir::operation::MaxPool2D::Param &param,
+ ir::Layout layout = ir::Layout::NHWC);
+
+Shapes inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::Conv2D::Param &param,
+ ir::Layout layout = ir::Layout::NHWC);
+
+Shapes inferDepthwiseConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::DepthwiseConv2D::Param &param,
+ ir::Layout layout = ir::Layout::NHWC);
+
+Shapes inferFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &ker_shape);
+
+} // namespace shape_inference
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_SHAPE_INFERENCE_H__
diff --git a/runtime/neurun/core/include/util/Utils.h b/runtime/neurun/core/include/util/Utils.h
new file mode 100644
index 000000000..e7468dabd
--- /dev/null
+++ b/runtime/neurun/core/include/util/Utils.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 functions
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NEURUN_UTIL_UTILS_H__
+#define __NEURUN_UTIL_UTILS_H__
+
+#include "ir/InternalType.h"
+#include "ir/Layout.h"
+#include "ir/Operand.h"
+#include "util/Coordinates.h"
+
+#define UNUSED_RELEASE(a) (void)(a)
+
+namespace neurun
+{
+namespace util
+{
+
+/**
+ * @brief Converts a internal padding type to const char*
+ * @param[in] type Padding type to be converted
+ * @return A string holding the converted value
+ */
+const char *to_string(ir::PaddingType type);
+
+Coordinates convertCoordinates(const Coordinates &from_coordinates, ir::Layout from_layout,
+ ir::Layout to_layout);
+
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_UTILS_H__
diff --git a/runtime/neurun/core/include/util/feature/Coordinate4D.h b/runtime/neurun/core/include/util/feature/Coordinate4D.h
new file mode 100644
index 000000000..b020ed239
--- /dev/null
+++ b/runtime/neurun/core/include/util/feature/Coordinate4D.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__
+#define __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__
+
+#include <stdint.h>
+
+namespace neurun
+{
+namespace util
+{
+namespace feature
+{
+
+/**
+ * @brief Class to represent position(offset) of subtensor.\n
+ * Assume that parent and child are already lowered (can get Shape4D).
+ */
+class Coordinate4D
+{
+public:
+ /**
+ * @brief Construct a new Coordinate4D object
+ */
+ Coordinate4D(void) : _n{0}, _h{0}, _w{0}, _c{0}
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct a new Coordinate4D object
+ * @param[in] n Batch offset
+ * @param[in] h Height offset
+ * @param[in] w Width offset
+ * @param[in] c Channel offset
+ * @return
+ */
+ Coordinate4D(int32_t n, int32_t h, int32_t w, int32_t c) : _n{n}, _h{h}, _w{w}, _c{c}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Set batch offset
+ * @param[in] n Batch offset
+ */
+ void n(int32_t n) { _n = n; }
+ /**
+ * @brief Set height offset
+ * @param[in] h Height offset
+ */
+ void h(int32_t h) { _h = h; }
+ /**
+ * @brief Set width offset
+ * @param[in] w Width offset
+ */
+ void w(int32_t w) { _w = w; }
+ /**
+ * @brief Set channel offset
+ * @param[in] c Channel offset
+ */
+ void c(int32_t c) { _c = c; }
+
+public:
+ /**
+ * @brief Return batch offset
+ * @return Batch offset
+ */
+ int32_t n(void) const { return _n; }
+ /**
+ * @brief Return height offset
+ * @return Height offset
+ */
+ int32_t h(void) const { return _h; }
+ /**
+ * @brief Return width offset
+ * @return Width offset
+ */
+ int32_t w(void) const { return _w; }
+ /**
+ * @brief Return channel offset
+ * @return Channel offset
+ */
+ int32_t c(void) const { return _c; }
+
+private:
+ int32_t _n;
+ int32_t _h;
+ int32_t _w;
+ int32_t _c;
+};
+
+} // namespace feature
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__
diff --git a/runtime/neurun/core/include/util/feature/nchw/Reader.h b/runtime/neurun/core/include/util/feature/nchw/Reader.h
new file mode 100644
index 000000000..0305bdf69
--- /dev/null
+++ b/runtime/neurun/core/include/util/feature/nchw/Reader.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_UTIL_FEATURE_NCHW_READER_H__
+#define __NEURUN_UTIL_FEATURE_NCHW_READER_H__
+
+#include <cassert>
+
+#include "backend/operand/ITensor.h"
+#include "misc/feature/Reader.h"
+#include "misc/feature/Shape.h"
+#include "util/Coordinates.h"
+#include "util/Utils.h"
+
+namespace neurun
+{
+namespace util
+{
+namespace feature
+{
+namespace nchw
+{
+
+template <typename T> class Reader final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ // Construct for buffer of model inputs
+ Reader(const ::nnfw::misc::feature::Shape &shape, const T *ptr, size_t len)
+ : _shape{shape}, _ptr{reinterpret_cast<const uint8_t *>(ptr)}, _len{len}
+ {
+ assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len);
+
+ // No padding
+ _strides.W = sizeof(T);
+ _strides.H = shape.W * sizeof(T);
+ _strides.C = shape.W * shape.H * sizeof(T);
+ _strides.N = shape.W * shape.H * shape.C * sizeof(T);
+ }
+
+ // Construct for backend tensor
+ Reader(backend::operand::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 ch, uint32_t row, uint32_t col) const override
+ {
+ const auto offset = feature_index_to_byte_offset(0, ch, row, col);
+
+ const T *ptr = reinterpret_cast<const T *>(_ptr + offset);
+
+ return *ptr;
+ }
+ T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ 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
+ nnfw::misc::feature::Shape _shape;
+ using Strides = nnfw::misc::feature::Shape;
+ Strides _strides;
+ const uint8_t *_ptr;
+ size_t _len;
+};
+
+} // namespace nchw
+} // namespace feature
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_FEATURE_NCHW_READER_H__
diff --git a/runtime/neurun/core/include/util/feature/nchw/View.h b/runtime/neurun/core/include/util/feature/nchw/View.h
new file mode 100644
index 000000000..d747937ee
--- /dev/null
+++ b/runtime/neurun/core/include/util/feature/nchw/View.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__
+#define __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__
+
+#include "misc/feature/Reader.h"
+#include "misc/feature/Shape.h"
+
+#include "backend/operand/ITensor.h"
+#include "util/Coordinates.h"
+#include "util/Utils.h"
+
+#include <cassert>
+
+namespace neurun
+{
+namespace util
+{
+namespace feature
+{
+namespace nchw
+{
+
+template <typename T> class View final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ // Construct for buffer of model inputs
+ View(const ::nnfw::misc::feature::Shape &shape, T *ptr, size_t len)
+ : _shape{shape}, _ptr{reinterpret_cast<uint8_t *>(ptr)}, _len{len}
+ {
+ assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len);
+
+ _strides.W = sizeof(T);
+ _strides.H = shape.W * sizeof(T);
+ _strides.C = shape.W * shape.H * sizeof(T);
+ _strides.N = shape.W * shape.H * shape.C * sizeof(T);
+ }
+
+ // Construct for backend tensor
+ View(::neurun::backend::operand::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 ch, uint32_t row, uint32_t col) const override
+ {
+ const auto offset = feature_index_to_byte_offset(0, ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_ptr + offset);
+
+ return *ptr;
+ }
+ T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ const auto offset = feature_index_to_byte_offset(batch, ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_ptr + offset);
+
+ return *ptr;
+ }
+
+public:
+ T &at(uint32_t ch, uint32_t row, uint32_t col)
+ {
+ const auto offset = feature_index_to_byte_offset(0, ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_ptr + offset);
+
+ return *ptr;
+ }
+ T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col)
+ {
+ const auto offset = feature_index_to_byte_offset(batch, ch, row, col);
+
+ T *ptr = reinterpret_cast<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
+ nnfw::misc::feature::Shape _shape;
+ using Strides = nnfw::misc::feature::Shape;
+ Strides _strides;
+ uint8_t *_ptr;
+ size_t _len;
+};
+
+} // namespace nchw
+} // namespace feature
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__
diff --git a/runtime/neurun/core/include/util/feature/nhwc/Reader.h b/runtime/neurun/core/include/util/feature/nhwc/Reader.h
new file mode 100644
index 000000000..0df7be4be
--- /dev/null
+++ b/runtime/neurun/core/include/util/feature/nhwc/Reader.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_UTIL_FEATURE_NHWC_READER_H__
+#define __NEURUN_UTIL_FEATURE_NHWC_READER_H__
+
+#include <cassert>
+
+#include "backend/operand/ITensor.h"
+#include "misc/feature/Reader.h"
+#include "misc/feature/Shape.h"
+#include "util/Coordinates.h"
+#include "util/Utils.h"
+
+namespace neurun
+{
+namespace util
+{
+namespace feature
+{
+namespace nhwc
+{
+
+template <typename T> class Reader final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ // Construct for buffer of model inputs
+ Reader(const ::nnfw::misc::feature::Shape &shape, const T *ptr, size_t len)
+ : _shape{shape}, _ptr{reinterpret_cast<const uint8_t *>(ptr)}, _len{len}
+ {
+ UNUSED_RELEASE(len); // Workaround for unused variable in release mode
+ assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len);
+
+ // No padding
+ _strides.C = sizeof(T);
+ _strides.W = shape.C * sizeof(T);
+ _strides.H = shape.C * shape.W * sizeof(T);
+ _strides.N = shape.C * shape.W * shape.H * sizeof(T);
+ }
+
+ // Construct for backend tensor
+ Reader(const backend::operand::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 row, uint32_t col, uint32_t ch) const override
+ {
+ const auto offset = feature_index_to_byte_offset(0, row, col, ch);
+
+ const T *ptr = reinterpret_cast<const T *>(_ptr + offset);
+
+ return *ptr;
+ }
+ T at(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const override
+ {
+ 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
+ nnfw::misc::feature::Shape _shape;
+ using Strides = nnfw::misc::feature::Shape;
+ Strides _strides;
+ const uint8_t *_ptr;
+ size_t _len;
+};
+
+} // namespace nhwc
+} // namespace feature
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_FEATURE_NHWC_READER_H__
diff --git a/runtime/neurun/core/include/util/feature/nhwc/View.h b/runtime/neurun/core/include/util/feature/nhwc/View.h
new file mode 100644
index 000000000..b9d98e9fa
--- /dev/null
+++ b/runtime/neurun/core/include/util/feature/nhwc/View.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__
+#define __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__
+
+#include <cassert>
+#include <cstddef>
+
+#include "backend/operand/ITensor.h"
+#include "misc/feature/Reader.h"
+#include "misc/feature/Shape.h"
+#include "util/Coordinates.h"
+#include "util/Utils.h"
+
+namespace neurun
+{
+namespace util
+{
+namespace feature
+{
+namespace nhwc
+{
+
+template <typename T> class View final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ // Construct for buffer of model inputs
+ View(const ::nnfw::misc::feature::Shape &shape, T *ptr, size_t len)
+ : _shape{shape}, _ptr{reinterpret_cast<uint8_t *>(ptr)}, _len{len}
+ {
+ UNUSED_RELEASE(len); // Workaround for unused variable in release mode
+ assert(shape.N * shape.H * shape.W * shape.C * sizeof(T) == len);
+
+ // No padding
+ _strides.C = sizeof(T);
+ _strides.W = shape.C * sizeof(T);
+ _strides.H = shape.C * shape.W * sizeof(T);
+ _strides.N = shape.C * shape.W * shape.H * sizeof(T);
+ }
+
+ // Construct for backend tensor
+ View(backend::operand::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 row, uint32_t col, uint32_t ch) const override
+ {
+ const auto offset = feature_index_to_byte_offset(0, row, col, ch);
+
+ const T *ptr = reinterpret_cast<const T *>(_ptr + offset);
+
+ return *ptr;
+ }
+ T at(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const override
+ {
+ const auto offset = feature_index_to_byte_offset(batch, row, col, ch);
+
+ const T *ptr = reinterpret_cast<const T *>(_ptr + offset);
+
+ return *ptr;
+ }
+
+ T &at(uint32_t row, uint32_t col, uint32_t ch)
+ {
+ const auto offset = feature_index_to_byte_offset(0, row, col, ch);
+
+ T *ptr = reinterpret_cast<T *>(_ptr + offset);
+
+ return *ptr;
+ }
+
+ T &at(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch)
+ {
+ const auto offset = feature_index_to_byte_offset(batch, row, col, ch);
+
+ T *ptr = reinterpret_cast<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
+ nnfw::misc::feature::Shape _shape;
+ using Strides = nnfw::misc::feature::Shape;
+ Strides _strides;
+ uint8_t *_ptr;
+ size_t _len;
+};
+
+} // namespace nhwc
+} // namespace feature
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__
diff --git a/runtime/neurun/core/include/util/logging.h b/runtime/neurun/core/include/util/logging.h
new file mode 100644
index 000000000..8ecd0ac12
--- /dev/null
+++ b/runtime/neurun/core/include/util/logging.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 __NEURUN_UTIL_LOGGING_H__
+#define __NEURUN_UTIL_LOGGING_H__
+
+#include <iostream>
+
+#include "util/ConfigSource.h"
+
+namespace neurun
+{
+namespace util
+{
+namespace logging
+{
+
+class Context
+{
+public:
+ Context() noexcept : _enabled{false}
+ {
+ const auto env = util::getConfigBool(util::config::NEURUN_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 neurun
+
+#define VERBOSE(name) \
+ if (::neurun::util::logging::ctx.enabled()) \
+ std::cout << "[" << #name << "] "
+
+#endif // __NEURUN_UTIL_LOGGING_H__
diff --git a/runtime/neurun/core/src/backend/Backend.cc b/runtime/neurun/core/src/backend/Backend.cc
new file mode 100644
index 000000000..c2f745f8f
--- /dev/null
+++ b/runtime/neurun/core/src/backend/Backend.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/Backend.h"
+
+#include "backend/IConfig.h"
+#include "backend/ITensorBuilder.h"
+#include "backend/IKernelGenerator.h"
+#include "backend/IShapeFixer.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+} // namespace backend
+} // namespace neurun
diff --git a/runtime/neurun/core/src/backend/BackendManager.cc b/runtime/neurun/core/src/backend/BackendManager.cc
new file mode 100644
index 000000000..32086e8b6
--- /dev/null
+++ b/runtime/neurun/core/src/backend/BackendManager.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <dlfcn.h>
+#include "BackendManager.h"
+
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+#include "util/logging.h"
+#include "util/ConfigSource.h"
+#include "misc/string_helpers.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+BackendManager &BackendManager::get()
+{
+ static BackendManager object;
+ return object;
+}
+
+template <typename T, class... Types>
+void BackendManager::loadObjectFromPlugin(std::shared_ptr<T> &object_of_plugin_class,
+ const std::string obj_creator_func_name, void *handle,
+ Types &&... args)
+{
+ T *(*allocate_obj)(Types && ... Args);
+ // load object creator function
+ allocate_obj = (T * (*)(Types && ... Args))dlsym(handle, obj_creator_func_name.c_str());
+ if (allocate_obj == nullptr)
+ {
+ fprintf(stderr, "BackendManager: unable to open function %s: %s\n",
+ obj_creator_func_name.c_str(), dlerror());
+ abort();
+ }
+
+ object_of_plugin_class.reset(allocate_obj(args...));
+}
+
+void BackendManager::loadBackend(const std::string &backend)
+{
+ const std::string backend_plugin = "libbackend_" + backend + ".so";
+ void *handle = dlopen(backend_plugin.c_str(), RTLD_LAZY | RTLD_LOCAL);
+ if (handle == nullptr)
+ {
+ VERBOSE(BackendManager::loadBackend) << "loadBackend failed to load plugin of "
+ << backend.c_str() << " backend: " << dlerror()
+ << std::endl;
+ return;
+ }
+
+ VERBOSE(BackendManager::loadBackend) << "loaded " << backend_plugin << " as a plugin of "
+ << backend << " backend\n";
+
+ {
+ // load object creator function
+ auto backend_create = (backend_create_t)dlsym(handle, "neurun_backend_create");
+ if (backend_create == nullptr)
+ {
+ fprintf(stderr, "BackendManager: unable to open function neurun_backend_create : %s\n",
+ dlerror());
+ abort();
+ }
+
+ // load object creator function
+ auto backend_destroy = (backend_destroy_t)dlsym(handle, "neurun_backend_destroy");
+ if (backend_destroy == nullptr)
+ {
+ fprintf(stderr, "BackendManager: unable to open function neurun_backend_destroy : %s\n",
+ dlerror());
+ abort();
+ }
+
+ auto backend_object =
+ std::unique_ptr<backend::Backend, backend_destroy_t>(backend_create(), backend_destroy);
+ auto backend_object_raw = backend_object.get();
+ bool initialized = backend_object->config()->initialize(); // Call initialize here?
+ if (!initialized)
+ {
+ VERBOSE(BackendManager::loadBackend)
+ << 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));
+ _available_backends.push_back(backend_object_raw);
+ }
+
+ // 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));
+}
+
+BackendManager::BackendManager()
+{
+ const auto backends = util::getConfigString(util::config::BACKENDS);
+ for (auto &backend_id : nnfw::misc::split(backends, ';'))
+ {
+ loadBackend(backend_id);
+ }
+
+ // No loaded backend
+ if (_available_backends.empty())
+ {
+ VERBOSE(BackendManager::loadBackend) << "There is no loaded backend\n";
+ abort();
+ }
+}
+
+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 *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 *BackendManager::getDefault() const { return get("cpu"); }
+
+} // namespace backend
+} // namespace neurun
diff --git a/runtime/neurun/core/src/backend/BackendManager.h b/runtime/neurun/core/src/backend/BackendManager.h
new file mode 100644
index 000000000..9c6483f9d
--- /dev/null
+++ b/runtime/neurun/core/src/backend/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 __NEURUN_BACKEND_BACKEND_MANAGER_H__
+#define __NEURUN_BACKEND_BACKEND_MANAGER_H__
+
+#include <memory>
+#include <map>
+
+#include "ir/Operands.h"
+#include "backend/Backend.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+class BackendManager
+{
+public:
+ using backend_create_t = Backend *(*)();
+ using backend_destroy_t = void (*)(Backend *);
+ using dlhandle_destroy_t = void (*)(void *);
+
+ static BackendManager &get();
+
+public:
+ Backend *get(const std::string &key);
+ const Backend *get(const std::string &key) const;
+ const Backend *getDefault() const;
+ const std::vector<const Backend *> &getAll() const { return _available_backends; };
+
+private:
+ BackendManager();
+
+private:
+ std::vector<const Backend *> _available_backends;
+ std::map<std::string, std::unique_ptr<void, dlhandle_destroy_t>> _handle_map;
+ std::map<std::string, std::unique_ptr<Backend, backend_destroy_t>> _gen_map;
+ /**
+ * @brief Allocate an object of a class of a plugin by loading a plugin function, that does
+ * allocation, and calling it
+ *
+ * @param object_of_plugin_class target object
+ * @param obj_creator_func_name name of the plugin function, that allocates an object
+ * @param handle handle of the plugin
+ * @param args arguments to pass to constructor of the plugin class
+ *
+ * @return
+ */
+ template <typename T, class... Types>
+ void loadObjectFromPlugin(std::shared_ptr<T> &object_of_plugin_class,
+ const std::string obj_creator_func_name, void *handle,
+ Types &&... args);
+
+ /**
+ * @brief load backend plugin
+ *
+ * @param backend backend to be loaded
+ *
+ * @return
+ */
+ void loadBackend(const std::string &backend);
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_BACKEND_MANAGER_H__
diff --git a/runtime/neurun/core/src/backend/ExecTime.cc b/runtime/neurun/core/src/backend/ExecTime.cc
new file mode 100644
index 000000000..d5aa679d7
--- /dev/null
+++ b/runtime/neurun/core/src/backend/ExecTime.cc
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/ExecTime.h"
+
+#include <fstream>
+#include <cassert>
+#include <limits>
+#include <algorithm>
+
+namespace neurun
+{
+namespace backend
+{
+
+int64_t ExecTime::getOperationExecTime(const 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, 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 *from_backend, const 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 *from_backend, const Backend *to_backend, bool quant,
+ uint32_t op_size) const
+{
+ return getOperationExecTime(from_backend, to_backend->config()->id(), quant, op_size);
+}
+
+} // namespace backend
+} // namespace neurun
diff --git a/runtime/neurun/core/src/backend/JSONExecTime.cc b/runtime/neurun/core/src/backend/JSONExecTime.cc
new file mode 100644
index 000000000..e2404b2c8
--- /dev/null
+++ b/runtime/neurun/core/src/backend/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 "backend/JSONExecTime.h"
+#include "backend/IConfig.h"
+#include <fstream>
+
+namespace neurun
+{
+namespace backend
+{
+/**
+ * @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 backend
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/BackendResolver.cc b/runtime/neurun/core/src/compiler/BackendResolver.cc
new file mode 100644
index 000000000..0c544190c
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/BackendResolver.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BackendResolver.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+BackendResolver::BackendResolver(const BackendResolver &obj)
+ : _context_manager{}, _gen_map{obj._gen_map}
+{
+ for (const auto &e : obj._context_manager)
+ {
+ _context_manager.emplace(e.first, nnfw::cpp14::make_unique<backend::BackendContext>(*e.second));
+ }
+}
+
+BackendResolver &BackendResolver::operator=(const BackendResolver &obj)
+{
+ _gen_map = obj._gen_map;
+
+ _context_manager.clear();
+ for (const auto &e : obj._context_manager)
+ {
+ _context_manager.emplace(e.first, nnfw::cpp14::make_unique<backend::BackendContext>(*e.second));
+ }
+
+ return *this;
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/BackendResolver.h b/runtime/neurun/core/src/compiler/BackendResolver.h
new file mode 100644
index 000000000..ddcae793a
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/BackendResolver.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 __NEURUN_COMPILER_BACKEND_RESOLVER_H__
+#define __NEURUN_COMPILER_BACKEND_RESOLVER_H__
+
+#include <unordered_map>
+#include <typeindex>
+
+#include "util/logging.h"
+#include "backend/Backend.h"
+#include "backend/BackendManager.h"
+#include "backend/ITensorBuilder.h"
+#include "ir/OperationIndexMap.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+class BackendResolver
+{
+public:
+ BackendResolver(const ir::Operands &operands,
+ const std::vector<const backend::Backend *> &backends,
+ const std::shared_ptr<backend::custom::IKernelBuilder> &kb)
+ {
+ for (const auto backend : backends)
+ {
+ _context_manager.emplace(backend, backend->newContext(operands, kb));
+ }
+ }
+
+ ~BackendResolver() = default;
+ BackendResolver(const BackendResolver &obj);
+ BackendResolver(BackendResolver &&obj) = default;
+ BackendResolver &operator=(const BackendResolver &obj);
+ BackendResolver &operator=(BackendResolver &&obj) = default;
+
+public:
+ const backend::BackendContext *getBackendContext(const ir::OperationIndex &index) const
+ {
+ return _context_manager.at(_gen_map.at(index)).get();
+ }
+
+ const backend::BackendContext *getBackendContext(const backend::Backend *backend) const
+ {
+ return _context_manager.at(backend).get();
+ }
+
+ backend::TensorBuilderSet tensor_builders() const
+ {
+ backend::TensorBuilderSet ret;
+ for (const auto &e : _context_manager)
+ {
+ ret.insert(e.second->tensor_builder);
+ }
+ return ret;
+ }
+
+ const backend::Backend *getBackend(const ir::OperationIndex &index) const
+ {
+ return getBackendContext(index)->backend;
+ }
+
+ 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::BackendContext &)> &fn) const
+ {
+ for (const auto &e : _gen_map)
+ {
+ fn(e.first, *_context_manager.at(e.second));
+ }
+ }
+
+private:
+ std::unordered_map<const backend::Backend *, std::unique_ptr<backend::BackendContext>>
+ _context_manager;
+ ir::OperationIndexMap<const backend::Backend *> _gen_map;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_BACKEND_RESOLVER_H__
diff --git a/runtime/neurun/core/src/compiler/CodeWithInfo.h b/runtime/neurun/core/src/compiler/CodeWithInfo.h
new file mode 100644
index 000000000..73dd1055b
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/CodeWithInfo.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 __NEURUN_COMPILER_CODE_WITH_INFO_H__
+#define __NEURUN_COMPILER_CODE_WITH_INFO_H__
+
+#include <memory>
+
+#include "compiler/Linear.h"
+#include "exec/IFunction.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+struct CodeWithInfo
+{
+ Linear::Element elem;
+ std::unique_ptr<exec::IFunction> fn;
+
+ CodeWithInfo(const Linear::Element &elem, std::unique_ptr<exec::IFunction> &&fn)
+ : elem{elem}, fn{std::move(fn)}
+ {
+ }
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_CODE_WITH_INFO_H__
diff --git a/runtime/neurun/core/src/compiler/Compiler.cc b/runtime/neurun/core/src/compiler/Compiler.cc
new file mode 100644
index 000000000..d5ee39d85
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/Compiler.cc
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/Compiler.h"
+
+#include "BackendResolver.h"
+#include "ParamChecker.h"
+#include "ExecutorFactory.h"
+#include "OperationValidator.h"
+
+#include "compiler/IScheduler.h"
+#include "compiler/ManualScheduler.h"
+#include "compiler/HEScheduler.h"
+#include "backend/ExecTime.h"
+#include "ir/operation/LowerInfo.h"
+#include "dumper/dot/DotDumper.h"
+#include "compiler/Linear.h"
+#include "exec/interp/ExecManager.h"
+#include "backend/ExecTime.h"
+#include "util/ConfigSource.h"
+
+namespace neurun
+{
+
+namespace compiler
+{
+
+static void checkProfilerConditions()
+{
+ if (!util::getConfigBool(util::config::USE_SCHEDULER))
+ throw std::runtime_error("Heterogeneous scheduler must be enabled during profiling.");
+
+ if (util::getConfigString(util::config::EXECUTOR) != "Dataflow")
+ throw std::runtime_error("Profiling mode works only with 'Dataflow' executor");
+}
+
+void Compiler::compile(void)
+{
+ _state = State::STARTED;
+
+ /***************************************************
+ * Prepare compilation phase
+ ***************************************************/
+
+ // Operation validation check
+ OperationValidator{*_graph}();
+
+ // Compilable check
+ if (!checkCompilable())
+ {
+ _executor = std::make_shared<exec::interp::ExecManager>(*_graph);
+ return;
+ }
+
+ // Mode check
+ if (util::getConfigBool(util::config::PROFILING_MODE))
+ checkProfilerConditions();
+
+ /***************************************************
+ * Backend independent analysis & optimization phase
+ ***************************************************/
+ // Schedule
+ std::unique_ptr<BackendResolver> br;
+ std::shared_ptr<ir::OperationIndexMap<int64_t>> indexed_ranks;
+ if (util::getConfigBool(util::config::USE_SCHEDULER))
+ {
+ auto scheduler = compiler::HEScheduler(
+ _graph->operands(), backend::BackendManager::get().getAll(), _graph->getKernelBuilder());
+ br = scheduler.schedule(*_graph);
+ indexed_ranks = scheduler.getIndexedRanks();
+ }
+ else
+ {
+ auto scheduler = compiler::ManualScheduler();
+ br = scheduler.schedule(*_graph);
+ }
+ _graph->setBackendResolver(std::move(br));
+ /*************************************************************
+ * Backend independent analysis & optimization phase finished
+ *************************************************************/
+
+ // dump graph to .dot
+ auto dump_level =
+ static_cast<dumper::dot::DotDumper::Level>(util::getConfigInt(util::config::GRAPH_DOT_DUMP));
+ neurun::dumper::dot::DotDumper dot_dumper(*_graph, dump_level);
+ dot_dumper.dump("before_lower");
+
+ // Lower: decide backend
+ _graph->lower();
+ _state = State::LOWERED;
+
+ dot_dumper.dump("after_lower");
+
+ const std::string executor_str = util::getConfigString(util::config::EXECUTOR);
+
+ _executor =
+ std::shared_ptr<exec::IExecutor>{ExecutorFactory::get().create(executor_str, *_graph)};
+ _executor->setIndexedRanks(indexed_ranks);
+ /********************************
+ * Code generation phase finished
+ ********************************/
+ _state = State::COMPILED;
+}
+
+bool Compiler::checkCompilable()
+{
+ // Disable compile phase
+ // When ready to use interpreter backend, remove this config and use backend setting
+ const auto env_disable_compile = util::getConfigBool(util::config::DISABLE_COMPILE);
+ if (env_disable_compile)
+ {
+ return false;
+ }
+
+ // TODO check unspecified operand shape
+
+ // Check compilable parameter
+ ParamChecker paramChecker{_graph};
+ paramChecker();
+ if (paramChecker.haveNoneConstParam())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace compiler
+
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/ExecutorFactory.cc b/runtime/neurun/core/src/compiler/ExecutorFactory.cc
new file mode 100644
index 000000000..59de6c4a4
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/ExecutorFactory.cc
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/BackendResolver.h"
+#include "backend/ExecTime.h"
+#include "compiler/Linear.h"
+#include "ir/dumper/Dumper.h"
+#include "SubTensorAnalyzer.h"
+#include "backend/IConstantInitializer.h"
+#include "backend/IKernelGenerator.h"
+#include "backend/IShapeFixer.h"
+#include "backend/ITensorRegister.h"
+#include "cpp14/memory.h"
+#include "CodeWithInfo.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+ExecutorFactory &ExecutorFactory::get()
+{
+ static ExecutorFactory singleton;
+ return singleton;
+}
+
+ExecutorFactory::ExecutorFactory()
+{
+ _map["Linear"] = createLinearExecutor;
+ _map["Dataflow"] = std::bind(createDataflowExecutor, std::placeholders::_1, false);
+ _map["Parallel"] = std::bind(createDataflowExecutor, std::placeholders::_1, true);
+}
+
+exec::IExecutor *ExecutorFactory::create(const std::string &id, ir::Graph &graph)
+{
+ return _map.at(id)(graph);
+}
+
+exec::IExecutor *ExecutorFactory::createLinearExecutor(ir::Graph &graph)
+{
+ auto operand_context = std::make_shared<OperandContext>();
+
+ // linearize
+ assert(!graph.isBuildingPhase());
+ auto linear = nnfw::cpp14::make_unique<Linear>(graph);
+
+ // Dump ops
+ linear->accept(ir::dumper::Dumper{});
+
+ /*************************************************
+ * Backend dependent analysis & optimization phase
+ *************************************************/
+
+ // SubTensorInfo should be generated after lower, before shape correction and finalize
+ // because SubTensorAnalyzer assume that insert permutation is already finished
+ // lower: decide backend and insert permutation
+ // fix shapes: prepare codegen to optimization
+ // generate tensor objects: generate tensor using subtensor info
+ // generate kernels
+ // allocate tesor memory
+ // constant intialization: fill the constants with values
+ // Generated SubTensorInfo is in operand(Object)
+ // for easy pass SubTensorInfo to plan builder and tensor builder
+ linear->accept(SubTensorAnalyzer{graph});
+
+ /**********************************************************
+ * Backend dependent analysis & optimization phase finished
+ **********************************************************/
+
+ /***********************
+ * Code generation phase
+ ***********************/
+
+ // Fix shapes
+ linear->iterate([&](const compiler::Linear::Element &element) {
+ auto backend = element.lower_info->backend();
+ auto shape_fixer = graph.backend_resolver()->getBackendContext(backend)->shape_fixer;
+ shape_fixer->fix(*element.op_seq);
+ });
+
+ linear->planTensors();
+
+ auto tensor_builders = graph.backend_resolver()->tensor_builders();
+
+ // Prepare tensors
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->prepare();
+ }
+
+ // Generate initializers
+ linear->generateConstantInitializers();
+
+ class ExecutionBuilder final : public IExecutionBuilder
+ {
+ public:
+ void append(std::unique_ptr<exec::IFunction> &&f) override
+ {
+ _code.emplace_back(_next_elem, std::move(f));
+ }
+
+ void setNextElem(const compiler::Linear::Element &next_elem) { _next_elem = next_elem; }
+ std::vector<CodeWithInfo> releaseCode() { return std::move(_code); }
+
+ private:
+ compiler::Linear::Element _next_elem;
+ std::vector<CodeWithInfo> _code;
+ };
+
+ ExecutionBuilder builder;
+
+ // Generate kernels
+ linear->iterate([&](const compiler::Linear::Element &element) {
+ auto backend = element.lower_info->backend();
+ builder.setNextElem(element);
+ auto kernel_gen = graph.backend_resolver()->getBackendContext(backend)->kernel_gen;
+ kernel_gen->generate(*element.op_seq, &builder);
+ });
+
+ auto code = builder.releaseCode();
+
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->allocateConsts();
+ }
+
+ // TODO Add optimization passes
+
+ // Initialize constant tensors
+ for (const auto backend : backend::BackendManager::get().getAll())
+ {
+ graph.backend_resolver()->getBackendContext(backend)->constant_initializer->run();
+ }
+
+ for (auto &&e : code)
+ {
+ e.fn->prepare();
+ auto backend = e.elem.lower_info->backend();
+ auto tensor_builder = graph.backend_resolver()->getBackendContext(backend)->tensor_builder;
+ tensor_builder->postFunctionPrepare();
+ }
+
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->allocateNonconsts();
+ }
+
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->finalize();
+ }
+
+ // Wrap tensors as Object and store them to plan
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->iterate([&](const ir::OperandIndex &index) {
+ auto object = tensor_builder->tensorAt(index);
+ operand_context->set(index, object);
+ });
+ }
+
+ // Prepare each TensorManager on each backend
+ auto tensor_mgrs = nnfw::cpp14::make_unique<backend::TensorManagerSet>();
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_mgrs->insert(tensor_builder->releaseTensorManager());
+ }
+
+ auto exec =
+ new exec::LinearExecutor{graph, operand_context, std::move(tensor_mgrs), std::move(code)};
+
+ const std::string trace_filepath = util::getConfigString(util::config::TRACE_FILEPATH);
+ if (!trace_filepath.empty())
+ {
+ std::unique_ptr<exec::IExecutionObserver> ctp =
+ nnfw::cpp14::make_unique<exec::ChromeTracingObserver>(trace_filepath);
+ exec->addObserver(std::move(ctp));
+ }
+
+ return exec;
+}
+
+exec::IExecutor *ExecutorFactory::createDataflowExecutor(ir::Graph &graph, bool parallel)
+{
+ auto operand_context = std::make_shared<OperandContext>();
+
+ graph.subgraphs().iterate([&](const ir::SubgraphIndex &, const ir::OpSequence &subg) {
+ auto subtensor_analyzer = SubTensorAnalyzer{graph};
+ subg.accept(subtensor_analyzer);
+ });
+
+ // Fix shapes and register tensors
+ graph.subgraphs().iterate([&](const ir::SubgraphIndex &subg_index, const ir::OpSequence &subg) {
+ auto backend = graph.getLowerInfo(subg_index)->backend();
+ auto shape_fixer = graph.backend_resolver()->getBackendContext(backend)->shape_fixer;
+ shape_fixer->fix(subg);
+ const auto tensor_register =
+ graph.backend_resolver()->getBackendContext(backend)->tensor_register;
+ tensor_register->registerTensors(subg, graph.getLowerInfo());
+ });
+
+ graph.operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) {
+ const auto lower_info = graph.getLowerInfo(ind);
+ for (auto factor : lower_info->def_factors())
+ {
+ auto backend = factor.backend();
+ auto tensor_builder = graph.backend_resolver()->getBackendContext(backend)->tensor_builder;
+
+ if (!tensor_builder->isRegistered(ind))
+ {
+ // These tensors do not exist in any op_seq (No use and def)
+ // These tensors cannot be a SubTensor
+ assert(obj.parent_info() == nullptr);
+
+ const auto info = obj.info();
+ const auto backend_layout = lower_info->def_factors().getOnlyElement().layout();
+ // TODO Change tensor info to have permuted shape
+ tensor_builder->registerTensorInfo(ind, info, backend_layout, obj.isConstant());
+ }
+
+ // Is not SubTensor?
+ if (!backend->config()->SupportSubTensorAlloc() || obj.parent_info() == nullptr)
+ {
+ // To make this never be deallocated, this is a workaround to use static memory planner
+ tensor_builder->notifyFirstUse(ind);
+ }
+ }
+ });
+
+ auto tensor_builders = graph.backend_resolver()->tensor_builders();
+
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->prepare();
+ }
+
+ class ExecutionBuilder : public IExecutionBuilder
+ {
+ public:
+ void append(std::unique_ptr<exec::IFunction> &&fn) override
+ {
+ auto itr = _code_map.find(_next_index);
+ if (itr == _code_map.end())
+ {
+ _code_map[_next_index] = nnfw::cpp14::make_unique<exec::FunctionSequence>();
+ }
+ _code_map[_next_index]->append(std::move(fn));
+ };
+
+ // TODO Remove this method and make `append` to get index value as an argument
+ void setNextIndex(const ir::SubgraphIndex next_index) { _next_index = next_index; }
+
+ exec::DataflowExecutor::CodeMap &&releaseCodeMap() { return std::move(_code_map); }
+
+ private:
+ ir::SubgraphIndex _next_index;
+ exec::DataflowExecutor::CodeMap _code_map;
+ };
+
+ auto execution_builder = nnfw::cpp14::make_unique<ExecutionBuilder>();
+
+ // Generate kernels
+ graph.subgraphs().iterate([&](const ir::SubgraphIndex &subg_index, const ir::OpSequence &subg) {
+ auto backend = graph.getLowerInfo(subg_index)->backend();
+ auto constant_initializer =
+ graph.backend_resolver()->getBackendContext(backend)->constant_initializer;
+ constant_initializer->generate(subg, graph.operands());
+ // TODO This approach is temporal. See declaration of `setNextIndex`.
+ execution_builder->setNextIndex(subg_index);
+ auto kernel_gen = graph.backend_resolver()->getBackendContext(backend)->kernel_gen;
+ kernel_gen->generate(subg, execution_builder.get());
+ });
+
+ for (const auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->allocateConsts();
+ }
+
+ // Initialize constant tensors
+ for (const auto backend : backend::BackendManager::get().getAll())
+ {
+ graph.backend_resolver()->getBackendContext(backend)->constant_initializer->run();
+ }
+
+ exec::DataflowExecutor::CodeMap code_map = execution_builder->releaseCodeMap();
+
+ for (auto &it : code_map)
+ {
+ auto subg_index = it.first;
+ auto &function_sequence = *(it.second);
+
+ function_sequence.iterate([&](exec::IFunction &ifunc) {
+ // NOTE. It may need avoiding prepare() for some operations
+ // Ref: https://github.sec.samsung.net/STAR/nnfw/issues/7326
+ ifunc.prepare();
+ auto backend = graph.getLowerInfo(subg_index)->backend();
+ auto tensor_builder = graph.backend_resolver()->getBackendContext(backend)->tensor_builder;
+ tensor_builder->postFunctionPrepare();
+ });
+ }
+
+ for (const auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->allocateNonconsts();
+ }
+
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->finalize();
+ }
+
+ // Wrap tensors as Object and store them to plan
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_builder->iterate([&](const ir::OperandIndex &index) {
+ auto object = tensor_builder->tensorAt(index);
+ operand_context->set(index, object);
+ });
+ }
+
+ // Prepare each TensorManager on each backend
+ auto tensor_mgrs = nnfw::cpp14::make_unique<backend::TensorManagerSet>();
+ for (auto &tensor_builder : tensor_builders)
+ {
+ tensor_mgrs->insert(tensor_builder->releaseTensorManager());
+ }
+
+ exec::ExecutorBase *exec = nullptr;
+ if (parallel)
+ {
+ exec = new exec::ParallelExecutor{graph, operand_context, std::move(tensor_mgrs),
+ std::move(code_map)};
+ }
+ else
+ {
+ exec = new exec::DataflowExecutor{graph, operand_context, std::move(tensor_mgrs),
+ std::move(code_map)};
+ if (util::getConfigBool(util::config::PROFILING_MODE))
+ {
+ auto et = std::make_shared<backend::ExecTime>(backend::BackendManager::get().getAll());
+ std::unique_ptr<exec::IExecutionObserver> obs =
+ nnfw::cpp14::make_unique<exec::ProfileObserver>(et);
+ exec->addObserver(std::move(obs));
+ }
+ }
+
+ const std::string trace_filepath = util::getConfigString(util::config::TRACE_FILEPATH);
+ if (!trace_filepath.empty())
+ {
+ std::unique_ptr<exec::IExecutionObserver> ctp =
+ nnfw::cpp14::make_unique<exec::ChromeTracingObserver>(trace_filepath);
+ exec->addObserver(std::move(ctp));
+ }
+
+ return exec;
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/ExecutorFactory.h b/runtime/neurun/core/src/compiler/ExecutorFactory.h
new file mode 100644
index 000000000..6da4ffc5e
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/ExecutorFactory.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 __NEURUN_COMPILER_EXECUTOR_FACTORY_H__
+#define __NEURUN_COMPILER_EXECUTOR_FACTORY_H__
+
+#include <unordered_map>
+
+#include "exec/IExecutor.h"
+#include "ir/Graph.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+class ExecutorFactory
+{
+public:
+ static ExecutorFactory &get();
+
+public:
+ exec::IExecutor *create(const std::string &id, ir::Graph &graph);
+
+private:
+ ExecutorFactory();
+
+private:
+ static exec::IExecutor *createLinearExecutor(ir::Graph &graph);
+ static exec::IExecutor *createDataflowExecutor(ir::Graph &graph, bool parallel);
+
+private:
+ std::unordered_map<std::string, std::function<exec::IExecutor *(ir::Graph &)>> _map;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_EXECUTOR_FACTORY_H__
diff --git a/runtime/neurun/core/src/compiler/HEScheduler.cc b/runtime/neurun/core/src/compiler/HEScheduler.cc
new file mode 100644
index 000000000..aec68d655
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/HEScheduler.cc
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/IExecutionBuilder.h"
+#include "compiler/BackendResolver.h"
+#include "backend/IShapeFixer.h"
+#include "util/logging.h"
+#include "util/Utils.h"
+#include "exec/FunctionSequence.h"
+#include <cassert>
+#include <cmath>
+#include <chrono>
+
+namespace neurun
+{
+
+namespace compiler
+{
+static uint32_t getOperationsFlattenedIOSize(const ir::Graph &graph, const ir::Operation &node)
+{
+ uint32_t size = 0;
+ for (const auto &input : node.getInputs())
+ {
+ size += graph.operands().at(input).info().total_size();
+ }
+ for (const auto &output : node.getOutputs())
+ {
+ size += graph.operands().at(output).info().total_size();
+ }
+ return size;
+}
+
+static bool isQuant(const ir::Graph &graph, const ir::Operation &node)
+{
+ for (const auto &input : node.getInputs())
+ {
+ const auto &obj = graph.operands().at(input);
+ if (obj.typeInfo().type() == ir::DataType::QUANT8_ASYMM)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool isWorkaroundSkip(const ir::Graph &graph, const backend::Backend *backend,
+ const ir::Operation &node, bool quant)
+{
+ /* TODO: this is workaround, come up with better solution if have.
+ Adding exception in stage doesn't help. Because if there is a record for add without
+ broadcast, scheduling will select it since it doesn't distinguish broadcast and
+ non-broadcast like it does for quant non-quantized*/
+ if (backend->config()->id() == "cpu" &&
+ (node.opcode() == ir::OpCode::Add || node.opcode() == ir::OpCode::Sub ||
+ node.opcode() == ir::OpCode::Mul))
+ {
+ const auto lhs_index{node.getInputs().at(ir::operation::Add::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::Add::Input::RHS)};
+ /*Broadcasting isn't supported on CPU: no way to differ the existing exec_time record with and
+ * without broadcasting*/
+ if (!(graph.operands().at(lhs_index).shape() == graph.operands().at(rhs_index).shape()))
+ {
+ return true;
+ }
+ }
+ /* TODO: this is workaround, come up with better solution if have.
+ Adding exception in stage doesn't help. Because if there is a record for Mul without
+ broadcast, scheduling will select it since it doesn't distinguish broadcast and
+ non-broadcast like it does for quant non-quantized*/
+ else if (backend->config()->id() == "acl_neon" && node.opcode() == ir::OpCode::Mul)
+ {
+ const auto lhs_index{node.getInputs().at(ir::operation::Mul::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::Mul::Input::RHS)};
+
+ // Nontrivial broadcasting isn't supported yet
+ if (quant ||
+ !(graph.operands().at(lhs_index).shape() == graph.operands().at(rhs_index).shape()))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+// if a node can be merged into op_seq
+static bool isMergeable(const ir::Graph &graph, const ir::Operation &node)
+{
+ size_t prev_op_cnt = 0;
+ for (const auto &input : node.getInputs())
+ {
+ // 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().list().size() > 0)
+ ++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().list().size() > 1)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+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());
+ loc_index = only_out_operand.getUses().list().front();
+ /* 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}});
+ }
+
+ const bool is_profiling = util::getConfigBool(util::config::PROFILING_MODE);
+ if (is_profiling)
+ {
+ // 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)
+{
+ const auto time = _exec_time->getPermuteTime(src_backend, dst_backend, quant, size);
+ if (time != _exec_time->NOT_FOUND)
+ return time;
+
+ // Makes the scheduler prefer keeping computations on one backend
+ return size / 200;
+}
+
+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 (!util::getConfigBool(util::config::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
+ {
+ node.accept(*_backend_resolver->getBackendContext(backend)->shape_fixer);
+
+ _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())
+ {
+ const auto &operand = _graph->operands().at(output);
+ const bool quant = operand.typeInfo().type() == ir::DataType::QUANT8_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;
+ }
+ auto transfer_cost =
+ _exec_time->getPermuteTime(backend, other_backend, quant, operand.info().total_size());
+ if (transfer_cost == _exec_time->NOT_FOUND)
+ {
+ // Makes the scheduler prefer keeping computations on one backend
+ transfer_cost = operand.info().total_size() / 100;
+ }
+ avg_transfer_cost += transfer_cost;
+ }
+ }
+ avg_transfer_cost /= _all_backends.size();
+ for (const auto &use : operand.getUses().list())
+ {
+ 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)
+{
+ const bool is_linear_exec = "Linear" == util::getConfigString(util::config::EXECUTOR);
+ const bool is_parallel_exec = "Parallel" == util::getConfigString(util::config::EXECUTOR);
+ // 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 subgraphs
+ // 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())
+ {
+ const auto &input_operand = _graph->operands().at(input_operand_idx);
+ const bool quant = input_operand.typeInfo().type() == ir::DataType::QUANT8_ASYMM;
+
+ for (const auto &input_node_idx : input_operand.getDef().list())
+ {
+ // 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 neurun
diff --git a/runtime/neurun/core/src/compiler/HEScheduler.h b/runtime/neurun/core/src/compiler/HEScheduler.h
new file mode 100644
index 000000000..538427065
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/HEScheduler.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file HEScheduler.h
+ * @brief This file contains HEScheduler class to define and run task Heterogeneous Execution
+ * Scheduler
+ */
+
+#ifndef __NEURUN_COMPILER_H_E_SCHEDULER_H_
+#define __NEURUN_COMPILER_H_E_SCHEDULER_H_
+
+#include "compiler/IScheduler.h"
+#include "ir/Graph.h"
+#include "backend/ExecTime.h"
+#include "backend/Backend.h"
+#include "cpp14/memory.h"
+#include "ir/OperationIndexMap.h"
+#include <map>
+#include <memory>
+
+namespace neurun
+{
+
+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 ir::Operands &operands, std::vector<const backend::Backend *> backends,
+ const std::shared_ptr<backend::custom::IKernelBuilder> &kb)
+ : _is_supported{}, _backends_avail_time{}, _ops_eft{},
+ _op_to_rank{std::make_shared<ir::OperationIndexMap<int64_t>>()},
+ _all_backends(std::move(backends))
+ {
+ _backend_resolver =
+ nnfw::cpp14::make_unique<compiler::BackendResolver>(operands, _all_backends, kb);
+ _exec_time = nnfw::cpp14::make_unique<backend::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<backend::ExecTime> _exec_time;
+ const ir::Graph *_graph{nullptr};
+ const std::vector<const backend::Backend *> _all_backends;
+ const backend::Backend *_cpu_backend{nullptr};
+};
+
+} // namespace compiler
+
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_H_E_SCHEDULER_H_
diff --git a/runtime/neurun/core/src/compiler/IScheduler.h b/runtime/neurun/core/src/compiler/IScheduler.h
new file mode 100644
index 000000000..dc1373ff9
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_CORE_COMPILER_I_SCHEDULER_H__
+#define __NEURUN_CORE_COMPILER_I_SCHEDULER_H__
+
+#include "BackendResolver.h"
+#include "ir/Graph.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+struct IScheduler
+{
+ virtual ~IScheduler() = default;
+
+ virtual std::unique_ptr<BackendResolver> schedule(const ir::Graph &graph) = 0;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_CORE_COMPILER_I_SCHEDULER_H__
diff --git a/runtime/neurun/core/src/compiler/Linear.cc b/runtime/neurun/core/src/compiler/Linear.cc
new file mode 100644
index 000000000..b18dcea02
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/Linear.cc
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/IShapeFixer.h"
+#include "backend/IConfig.h"
+#include "backend/IConstantInitializer.h"
+#include "backend/ITensorRegister.h"
+#include "backend/Backend.h"
+#include "compiler/SubTensorInfo.h"
+
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+Linear::Linear(ir::Graph &graph) : _graph(graph)
+{
+ // Get SubgraphSequence by topological sorting
+ {
+ ir::Subgraphs &subgraphs = _graph.subgraphs();
+ ir::Operands &operands = _graph.operands();
+ // subgraphs can't access a op_seq by an operand so that input_to_subgs can offer it
+ std::unordered_map<ir::OperandIndex, std::list<ir::SubgraphIndex>> input_to_subgs;
+
+ // Get the relations between input/op_seq to be used for dfs-post-iter
+ //
+ // [0] # input -> _input_to_op_seqes[0] = {SUBG0}
+ // |
+ // [SUBG0]
+ // |
+ // [1]-----. # input -> _input_to_op_seqes[1] = {SUBG1, SUBG2}
+ // | |
+ // [SUBG1] [SUBG2]
+ // | |
+ // [2] [3] # input -> _input_to_op_seqes[2] = {SUBG3}
+ // \ / # input -> _input_to_op_seqes[3] = {SUBG3}
+ // [SUBG3]
+ // |
+ // [4]
+ subgraphs.iterate([&](const ir::SubgraphIndex &subg_idx, ir::OpSequence &subg) {
+ for (auto input : subg.getInputs())
+ {
+ // only valid_inputs
+ const auto &operand = operands.at(input);
+ if (operand.isConstant())
+ continue;
+
+ auto it = input_to_subgs.find(input);
+ if (it == input_to_subgs.end())
+ {
+ std::list<ir::SubgraphIndex> list{subg_idx};
+ input_to_subgs[input] = list;
+ }
+ else
+ {
+ it->second.push_back(subg_idx);
+ }
+ }
+ });
+
+ std::unordered_map<ir::SubgraphIndex, bool> visited;
+ subgraphs.iterate(
+ [&](const ir::SubgraphIndex &index, const ir::OpSequence &) { visited[index] = false; });
+
+ std::function<void(const ir::SubgraphIndex &, ir::OpSequence &)> dfs_recursive =
+ [&](const ir::SubgraphIndex &index, ir::OpSequence &subg) -> void {
+ if (visited[index])
+ return;
+ visited[index] = true;
+
+ // The outputs should be not constants
+ for (auto output : subg.getOutputs())
+ {
+ const auto it = input_to_subgs.find(output);
+ if (it != input_to_subgs.end())
+ {
+ const auto &subg_index_list = it->second;
+ for (const auto &index : subg_index_list)
+ {
+ auto &subg = subgraphs.at(index);
+ dfs_recursive(index, subg);
+ }
+ }
+ }
+
+ _elements.emplace_back(&subgraphs.at(index), _graph.getLowerInfo(index));
+ };
+
+ subgraphs.iterate(dfs_recursive);
+
+ // All of the nodes must have been visited.
+ assert(std::all_of(visited.begin(), visited.end(),
+ [](const std::pair<const ir::SubgraphIndex, bool> &v) { return v.second; }));
+
+ // NOTE. Now these op_seq are on the reverse order
+ std::reverse(_elements.begin(), _elements.end());
+ }
+
+ {
+ const auto &backendToString = [](const neurun::backend::Backend *backend) {
+ assert(backend);
+ std::string str;
+ str += backend->config()->id();
+ str += " ";
+ return "{ " + str + "}";
+ };
+
+ VERBOSE(Linear) << "Final SubgraphSequence" << std::endl;
+ for (const auto &element : _elements)
+ {
+ const auto subg = element.op_seq;
+ const auto lower_info = element.lower_info;
+ VERBOSE(Linear) << "* SUBG"
+ << " " << backendToString(lower_info->backend()) << " " << subg->getStr()
+ << std::endl;
+ }
+ }
+}
+
+void Linear::accept(ir::OperationVisitor &&visitor) const
+{
+ for (const auto &e : _elements)
+ {
+ e.op_seq->accept(visitor);
+ }
+}
+
+void Linear::planTensors()
+{
+ ir::OperandIndexMap<std::shared_ptr<backend::ITensorBuilder>> tensor_builder_map;
+
+ // NOTE
+ // While current ITensorBuilder exposes registerSubTensorInfo for subtensor,
+ // this stage uses registerSubTensorInfo() and notify{First|Last}Use()
+ // but handling subtensor should be processed on each backend. See #5726.
+ ir::OperandIndexMap<uint32_t> uses_map;
+ ir::OperandIndexMap<uint32_t> def_map;
+ ir::OperandIndexSequence constants;
+
+ iterate([&](const neurun::compiler::Linear::Element &element) {
+ const auto backend = element.lower_info->backend();
+ const auto tensor_register =
+ _graph.backend_resolver()->getBackendContext(backend)->tensor_register;
+ tensor_register->registerTensors(*element.op_seq, _graph.getLowerInfo());
+ });
+
+ // Prepare scanning
+ _graph.operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) {
+ const auto lower_info = _graph.getLowerInfo(ind);
+ // TODO Remove if neurun 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 be not used. no more process."
+ << std::endl;
+ return;
+ }
+
+ uses_map[ind] = obj.getUses().size();
+ def_map[ind] = obj.getDef().size(); // should be 1 or 0
+
+ bool is_const = obj.isConstant();
+ if (is_const)
+ {
+ constants.append(ind);
+ }
+
+ for (auto factor : lower_info->def_factors())
+ {
+ auto backend = factor.backend();
+ auto tensor_builder = _graph.backend_resolver()->getBackendContext(backend)->tensor_builder;
+
+ if (!tensor_builder->isRegistered(ind))
+ {
+ // These tensors do not exist in any op_seq (No use and def)
+ // These tensors cannot be a SubTensor
+ assert(obj.parent_info() == nullptr);
+
+ const auto info = obj.info();
+ const auto backend_layout = lower_info->def_factors().getOnlyElement().layout();
+ // TODO Change tensor info to have permuted shape
+ tensor_builder->registerTensorInfo(ind, info, backend_layout, is_const);
+ }
+
+ tensor_builder_map[ind] = tensor_builder;
+ }
+ });
+
+ // If a tensor is model output, increase the use of the tensor.
+ // This aim is same to above one.
+ for (const auto &ind : _graph.getOutputs())
+ {
+ 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())
+ {
+ 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 USE of inputs. Decrease the USE and deallocate if the USE is 0
+ VERBOSE(LINEAR) << "TENSORS" << std::endl;
+ for (const auto &e : _elements)
+ {
+ for (const auto &op : e.op_seq->operations())
+ {
+ for (const auto &ind : op.node->getOutputs())
+ {
+ assert(def_map.find(ind) != def_map.end());
+ if (def_map[ind])
+ {
+ def_map[ind] = 0;
+ tensor_builder_map[ind]->notifyFirstUse(ind);
+ }
+ }
+
+ for (const auto &ind : op.node->getInputs())
+ {
+ assert(uses_map.find(ind) != uses_map.end());
+ assert(uses_map[ind] > 0);
+ uses_map[ind]--;
+ if (uses_map[ind] == 0)
+ {
+ tensor_builder_map[ind]->notifyLastUse(ind);
+ }
+ }
+ }
+ }
+
+ // Dispose and validate
+ for (const auto &ind : _graph.getOutputs())
+ {
+ --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; }));
+}
+
+void Linear::iterate(const std::function<void(const Element &element)> &fn) const
+{
+ for (const auto &e : _elements)
+ {
+ fn(e);
+ }
+}
+
+void Linear::generateConstantInitializers(void) const
+{
+ iterate([&](const compiler::Linear::Element &element) {
+ auto backend = element.lower_info->backend();
+
+ auto constant_initializer =
+ _graph.backend_resolver()->getBackendContext(backend)->constant_initializer;
+ constant_initializer->generate(*element.op_seq, _graph.operands());
+ });
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/Linear.h b/runtime/neurun/core/src/compiler/Linear.h
new file mode 100644
index 000000000..e10d03695
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/Linear.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_COMPILER_LINEAR_H__
+#define __NEURUN_COMPILER_LINEAR_H__
+
+#include <vector>
+#include <memory>
+
+#include "ir/Subgraphs.h"
+#include "backend/ITensorBuilder.h"
+#include "ir/Graph.h"
+#include "compiler/BackendResolver.h"
+
+namespace neurun
+{
+namespace ir
+{
+struct OperationVisitor;
+} // namespace ir
+} // namespace neurun
+
+namespace neurun
+{
+namespace compiler
+{
+
+class Linear
+{
+public:
+ struct Element
+ {
+ const ir::OpSequence *op_seq;
+ const ir::operation::LowerInfo *lower_info;
+
+ Element() : op_seq{nullptr}, lower_info{nullptr} {}
+
+ Element(const ir::OpSequence *op_seq, const ir::operation::LowerInfo *lower_info)
+ : op_seq{op_seq}, lower_info{lower_info}
+ {
+ // DO NOTHING
+ }
+ };
+
+public:
+ Linear(ir::Graph &graph);
+
+public:
+ Linear(const Linear &linear) = delete;
+
+public:
+ void accept(ir::OperationVisitor &&visitor) const;
+
+ void planTensors();
+
+ void iterate(const std::function<void(const Element &element)> &fn) const;
+
+ void generateConstantInitializers(void) const;
+
+private:
+ ir::Graph &_graph;
+ std::vector<Element> _elements;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_LINEAR_H__
diff --git a/runtime/neurun/core/src/compiler/ManualScheduler.cc b/runtime/neurun/core/src/compiler/ManualScheduler.cc
new file mode 100644
index 000000000..1fb9d3759
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/ManualScheduler.cc
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/BackendManager.h"
+#include "backend/IConfig.h"
+#include "util/ConfigSource.h"
+#include "misc/string_helpers.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+std::unique_ptr<BackendResolver> ManualScheduler::schedule(const ir::Graph &graph)
+{
+ auto backend_resolver = nnfw::cpp14::make_unique<compiler::BackendResolver>(
+ graph.operands(), backend::BackendManager::get().getAll(), graph.getKernelBuilder());
+
+ // 1. Backend for All operations
+ auto backend_all_str = util::getConfigString(util::config::OP_BACKEND_ALLOPS);
+ backend::Backend *backend_all = nullptr;
+
+ if (backend_all_str.empty())
+ {
+ const auto backends_str = util::getConfigString(util::config::BACKENDS);
+ size_t prev_pos = 0;
+ auto pos = backends_str.find(";");
+ while (pos != std::string::npos)
+ {
+ backend_all_str = backends_str.substr(prev_pos, pos - prev_pos);
+ backend_all = backend::BackendManager::get().get(backend_all_str);
+ if (backend_all != nullptr)
+ break;
+
+ prev_pos = pos + 1;
+ pos = backends_str.find(";", prev_pos);
+ }
+ // if backends doesn't terminate with ";"
+ if (backend_all == nullptr && prev_pos < backends_str.size())
+ {
+ backend_all_str = backends_str.substr(prev_pos);
+ backend_all = backend::BackendManager::get().get(backend_all_str);
+ }
+ }
+ else
+ {
+ backend_all = backend::BackendManager::get().get(backend_all_str);
+ }
+
+ VERBOSE(ManualScheduler) << "Default backend for all ops: " << backend_all_str << 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;
+ // By default, Custom uses cpu backend
+ op_type_map[ir::OpCode::Custom] = backend::BackendManager::get().get("cpu");
+
+#define OP(InternalName) \
+ { \
+ const auto &backend_str = util::getConfigString(util::config::OP_BACKEND_##InternalName); \
+ if (!backend_str.empty()) \
+ { \
+ auto backend = backend::BackendManager::get().get(backend_str); \
+ VERBOSE(Lower) << "backend for " << #InternalName << ": " << backend_str << std::endl; \
+ op_type_map[ir::OpCode::InternalName] = backend; \
+ } \
+ }
+#include "ir/Operations.lst"
+#undef OP
+
+ 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
+ try
+ {
+ 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));
+
+ graph.operations().at(ir::OperationIndex{key}); // Check if exist, or this wil throw
+ backend_resolver->setBackend(ir::OperationIndex{key},
+ backend::BackendManager::get().get(val));
+ }
+ }
+ catch (...)
+ {
+ VERBOSE(ManualScheduler) << "Invalid value from " << util::config::OP_BACKEND_MAP
+ << ". Some of the given values are ignored" << std::endl;
+ }
+
+ // 4. Operations that are specially handled
+ // All configuration above will be ignored(overwritten)
+ op_type_map[ir::OpCode::Permute] = backend::BackendManager::get().get("cpu");
+
+ // Dump final assignment
+ backend_resolver->iterate(
+ [&](const ir::OperationIndex &index, const backend::BackendContext &backend_ctx) {
+ VERBOSE(ManualScheduler) << "backend for operation #" << index.value() << ": "
+ << backend_ctx.backend->config()->id() << std::endl;
+ });
+
+ return backend_resolver;
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/ManualScheduler.h b/runtime/neurun/core/src/compiler/ManualScheduler.h
new file mode 100644
index 000000000..a442cec08
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/ManualScheduler.h
@@ -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.
+ */
+
+#ifndef __NEURUN_CORE_COMPILER_MANUAL_SCHEDULER_H__
+#define __NEURUN_CORE_COMPILER_MANUAL_SCHEDULER_H__
+
+#include "IScheduler.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+class ManualScheduler : public IScheduler
+{
+public:
+ std::unique_ptr<BackendResolver> schedule(const ir::Graph &graph) override;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_CORE_COMPILER_MANUAL_SCHEDULER_H__
diff --git a/runtime/neurun/core/src/compiler/OperandContext.cc b/runtime/neurun/core/src/compiler/OperandContext.cc
new file mode 100644
index 000000000..c06f6157b
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/OperandContext.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OperandContext.h"
+
+#include <cassert>
+
+namespace neurun
+{
+namespace compiler
+{
+
+OperandContext &OperandContext::set(const ir::OperandIndex &id,
+ const std::shared_ptr<backend::operand::ITensor> &tensor)
+{
+ // Only one tensor for an id
+ assert(_tensors.find(id) == _tensors.end());
+ _tensors[id] = tensor;
+ return (*this);
+}
+
+void OperandContext::iterate(
+ const std::function<void(const ir::OperandIndex &, backend::operand::ITensor &)> &fn)
+{
+ for (auto &e : _tensors)
+ {
+ fn(e.first, *e.second);
+ }
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/OperandContext.h b/runtime/neurun/core/src/compiler/OperandContext.h
new file mode 100644
index 000000000..da1a51bb9
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/OperandContext.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 __NEURUN_COMPILER_OPERAND_CONTEXT_H__
+#define __NEURUN_COMPILER_OPERAND_CONTEXT_H__
+
+#include "backend/operand/ITensor.h"
+#include "ir/OperandIndexMap.h"
+#include <unordered_map>
+#include <memory>
+
+namespace neurun
+{
+namespace compiler
+{
+
+class OperandContext
+{
+public:
+ OperandContext &set(const ir::OperandIndex &ind,
+ const std::shared_ptr<backend::operand::ITensor> &tensor);
+
+public:
+ bool exist(const ir::OperandIndex &ind) const { return _tensors.find(ind) != _tensors.end(); }
+
+public:
+ std::shared_ptr<backend::operand::ITensor> at(const ir::OperandIndex &ind) const
+ {
+ return _tensors.at(ind);
+ }
+
+ std::shared_ptr<backend::operand::ITensor> &at(const ir::OperandIndex &ind)
+ {
+ return _tensors.at(ind);
+ }
+
+ void
+ iterate(const std::function<void(const ir::OperandIndex &, backend::operand::ITensor &)> &fn);
+
+private:
+ ir::OperandIndexMap<std::shared_ptr<backend::operand::ITensor>> _tensors;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_OPERAND_CONTEXT_H__
diff --git a/runtime/neurun/core/src/compiler/OperationValidator.cc b/runtime/neurun/core/src/compiler/OperationValidator.cc
new file mode 100644
index 000000000..74f76bdbe
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/OperationValidator.cc
@@ -0,0 +1,985 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <typeinfo>
+
+#include "ir/Graph.h"
+#include "ir/operation/LowerInfo.h"
+
+#include "util/logging.h"
+#include "util/Utils.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+OperationValidator::OperationValidator(const ir::Graph &graph)
+ : _graph{graph}, _ctx{graph.operands()}, _current_subg_layout{ir::Layout::UNKNOWN}
+{
+}
+
+void OperationValidator::operator()()
+{
+ // TODO Get frontend layout from graph
+ _current_subg_layout = ir::Layout::NHWC;
+
+ _graph.operations().iterate(
+ [&](const ir::OperationIndex &, const ir::Operation &node) { node.accept(*this); });
+}
+
+void OperationValidator::visit(const ir::operation::BatchToSpaceND &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)};
+ const auto block_size_index{
+ node.getInputs().at(ir::operation::BatchToSpaceND::Input::BLOCK_SIZE)};
+
+ const auto frontend_layout = _current_subg_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);
+
+ UNUSED_RELEASE(input_shape);
+ UNUSED_RELEASE(output_shape);
+
+ // All assertions as per NNAPI specification.
+ assert(_ctx.at(ifm_index).shape().rank() == 4);
+ assert(_ctx.at(ofm_index).shape().rank() == 4);
+ assert(_ctx.at(block_size_index).shape().rank() == 1);
+
+ assert(_ctx.at(block_size_index).shape().dim(0) == 2);
+
+ assert(_ctx.at(block_size_index).isConstant());
+
+ assert(input_shape.C == output_shape.C);
+}
+
+void OperationValidator::visit(const ir::operation::Cast &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(input_index);
+
+ assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape());
+}
+
+void OperationValidator::visit(const ir::operation::Comparison &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)};
+ const auto rhs_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(lhs_index);
+ UNUSED_RELEASE(rhs_index);
+
+ assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(rhs_index).typeInfo().type());
+ assert(_ctx.at(output_index).typeInfo().type() == ir::DataType::BOOL8);
+}
+
+void OperationValidator::visit(const ir::operation::Softmax &node)
+{
+ VERBOSE(Softmax) << "Configure SOFTMAX operation" << std::endl;
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(input_index);
+
+ assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
+}
+
+void OperationValidator::visit(const ir::operation::InstanceNorm &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::InstanceNorm::Input::INPUT)};
+ const auto gamma_index{node.getInputs().at(ir::operation::InstanceNorm::Input::GAMMA)};
+ const auto beta_index{node.getInputs().at(ir::operation::InstanceNorm::Input::BETA)};
+
+ UNUSED_RELEASE(ofm_index);
+ UNUSED_RELEASE(ifm_index);
+ UNUSED_RELEASE(gamma_index);
+ UNUSED_RELEASE(beta_index);
+
+ assert(_ctx.at(ifm_index).shape().rank() == 4);
+ assert(_ctx.at(ifm_index).shape() == _ctx.at(ofm_index).shape());
+ assert(_ctx.at(gamma_index).shape().rank() == 1);
+ assert(_ctx.at(beta_index).shape().rank() == 1);
+}
+
+void OperationValidator::visit(const ir::operation::Permute &node)
+{
+ VERBOSE(Permute) << "Configure Permute operation" << std::endl;
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(input_index);
+
+ assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
+}
+
+void OperationValidator::visit(const ir::operation::ReduceSum &node)
+{
+ VERBOSE(Permute) << "Configure ReduceSum operation" << std::endl;
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ReduceSum::Input::INPUT)};
+ const auto &axes = node.param().axes;
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(input_index);
+ UNUSED_RELEASE(axes);
+
+ const auto input_shape = _ctx.at(input_index).shape();
+ const auto output_shape = _ctx.at(output_index).shape();
+
+ UNUSED_RELEASE(output_shape);
+ UNUSED_RELEASE(input_shape);
+
+ assert(input_shape.rank() <= 4);
+ assert(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
+ assert(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)
+ assert((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 OperationValidator::visit(const ir::operation::Transpose &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Transpose::Input::INPUT)};
+ const auto &perm{node.param().perm};
+
+ const auto &output_shape = _ctx.at(output_index).shape();
+ const auto &input_shape = _ctx.at(input_index).shape();
+
+ UNUSED_RELEASE(output_shape);
+ UNUSED_RELEASE(input_shape);
+ UNUSED_RELEASE(perm);
+
+ assert(input_shape.rank() == static_cast<int>(perm.size()));
+ assert(input_shape.rank() == output_shape.rank());
+}
+
+void OperationValidator::visit(const ir::operation::ReduceMax &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::ReduceMax::Input::INPUT)};
+ const auto &axes = node.param().axes;
+
+ auto output_shape = _ctx.at(output_index).shape();
+ auto input_shape = _ctx.at(input_index).shape();
+
+ UNUSED_RELEASE(output_shape);
+ UNUSED_RELEASE(input_shape);
+ UNUSED_RELEASE(axes);
+
+ assert(input_shape.rank() <= 4);
+ assert(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
+ assert(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(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1)
+ assert((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 OperationValidator::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)};
+ 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);
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(hidden_state_out_index);
+ UNUSED_RELEASE(input_index);
+ UNUSED_RELEASE(weights_index);
+ UNUSED_RELEASE(recurrent_weights_index);
+ UNUSED_RELEASE(bias_index);
+ UNUSED_RELEASE(hidden_state_in_index);
+ UNUSED_RELEASE(batch_size);
+ UNUSED_RELEASE(num_units);
+
+ assert(_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);
+ assert(_ctx.at(bias_index).shape().rank() == 1);
+
+ assert(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));
+ assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(weights_index).shape().dim(1));
+
+ assert(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));
+ assert(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 OperationValidator::visit(const ir::operation::SpaceToBatchND &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)};
+ const auto block_size_index{
+ node.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)};
+ const auto paddings_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)};
+
+ const auto frontend_layout = _current_subg_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);
+
+ UNUSED_RELEASE(input_shape);
+ UNUSED_RELEASE(output_shape);
+
+ // All assertions as per NNAPI specification.
+ assert(_ctx.at(ifm_index).shape().rank() == 4);
+ assert(_ctx.at(ofm_index).shape().rank() == 4);
+ assert(_ctx.at(block_size_index).shape().rank() == 1);
+ assert(_ctx.at(paddings_index).shape().rank() == 2);
+
+ assert(_ctx.at(block_size_index).shape().dim(0) == 2);
+ assert(_ctx.at(paddings_index).shape().dim(0) == 2);
+ assert(_ctx.at(paddings_index).shape().dim(1) == 2);
+
+ assert(_ctx.at(block_size_index).isConstant());
+ assert(_ctx.at(paddings_index).isConstant());
+
+ assert(input_shape.C == output_shape.C);
+}
+
+void OperationValidator::visit(const ir::operation::SpaceToDepth &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)};
+
+ const auto frontend_layout = _current_subg_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;
+
+ UNUSED_RELEASE(input_shape);
+ UNUSED_RELEASE(output_shape);
+ UNUSED_RELEASE(block_size);
+
+ // All assertions as per NNAPI specification.
+ assert(_ctx.at(ifm_index).shape().rank() == 4);
+ assert(_ctx.at(ofm_index).shape().rank() == 4);
+ assert((block_size >= 1) && (input_shape.H % block_size == 0) &&
+ (input_shape.W % block_size == 0));
+ assert(input_shape.N == output_shape.N);
+ assert(input_shape.C * block_size * block_size == output_shape.C);
+}
+
+void OperationValidator::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);
+
+ UNUSED_RELEASE(output_obj);
+ UNUSED_RELEASE(lookups_obj);
+ UNUSED_RELEASE(values_obj);
+
+ // Verify operand here, not at SimpleEmbeddingLookup::configure() to avoid acl's modifying
+ // TensorShape sometimes(Issue: https://github.sec.samsung.net/STAR/nnfw/issues/729)
+ {
+ assert(lookups_obj.typeInfo().type() == ir::DataType::INT32);
+
+ const auto &output_shape = output_obj.shape();
+ const auto &lookups_shape = lookups_obj.shape();
+ const auto &values_shape = values_obj.shape();
+
+ UNUSED_RELEASE(output_shape);
+ UNUSED_RELEASE(lookups_shape);
+ UNUSED_RELEASE(values_shape);
+
+ assert(lookups_shape.rank() == 1);
+ assert(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.
+ assert(output_shape.rank() == values_shape.rank());
+ assert(output_shape.dim(0) == lookups_shape.dim(0));
+ for (int n = 1; n < output_shape.rank(); ++n)
+ {
+ assert(output_shape.dim(n) == values_shape.dim(n));
+ }
+ }
+}
+
+void OperationValidator::visit(const ir::operation::Exp &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Exp::Input::INPUT)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(input_index);
+
+ assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape());
+ assert(_ctx.at(output_index).typeInfo().type() == _ctx.at(input_index).typeInfo().type());
+}
+
+void OperationValidator::visit(const ir::operation::Floor &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Floor::Input::INPUT)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(input_index);
+
+ assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape());
+ assert(_ctx.at(output_index).typeInfo().type() == _ctx.at(input_index).typeInfo().type());
+}
+
+void OperationValidator::visit(const ir::operation::HashtableLookup &node)
+{
+ const auto output_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::OUTPUT)};
+ const auto hits_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::HITS)};
+
+ const auto lookups_index{node.getInputs().at(ir::operation::HashtableLookup::Input::LOOKUPS)};
+ const auto keys_index{node.getInputs().at(ir::operation::HashtableLookup::Input::KEYS)};
+ const auto values_index{node.getInputs().at(ir::operation::HashtableLookup::Input::VALUES)};
+
+ const auto &output_obj = _ctx.at(output_index);
+ const auto &hits_obj = _ctx.at(hits_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);
+
+ assert(lookups_obj.typeInfo().type() == ir::DataType::INT32);
+ assert(keys_obj.typeInfo().type() == ir::DataType::INT32);
+ assert(hits_obj.typeInfo().type() == ir::DataType::QUANT8_ASYMM);
+
+ const auto &output_shape = output_obj.shape();
+ const auto &hits_shape = hits_obj.shape();
+
+ const auto &lookups_shape = lookups_obj.shape();
+ const auto &keys_shape = keys_obj.shape();
+ const auto &values_shape = values_obj.shape();
+
+ UNUSED_RELEASE(output_shape);
+ UNUSED_RELEASE(hits_shape);
+ UNUSED_RELEASE(lookups_shape);
+ UNUSED_RELEASE(keys_shape);
+ UNUSED_RELEASE(values_shape);
+
+ assert(values_shape.rank() == output_shape.rank());
+ assert(lookups_shape.rank() == 1);
+ assert(keys_shape.rank() == 1);
+ assert(values_shape.dim(0) == keys_shape.dim(0));
+ assert(lookups_shape.dim(0) == output_shape.dim(0));
+}
+
+void OperationValidator::visit(const ir::operation::TransposeConv &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ 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
+ assert(_ctx.at(ofm_index).shape().rank() == 4);
+ assert(_ctx.at(ofm_index).shape().rank() == _ctx.at(ifm_index).shape().rank());
+ assert(_ctx.at(ofm_index).shape().rank() == _ctx.at(ker_index).shape().rank());
+
+ const auto frontend_layout = _current_subg_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);
+
+ UNUSED_RELEASE(ofm_shape);
+ UNUSED_RELEASE(ifm_shape);
+ UNUSED_RELEASE(ker_shape);
+
+ assert((node.param().padding.type == ir::PaddingType::SAME) ||
+ (node.param().padding.type == ir::PaddingType::VALID));
+ assert(ifm_shape.N == ofm_shape.N);
+ assert(ifm_shape.C == ker_shape.C);
+ assert(ker_shape.N == ofm_shape.C);
+}
+
+void OperationValidator::visit(const ir::operation::Gather &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+
+ const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)};
+ const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)};
+
+ const auto axis = node.param().axis;
+
+ 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();
+
+ UNUSED_RELEASE(ifm_shape);
+ UNUSED_RELEASE(indices_shape);
+ UNUSED_RELEASE(ofm_shape);
+ UNUSED_RELEASE(axis);
+
+ assert(ifm_shape.rank() <= 4);
+ assert(indices_shape.rank() <= 3);
+ assert(ofm_shape.rank() <= 4);
+}
+
+void OperationValidator::visit(const ir::operation::Dequantize &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::Dequantize::Input::INPUT)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(input_index);
+
+ assert(_ctx.at(input_index).shape().rank() <= 4);
+ assert(_ctx.at(input_index).shape() == _ctx.at(output_index).shape());
+ assert(_ctx.at(input_index).typeInfo().type() == ir::DataType::QUANT8_ASYMM);
+ assert(_ctx.at(output_index).typeInfo().type() == ir::DataType::FLOAT32);
+}
+
+void OperationValidator::visit(const ir::operation::Mean &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::Mean::Input::INPUT)};
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape();
+ const auto ofm_shape = _ctx.at(ofm_index).shape();
+
+ // 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 (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank())
+ {
+ if (ofm_shape.rank() == 2)
+ {
+ // Reducing HW
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1));
+ }
+ else if (ofm_shape.rank() == 3)
+ {
+ // Reducing C or
+ // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1)
+ assert((ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) &&
+ ifm_shape.dim(2) == ofm_shape.dim(2)) ||
+ (ifm_shape.dim(0) == ofm_shape.dim(0) &&
+ (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) &&
+ ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1));
+ }
+ }
+}
+
+void OperationValidator::visit(const ir::operation::DepthToSpace &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(ir::operation::DepthToSpace::Input::INPUT)};
+
+ const auto frontend_layout = _current_subg_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);
+
+ UNUSED_RELEASE(output_shape);
+ UNUSED_RELEASE(input_shape);
+
+ assert(_ctx.at(input_index).shape().rank() == 4);
+ assert(_ctx.at(output_index).shape().rank() == 4);
+
+ int32_t block_size = node.param().block_size;
+
+ UNUSED_RELEASE(block_size);
+
+ assert(block_size > 0);
+
+ { // assertions block
+ assert(output_shape.N == input_shape.N);
+ assert(output_shape.H == input_shape.H * block_size);
+ assert(output_shape.W == input_shape.W * block_size);
+ assert(input_shape.C % (block_size * block_size) == 0);
+ assert(output_shape.C == input_shape.C / (block_size * block_size));
+ }
+}
+
+void OperationValidator::visit(const ir::operation::Pack &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto num{node.param().num};
+ const auto axis{node.param().axis};
+
+ 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();
+
+ UNUSED_RELEASE(num);
+ UNUSED_RELEASE(axis);
+ UNUSED_RELEASE(output_rank);
+
+ assert(num == static_cast<int32_t>(node.getInputs().size()));
+ assert(axis >= -output_rank && axis < output_rank);
+ for (const auto &index : node.getInputs())
+ {
+ UNUSED_RELEASE(index);
+ assert(input_shape == _ctx.at(index).shape());
+ }
+}
+
+void OperationValidator::visit(const ir::operation::ReduceMin &node)
+{
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(ir::operation::ReduceMin::Input::INPUT)};
+ const auto &axes = node.param().axes;
+
+ auto ifm_shape = _ctx.at(ifm_index).shape();
+ auto ofm_shape = _ctx.at(ofm_index).shape();
+
+ UNUSED_RELEASE(ifm_shape);
+ UNUSED_RELEASE(ofm_shape);
+ UNUSED_RELEASE(axes);
+
+ assert(ifm_shape.rank() <= 4);
+ assert(ofm_shape.rank() <= ifm_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 (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank())
+ {
+ if (ofm_shape.rank() == 2)
+ {
+ // Reducing HW
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1));
+ }
+ else if (ofm_shape.rank() == 3)
+ {
+ // Reducing C or
+ // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1)
+ assert((ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) &&
+ ifm_shape.dim(2) == ofm_shape.dim(2)) ||
+ (ifm_shape.dim(0) == ofm_shape.dim(0) &&
+ (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) &&
+ ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1));
+ }
+ }
+}
+
+void OperationValidator::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 scratch_buffer_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)};
+ const auto output_state_out_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)};
+ const auto cell_state_out_index{
+ node.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)};
+ const auto output_index{node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)};
+
+ const auto input_index{node.getInputs().at(ir::operation::LSTM::Input::INPUT)};
+ const auto input_to_input_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)};
+ 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)};
+ 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)};
+ const auto cell_to_forget_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_FORGET_WEIGHTS)};
+ const auto cell_to_output_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_OUTPUT_WEIGHTS)};
+ const auto input_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::INPUT_GATE_BIAS)};
+ const auto forget_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::FORGET_GATE_BIAS)};
+ const auto cell_bias_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_BIAS)};
+ const auto output_gate_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_GATE_BIAS)};
+ const auto projection_weights_index{
+ node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_WEIGHTS)};
+ const auto projection_bias_index{
+ node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_BIAS)};
+ 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)};
+
+ UNUSED_RELEASE(scratch_buffer_index);
+ UNUSED_RELEASE(output_state_out_index);
+ UNUSED_RELEASE(cell_state_out_index);
+ UNUSED_RELEASE(output_index);
+
+ UNUSED_RELEASE(input_index);
+ UNUSED_RELEASE(input_to_input_weights_index);
+ UNUSED_RELEASE(input_to_forget_weights_index);
+ UNUSED_RELEASE(input_to_cell_weights_index);
+ UNUSED_RELEASE(input_to_output_weights_index);
+ UNUSED_RELEASE(recurrent_to_input_weights_index);
+ UNUSED_RELEASE(recurrent_to_forget_weights_index);
+ UNUSED_RELEASE(recurrent_to_cell_weights_index);
+ UNUSED_RELEASE(recurrent_to_output_weights_index);
+ UNUSED_RELEASE(cell_to_input_weights_index);
+ UNUSED_RELEASE(cell_to_forget_weights_index);
+ UNUSED_RELEASE(cell_to_output_weights_index);
+ UNUSED_RELEASE(input_gate_bias_index);
+ UNUSED_RELEASE(forget_gate_bias_index);
+ UNUSED_RELEASE(cell_bias_index);
+ UNUSED_RELEASE(output_gate_bias_index);
+ UNUSED_RELEASE(projection_weights_index);
+ UNUSED_RELEASE(projection_bias_index);
+ UNUSED_RELEASE(output_state_in_index);
+ UNUSED_RELEASE(cell_state_in_index);
+
+ assert(_ctx.at(scratch_buffer_index).shape().rank() == 2 &&
+ _ctx.at(output_state_out_index).shape().rank() == 2 &&
+ _ctx.at(cell_state_out_index).shape().rank() == 2 &&
+ _ctx.at(output_index).shape().rank() == 2 && _ctx.at(input_index).shape().rank() == 2 &&
+ _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.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.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);
+
+ assert(_ctx.at(cell_to_input_weights_index).shape().rank() == 1 &&
+ _ctx.at(cell_to_forget_weights_index).shape().rank() == 1 &&
+ _ctx.at(cell_to_output_weights_index).shape().rank() == 1 &&
+ _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.at(projection_bias_index).shape().rank() == 1);
+
+ // CIFG assertion
+ assert((_ctx.at(input_to_input_weights_index).shape().dim(0) == 0 &&
+ _ctx.at(input_to_input_weights_index).shape().dim(1) == 0 &&
+ _ctx.at(recurrent_to_input_weights_index).shape().dim(0) == 0 &&
+ _ctx.at(recurrent_to_input_weights_index).shape().dim(1) == 0 &&
+ _ctx.at(input_gate_bias_index).shape().dim(0) == 0 &&
+ _ctx.at(cell_to_input_weights_index).shape().dim(0) == 0) ||
+ (_ctx.at(input_to_input_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(input_to_input_weights_index).shape().dim(1) != 0 &&
+ _ctx.at(recurrent_to_input_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(recurrent_to_input_weights_index).shape().dim(1) != 0 &&
+ _ctx.at(input_gate_bias_index).shape().dim(0) != 0));
+
+ // Peephole assertion
+ assert((_ctx.at(cell_to_forget_weights_index).shape().dim(0) == 0 &&
+ _ctx.at(cell_to_output_weights_index).shape().dim(0) == 0) ||
+ (_ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0));
+
+ bool has_input_to_input_weights = _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.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.at(input_gate_bias_index).shape().dim(0) != 0;
+ bool has_cell_to_input_weights = _ctx.at(cell_to_input_weights_index).shape().dim(0) != 0;
+ bool has_cell_to_forget_weights = _ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0;
+ bool has_cell_to_output_weights = _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0;
+ bool has_projection_weights = _ctx.at(projection_weights_index).shape().dim(0) != 0 &&
+ _ctx.at(projection_weights_index).shape().dim(1) != 0;
+ bool has_projection_bias = _ctx.at(projection_bias_index).shape().dim(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;
+
+ UNUSED_RELEASE(has_input_to_input_weights);
+ UNUSED_RELEASE(has_recurrent_to_input_weights);
+ UNUSED_RELEASE(has_input_gate_bias);
+ UNUSED_RELEASE(has_cell_to_input_weights);
+ UNUSED_RELEASE(has_cell_to_forget_weights);
+ UNUSED_RELEASE(has_cell_to_output_weights);
+ UNUSED_RELEASE(has_projection_weights);
+ UNUSED_RELEASE(has_projection_bias);
+ UNUSED_RELEASE(has_cifg_param);
+ UNUSED_RELEASE(has_peephole_param);
+ UNUSED_RELEASE(has_projection_param);
+
+ const auto batch_size = _ctx.at(input_index).shape().dim(0);
+ UNUSED_RELEASE(batch_size);
+ assert(batch_size == _ctx.at(output_state_in_index).shape().dim(0) &&
+ batch_size == _ctx.at(cell_state_in_index).shape().dim(0) &&
+ batch_size == _ctx.at(scratch_buffer_index).shape().dim(0) &&
+ batch_size == _ctx.at(output_state_out_index).shape().dim(0) &&
+ batch_size == _ctx.at(cell_state_out_index).shape().dim(0) &&
+ batch_size == _ctx.at(output_index).shape().dim(0));
+
+ const auto input_size = _ctx.at(input_index).shape().dim(1);
+ UNUSED_RELEASE(input_size);
+ assert(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(cell_state_out_index).shape().dim(1);
+ UNUSED_RELEASE(num_units);
+ assert(num_units == _ctx.at(input_to_forget_weights_index).shape().dim(0) &&
+ 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) &&
+ (((num_units * 3) == _ctx.at(scratch_buffer_index).shape().dim(1)) ||
+ ((num_units * 4) == _ctx.at(scratch_buffer_index).shape().dim(1))));
+
+ const auto output_size = _ctx.at(output_index).shape().dim(1);
+ UNUSED_RELEASE(output_size);
+ assert(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) &&
+ output_size == _ctx.at(output_state_out_index).shape().dim(1));
+
+ if (has_cifg_param)
+ {
+ assert(input_size == _ctx.at(input_to_input_weights_index).shape().dim(1));
+ assert(num_units == _ctx.at(input_to_input_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(recurrent_to_input_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 /* non-peephole */) &&
+ num_units == _ctx.at(input_gate_bias_index).shape().dim(0));
+ assert(output_size == _ctx.at(recurrent_to_input_weights_index).shape().dim(1));
+ assert(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.
+ assert(has_peephole_param);
+ }
+ assert(_ctx.at(scratch_buffer_index).shape().dim(1) == num_units * 4);
+ }
+ else
+ {
+ assert(_ctx.at(scratch_buffer_index).shape().dim(1) == num_units * 3);
+ }
+
+ if (has_peephole_param)
+ {
+ assert(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)
+ {
+ assert(num_units == _ctx.at(projection_weights_index).shape().dim(1));
+ assert(output_size == _ctx.at(projection_weights_index).shape().dim(0));
+ if (has_projection_bias)
+ {
+ assert(output_size == _ctx.at(projection_bias_index).shape().dim(0));
+ }
+ }
+}
+
+void OperationValidator::visit(const ir::operation::Unpack &node)
+{
+ const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)};
+ const auto num{node.param().num};
+ const auto axis{node.param().axis};
+
+ const auto &input_shape = _ctx.at(input_index).shape();
+ const auto input_rank = static_cast<int32_t>(input_shape.rank());
+
+ UNUSED_RELEASE(num);
+ UNUSED_RELEASE(axis);
+ UNUSED_RELEASE(input_rank);
+
+ assert(num == static_cast<int32_t>(node.getOutputs().size()));
+ assert(axis >= -input_rank && axis < input_rank);
+}
+
+void OperationValidator::visit(const ir::operation::Pad &node)
+{
+ const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)};
+ const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)};
+ const auto output_index{node.getInputs().at(0)};
+
+ const auto &pad_shape = _ctx.at(pad_index).shape();
+ const auto input_rank = static_cast<int32_t>(_ctx.at(input_index).shape().rank());
+
+ UNUSED_RELEASE(pad_shape);
+ UNUSED_RELEASE(input_rank);
+ UNUSED_RELEASE(output_index);
+
+ assert(pad_shape.rank() == 2);
+ assert(pad_shape.dim(0) == input_rank);
+ assert(pad_shape.dim(1) == 2);
+ assert(_ctx.at(pad_index).typeInfo().type() == ir::DataType::INT32);
+ assert(_ctx.at(input_index).shape().rank() == _ctx.at(output_index).shape().rank());
+}
+
+void OperationValidator::visit(const ir::operation::Min &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::Min::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::Min::Input::RHS)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(lhs_index);
+ UNUSED_RELEASE(rhs_index);
+
+ assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(rhs_index).typeInfo().type());
+ assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(output_index).typeInfo().type());
+}
+
+void OperationValidator::visit(const ir::operation::Max &node)
+{
+ const auto output_index{node.getOutputs().at(0)};
+ const auto lhs_index{node.getInputs().at(ir::operation::Max::Input::LHS)};
+ const auto rhs_index{node.getInputs().at(ir::operation::Max::Input::RHS)};
+
+ UNUSED_RELEASE(output_index);
+ UNUSED_RELEASE(lhs_index);
+ UNUSED_RELEASE(rhs_index);
+
+ assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(rhs_index).typeInfo().type());
+ assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(output_index).typeInfo().type());
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/OperationValidator.h b/runtime/neurun/core/src/compiler/OperationValidator.h
new file mode 100644
index 000000000..6ff3c7815
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/OperationValidator.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_COMPILER_OPERATION_VALIDATOR_H__
+#define __NEURUN_COMPILER_OPERATION_VALIDATOR_H__
+
+#include "ir/Layout.h"
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+class Graph;
+class Operands;
+} // namespace ir
+} // namespace neurun
+
+namespace neurun
+{
+namespace compiler
+{
+
+class OperationValidator : public ir::OperationVisitor
+{
+public:
+ OperationValidator(void) = delete;
+ OperationValidator(const ir::Graph &graph);
+
+public:
+ void operator()();
+
+public:
+ void visit(const ir::operation::BatchToSpaceND &node) override;
+ void visit(const ir::operation::Cast &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::ReduceSum &node) override;
+ void visit(const ir::operation::Transpose &node) override;
+ void visit(const ir::operation::ReduceMax &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::EmbeddingLookup &node) override;
+ void visit(const ir::operation::Exp &node) override;
+ void visit(const ir::operation::Floor &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::Dequantize &node) override;
+ void visit(const ir::operation::Mean &node) override;
+ void visit(const ir::operation::DepthToSpace &node) override;
+ void visit(const ir::operation::Pack &node) override;
+ void visit(const ir::operation::ReduceMin &node) override;
+ void visit(const ir::operation::LSTM &node) override;
+ void visit(const ir::operation::Unpack &node) override;
+ void visit(const ir::operation::Pad &node) override;
+ void visit(const ir::operation::Min &node) override;
+ void visit(const ir::operation::Max &node) override;
+
+private:
+ // TODO Remove _ctx field
+ const ir::Graph &_graph;
+ const ir::Operands &_ctx;
+ ir::Layout _current_subg_layout;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_OPERATION_VALIDATOR_H__
diff --git a/runtime/neurun/core/src/compiler/ParamChecker.cc b/runtime/neurun/core/src/compiler/ParamChecker.cc
new file mode 100644
index 000000000..bf172b53f
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+namespace compiler
+{
+
+void ParamChecker::operator()()
+{
+ _model->operations().iterate(
+ [&](const ir::OperationIndex &, const ir::Operation &node) { node.accept(*this); });
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/ParamChecker.h b/runtime/neurun/core/src/compiler/ParamChecker.h
new file mode 100644
index 000000000..7e88ff185
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_COMPILER_PARAM_CHECKER_H__
+#define __NEURUN_COMPILER_PARAM_CHECKER_H__
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+class Graph;
+} // namespace ir
+} // namespace neurun
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_COMPILER_OPERATION_VALIDATOR_H__
diff --git a/runtime/neurun/core/src/compiler/SubTensorAnalyzer.cc b/runtime/neurun/core/src/compiler/SubTensorAnalyzer.cc
new file mode 100644
index 000000000..dae1a74ff
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/SubTensorAnalyzer.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SubTensorAnalyzer.h"
+
+#include <typeinfo>
+
+#include "cpp14/memory.h"
+#include "ir/OperandIndexSequence.h"
+#include "util/logging.h"
+#include "util/Coordinates.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+void SubTensorAnalyzer::visit(const ir::operation::Concat &node)
+{
+ // If operator is concat (or other operators related with subsumption), fill subsumption info
+ // TODO: if one tensor is subset of many parents or model input
+ // Solution 1. Handle 1st parent only, ignore others (need to invert for other children)
+ // Solution 2. Insert copy operation for other parents
+ int32_t axis_raw = node.param().axis;
+
+ const auto &output_index = node.getOutputs().at(0);
+ const auto &inputs = node.getInputs();
+
+ int32_t axis_point = 0;
+ const auto rank = _graph.operands().at(output_index).shape().rank();
+ int32_t axis = axis_raw < 0 ? (axis_raw + rank) : axis_raw;
+ assert(rank > axis);
+
+ for (const auto &input_index : inputs)
+ {
+ // NOTE Not support multiple parent tensor yet
+ //
+ // Let us consider the following example (where OP_i is not a CONCAT):
+ //
+ // %0 = OP_0
+ // %1 = OP_1
+ // %2 = OP_2
+ // %3 = CONCAT(%0, %1)
+ // %4 = CONCAT(%0, %2)
+ //
+ // %0 and %1 SHOULD be consecutive in order to eliminate the former CONCAT operation,
+ // which makes it impossible to eliminate the latter CONCAT operation.
+ // - Note that %0 and %2 cannot be consecutive.
+ if (_graph.operands().at(input_index).parent_info() != nullptr)
+ {
+ return;
+ }
+
+ // NOTE Not support the case that concat's input is a constant or a input of model
+ if (_graph.operands().at(input_index).isConstant() || _graph.getInputs().contains(input_index))
+ {
+ return;
+ }
+ }
+
+ for (const auto &input_index : inputs)
+ {
+ auto input_shape = _graph.operands().at(input_index).shape();
+ assert(rank == input_shape.rank());
+
+ neurun::util::Coordinates coordinate_info{};
+ for (int i = 0; i < rank; i++)
+ {
+ coordinate_info.set(i, 0);
+ }
+ coordinate_info.set(axis, axis_point);
+
+ auto parentInfo =
+ nnfw::cpp14::make_unique<ir::operand::ParentInfo>(output_index, coordinate_info);
+
+ _graph.operands().at(input_index).parent_info(std::move(parentInfo));
+
+ axis_point += input_shape.dim(axis);
+ }
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtime/neurun/core/src/compiler/SubTensorAnalyzer.h b/runtime/neurun/core/src/compiler/SubTensorAnalyzer.h
new file mode 100644
index 000000000..54d41e460
--- /dev/null
+++ b/runtime/neurun/core/src/compiler/SubTensorAnalyzer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file SubTensorAnalyzer.h
+ * @brief This file contains SubTensorAnalyzer to analyze tensor subsumption
+ * using operation visitor
+ */
+
+#ifndef __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__
+#define __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__
+
+#include "ir/OperationVisitor.h"
+#include "ir/Graph.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+/**
+ * @brief Class to analyze tensor subsumption
+ */
+class SubTensorAnalyzer : public ir::OperationVisitor
+{
+public:
+ /**
+ * @brief Construct a new SubTensorAnalyzer object
+ * @param[in] ctx Graph operand set
+ */
+ SubTensorAnalyzer(ir::Graph &graph) : _graph{graph}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void visit(const ir::operation::Concat &) override;
+
+private:
+ ir::Graph &_graph; // TODO Refactor : Do not update Operands
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__
diff --git a/runtime/neurun/core/src/dumper/dot/DotBuilder.cc b/runtime/neurun/core/src/dumper/dot/DotBuilder.cc
new file mode 100644
index 000000000..4c7089a9c
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+// DotDumper
+DotBuilder::DotBuilder() {}
+
+void DotBuilder::update(const Node &node_info)
+{
+ add(node_info);
+ for (auto edge : node_info.edges())
+ {
+ addEdge(node_info, *edge);
+ }
+}
+
+void DotBuilder::addSubgraph(const DotSubgraphInfo &subgraph_info)
+{
+ _dot << "op_seq 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 neurun
diff --git a/runtime/neurun/core/src/dumper/dot/DotBuilder.h b/runtime/neurun/core/src/dumper/dot/DotBuilder.h
new file mode 100644
index 000000000..c04f6bc52
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_DUMPER_DOT_DOT_BUILDER_H__
+#define __NEURUN_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 = neurun::ir::Operation;
+using Object = neurun::ir::Operand;
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+class DotBuilder
+{
+public:
+ DotBuilder();
+
+public:
+ void update(const Node &dotinfo);
+ void addSubgraph(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 neurun
+
+#endif // __NEURUN_DUMPER_DOT_DOT_BUILDER_H__
diff --git a/runtime/neurun/core/src/dumper/dot/DotDumper.cc b/runtime/neurun/core/src/dumper/dot/DotDumper.cc
new file mode 100644
index 000000000..44313a657
--- /dev/null
+++ b/runtime/neurun/core/src/dumper/dot/DotDumper.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/BackendManager.h"
+#include "backend/IConfig.h"
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+void DotDumper::dump(const std::string &tag)
+{
+ if (_level == Level::OFF)
+ {
+ return;
+ }
+
+ neurun::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;
+
+ operations.iterate([&](const ir::OperationIndex &index, const ir::Operation &op) {
+ auto node = nnfw::cpp14::make_unique<Operation>(index, op);
+
+ for (auto output : op.getOutputs())
+ {
+ using neurun::dumper::dot::Operand;
+ auto child = std::make_shared<Operand>(output, Operand::Type::MODEL_OUTPUT);
+ node->addEdge(child);
+ }
+
+ operation_nodes.emplace(index, std::move(node));
+ });
+
+ 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 : backend::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();
+ }
+ if (object.isConstant() || _graph.getInputs().contains(index))
+ {
+ showing_cond = showing_cond && (object.getUses().size() > 0);
+ }
+ if (showing_cond)
+ {
+ shown_operand_set.add(index);
+
+ auto type = [&]() {
+ using neurun::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 lower_info = _graph.getLowerInfo(index);
+ auto node = nnfw::cpp14::make_unique<Operand>(index, type);
+
+ {
+ // Display LowerInfo attributes
+ std::string label = std::to_string(index.value());
+ std::string fillcolor = "";
+ if (lower_info)
+ {
+ 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);
+ }
+
+ for (auto operation_index : object.getUses().list())
+ {
+ auto &operation = operations.at(operation_index);
+ auto child = std::make_shared<Operation>(operation_index, operation);
+ node->addEdge(child);
+ }
+
+ operand_nodes.emplace(index, std::move(node));
+ }
+ });
+
+ const auto subgraphs = _graph.subgraphs();
+ if (subgraphs)
+ {
+ subgraphs->iterate([&](const ir::SubgraphIndex &index, const ir::OpSequence &op_seq) {
+ const auto lower_info = _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};
+ subgraph_info.label(label);
+ subgraph_info.fillcolor(fillcolor);
+ dot_builder.addSubgraph(subgraph_info);
+
+ // Set fillcolor of all operations in the op_seq
+ for (const auto &op : op_seq.operations())
+ {
+ auto found = operation_nodes.find(op.index);
+ 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 neurun
diff --git a/runtime/neurun/core/src/dumper/dot/DotDumper.h b/runtime/neurun/core/src/dumper/dot/DotDumper.h
new file mode 100644
index 000000000..ec4d2b967
--- /dev/null
+++ b/runtime/neurun/core/src/dumper/dot/DotDumper.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.
+ */
+
+#include "ir/Graph.h"
+
+#ifndef __NEURUN_DUMPER_DOT_DOT_DUMPER_H__
+#define __NEURUN_DUMPER_DOT_DOT_DUMPER_H__
+
+namespace neurun
+{
+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) : _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 ir::Graph &_graph;
+ Level _level;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
+
+#endif // __NEURUN_DUMPER_DOT_DOT_DUMPER_H__
diff --git a/runtime/neurun/core/src/dumper/dot/DotSubgraphInfo.cc b/runtime/neurun/core/src/dumper/dot/DotSubgraphInfo.cc
new file mode 100644
index 000000000..8cfe35900
--- /dev/null
+++ b/runtime/neurun/core/src/dumper/dot/DotSubgraphInfo.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 "DotSubgraphInfo.h"
+
+#include <sstream>
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+DotSubgraphInfo::DotSubgraphInfo(const ir::SubgraphIndex &index, const ir::OpSequence &op_seq,
+ const util::Set<ir::OperandIndex> &shown_operands)
+ : _index{index}
+{
+ for (const auto &element : op_seq.operations())
+ {
+ _operations.insert(element.index);
+ for (auto o : element.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 : element.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 neurun
diff --git a/runtime/neurun/core/src/dumper/dot/DotSubgraphInfo.h b/runtime/neurun/core/src/dumper/dot/DotSubgraphInfo.h
new file mode 100644
index 000000000..0aa7c6ddf
--- /dev/null
+++ b/runtime/neurun/core/src/dumper/dot/DotSubgraphInfo.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 __NEURUN_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__
+#define __NEURUN_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__
+
+#include <unordered_set>
+
+#include "ir/Index.h"
+#include "ir/OpSequence.h"
+#include "util/Set.h"
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+class DotSubgraphInfo
+{
+public:
+ DotSubgraphInfo(const ir::SubgraphIndex &index, const ir::OpSequence &op_seq,
+ const util::Set<ir::OperandIndex> &shown_operands);
+
+ ir::SubgraphIndex 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::SubgraphIndex _index;
+ std::string _label;
+ std::string _fillcolor;
+ std::unordered_set<ir::OperationIndex> _operations;
+ std::unordered_set<ir::OperandIndex> _operands;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
+
+#endif // __NEURUN_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__
diff --git a/runtime/neurun/core/src/dumper/dot/Node.cc b/runtime/neurun/core/src/dumper/dot/Node.cc
new file mode 100644
index 000000000..166f0f40f
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/dumper/dot/Node.h b/runtime/neurun/core/src/dumper/dot/Node.h
new file mode 100644
index 000000000..364cb08a4
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_DUMPER_DOT_NODE_H__
+#define __NEURUN_DUMPER_DOT_NODE_H__
+
+#include <string>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+
+namespace neurun
+{
+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 addEdge(std::shared_ptr<Node> dotinfo) { _children.emplace_back(dotinfo); }
+ /**
+ * @brief Return list of edges
+ *
+ * @return Edges
+ */
+ const std::vector<std::shared_ptr<Node>> &edges() const { return _children; }
+
+private:
+ std::string _id;
+ std::unordered_map<std::string, std::string> _attributes;
+ std::vector<std::shared_ptr<Node>> _children;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
+
+#endif // __NEURUN_DUMPER_DOT_NODE_H__
diff --git a/runtime/neurun/core/src/dumper/dot/OperandNode.cc b/runtime/neurun/core/src/dumper/dot/OperandNode.cc
new file mode 100644
index 000000000..76d2c704c
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/dumper/dot/OperandNode.h b/runtime/neurun/core/src/dumper/dot/OperandNode.h
new file mode 100644
index 000000000..5ebd651b6
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__
+#define __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__
+
+#include <vector>
+
+#include "Node.h"
+#include "ir/Operand.h"
+#include "ir/Index.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__
diff --git a/runtime/neurun/core/src/dumper/dot/OperationNode.cc b/runtime/neurun/core/src/dumper/dot/OperationNode.cc
new file mode 100644
index 000000000..ca870ba05
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/dumper/dot/OperationNode.h b/runtime/neurun/core/src/dumper/dot/OperationNode.h
new file mode 100644
index 000000000..ba0713790
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__
+#define __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__
+
+#include "Node.h"
+#include "ir/Operation.h"
+#include "ir/Index.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__
diff --git a/runtime/neurun/core/src/exec/DataflowExecutor.cc b/runtime/neurun/core/src/exec/DataflowExecutor.cc
new file mode 100644
index 000000000..e22d41031
--- /dev/null
+++ b/runtime/neurun/core/src/exec/DataflowExecutor.cc
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 neurun
+{
+namespace exec
+{
+
+int64_t DataflowExecutor::calculateRank(const std::vector<ir::Element> &operations)
+{
+ int64_t rank = 0;
+ if (!_indexed_ranks)
+ {
+ return rank;
+ }
+ for (const auto &element : operations)
+ {
+ auto it = _indexed_ranks->find(element.index);
+ if (it == _indexed_ranks->end())
+ {
+ assert(element.node->opcode() == ir::OpCode::Permute);
+ // assign int32_t::max to prevent integer overflow
+ rank += std::numeric_limits<int32_t>::max();
+ }
+ else
+ {
+ rank += it->second;
+ }
+ }
+ return rank;
+}
+
+void DataflowExecutor::emplaceToReadyJobs(const uint32_t &id)
+{
+ auto &job = _waiting_jobs[id];
+ assert(job != nullptr);
+ auto &subg = _graph.subgraphs()->at(_job_to_op_seq[job->index()]);
+ auto rank = calculateRank(subg.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(const ir::Graph &graph,
+ const std::shared_ptr<compiler::OperandContext> &operand_context,
+ std::unique_ptr<backend::TensorManagerSet> tensor_mgrs,
+ CodeMap &&code_map)
+ : ExecutorBase{graph, operand_context, std::move(tensor_mgrs)}, _code_map{std::move(code_map)}
+{
+ VERBOSE(DataflowExecutor) << "Constructing Dataflow Executor" << std::endl;
+
+ const ir::Subgraphs *subgraphs = _graph.subgraphs();
+ // Assign jobs convert SubgraphIndex to job index(uint32_t)
+ uint32_t next_job_index = 0;
+ std::unordered_map<ir::SubgraphIndex, uint32_t> subgraph_to_job;
+ subgraphs->iterate([&](const ir::SubgraphIndex &subg_index, const ir::OpSequence &) {
+ VERBOSE(DataflowExecutor) << "Create a job #" << next_job_index << " with SubgraphIndex "
+ << subg_index.value() << std::endl;
+ _finished_jobs.emplace_back(
+ nnfw::cpp14::make_unique<Job>(next_job_index, _code_map.at(subg_index).get()));
+ subgraph_to_job[subg_index] = next_job_index++;
+ });
+
+ _waiting_jobs.resize(next_job_index);
+ _output_info.resize(next_job_index);
+ _initial_input_info.resize(next_job_index, 0);
+
+ subgraphs->iterate([&](const ir::SubgraphIndex &subg_index, const ir::OpSequence &subg) {
+ auto job_index = subgraph_to_job[subg_index];
+ for (auto output : subg.getOutputs())
+ {
+ // Update output and input info
+ subgraphs->iterate(
+ [&](const ir::SubgraphIndex &subg_cur_index, const ir::OpSequence &subg_cur) {
+ if (subg_cur.getInputs().contains(output))
+ {
+ auto dep_index = subgraph_to_job[subg_cur_index];
+ ++_initial_input_info[dep_index];
+ _output_info[job_index].push_back(dep_index);
+ }
+ });
+ }
+ });
+ for (const auto &s : subgraph_to_job)
+ _job_to_op_seq.emplace(s.second, s.first);
+
+ _input_info = _initial_input_info;
+}
+
+void DataflowExecutor::executeImpl()
+{
+ 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)
+ {
+ if (_input_info[i] == 0)
+ {
+ emplaceToReadyJobs(i);
+ }
+ }
+ assert(!_ready_jobs.empty()); // Cannot begin if there is no initial jobs
+ bool is_profiling = util::getConfigBool(util::config::PROFILING_MODE);
+
+ _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 subgraph_index = _job_to_op_seq[job_index];
+ auto op_seq = &_graph.subgraphs()->at(subgraph_index);
+ const backend::Backend *backend =
+ _graph.getLowerInfo()->operation.at(subgraph_index)->backend();
+
+ _subject.notifyJobBegin(this, op_seq, backend);
+
+ if (is_profiling)
+ job->fn()->runSync();
+ else
+ 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 neurun
diff --git a/runtime/neurun/core/src/exec/DataflowExecutor.h b/runtime/neurun/core/src/exec/DataflowExecutor.h
new file mode 100644
index 000000000..6c12093fd
--- /dev/null
+++ b/runtime/neurun/core/src/exec/DataflowExecutor.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 __NEURUN_EXEC_DATAFLOW_EXECUTOR_H__
+#define __NEURUN_EXEC_DATAFLOW_EXECUTOR_H__
+
+#include <list>
+#include <map>
+#include <unordered_map>
+
+#include "FunctionSequence.h"
+#include "Job.h"
+#include "ir/OperandIndexSequence.h"
+#include "ir/Index.h"
+#include "cpp14/memory.h"
+#include "exec/ExecutorBase.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+class DataflowExecutor : public ExecutorBase
+{
+public:
+ using CodeMap = std::unordered_map<ir::SubgraphIndex, std::unique_ptr<FunctionSequence>>;
+
+protected:
+ virtual void notify(uint32_t finished_job_id);
+ bool noWaitingJobs();
+
+public:
+ /**
+ * @brief Constructs a DataflowExecutor object
+ *
+ * @param graph Graph object
+ * @param operand_context (Only for input/output operand data access)
+ * @param code_map Compiled code map
+ * @param ranks Operation ranks for ordering execution
+ */
+ DataflowExecutor(const ir::Graph &graph,
+ const std::shared_ptr<compiler::OperandContext> &operand_context,
+ std::unique_ptr<backend::TensorManagerSet> tensor_mgrs, CodeMap &&code_map);
+
+ void executeImpl() override;
+
+protected:
+ int64_t calculateRank(const std::vector<ir::Element> &operations);
+ void emplaceToReadyJobs(const uint32_t &id);
+
+protected:
+ 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::SubgraphIndex> _job_to_op_seq;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_DATAFLOW_EXECUTOR_H__
diff --git a/runtime/neurun/core/src/exec/Execution.cc b/runtime/neurun/core/src/exec/Execution.cc
new file mode 100644
index 000000000..bc7bbd160
--- /dev/null
+++ b/runtime/neurun/core/src/exec/Execution.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/Execution.h"
+
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+Execution::Execution(const std::shared_ptr<IExecutor> &executor) : _executor{executor}
+{
+ _io_desc.inputs.resize(_executor->graph().getInputs().size());
+ _io_desc.outputs.resize(_executor->graph().getOutputs().size());
+}
+
+// TODO Remove default parameter
+void Execution::setInput(const ir::IOIndex &index, const void *buffer, size_t length,
+ ir::Layout layout)
+{
+ const auto input_index = graph().getInputs().at(index);
+ const auto info = graph().operands().at(input_index).info();
+
+ if (length < info.total_size())
+ {
+ throw std::runtime_error{"Too small length"};
+ }
+
+ _io_desc.inputs.at(index.value()) =
+ nnfw::cpp14::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)
+{
+ const ir::OperandInfo info{shape, type};
+
+ if (length < info.total_size())
+ {
+ throw std::runtime_error{"Too small length"};
+ }
+
+ _io_desc.inputs.at(index.value()) =
+ nnfw::cpp14::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 = graph().getOutputs().at(index);
+ const auto info = graph().operands().at(output_index).info();
+
+ if (length < info.total_size())
+ {
+ throw std::runtime_error{"Too small length"};
+ }
+
+ _io_desc.outputs.at(index.value()) =
+ nnfw::cpp14::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)
+{
+ const ir::OperandInfo info{shape, type};
+
+ if (length < info.total_size())
+ {
+ throw std::runtime_error{"Too small length"};
+ }
+
+ _io_desc.outputs.at(index.value()) =
+ nnfw::cpp14::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()) = nnfw::cpp14::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()) = nnfw::cpp14::make_unique<OutputDesc>(
+ output_desc->info, output_desc->buffer, output_desc->size, layout);
+}
+
+void Execution::execute()
+{
+ VERBOSE(Execution) << "Start execution" << std::endl;
+
+ _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 = nnfw::cpp14::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; }
+
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/ExecutionObservee.cc b/runtime/neurun/core/src/exec/ExecutionObservee.cc
new file mode 100644
index 000000000..3b342d703
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/exec/ExecutionObservee.h b/runtime/neurun/core/src/exec/ExecutionObservee.h
new file mode 100644
index 000000000..dafeef55b
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_EXEC_EXECUTION_OBSERVEE_H__
+#define __NEURUN_EXEC_EXECUTION_OBSERVEE_H__
+
+#include <list>
+
+#include "exec/ExecutionObservers.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_EXEC_EXECUTION_OBSERVEE__
diff --git a/runtime/neurun/core/src/exec/ExecutionObservers.cc b/runtime/neurun/core/src/exec/ExecutionObservers.cc
new file mode 100644
index 000000000..071a9e228
--- /dev/null
+++ b/runtime/neurun/core/src/exec/ExecutionObservers.cc
@@ -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.
+ */
+
+#include "exec/ExecutionObservers.h"
+
+#include <string>
+
+#include "util/logging.h"
+#include "ir/operation/Permute.h"
+#include "exec/IExecutor.h"
+#include "misc/polymorphic_downcast.h"
+#include "ir/OpSequence.h"
+
+namespace neurun
+{
+
+namespace exec
+{
+
+void ProfileObserver::handleBegin(neurun::exec::IExecutor *, const ir::OpSequence *,
+ const neurun::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
+ auto node = op_seq->operations().at(0).node;
+ 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::QUANT8_ASYMM;
+
+ uint32_t size = 0;
+ for (const auto &input : node->getInputs())
+ {
+ size += exec->graph().operands().at(input).info().total_size();
+ }
+ for (const auto &output : node->getOutputs())
+ {
+ size += exec->graph().operands().at(output).info().total_size();
+ }
+ if (node_name == "Permute")
+ {
+ auto *permute_node = nnfw::misc::polymorphic_downcast<const ir::operation::Permute *>(node);
+ assert(permute_node != nullptr);
+ _et->updatePermuteTime(permute_node->param().input_backend_ctx->backend,
+ permute_node->param().output_backend_ctx->backend, is_quantized, size,
+ timer_res);
+ }
+ else
+ {
+ _et->updateOperationExecTime(backend, node_name, is_quantized, size, timer_res);
+ }
+};
+
+ChromeTracingObserver::ChromeTracingObserver(const std::string &filepath)
+ : _ofs{filepath, std::ofstream::out}, _recorder{}, _collector{&_recorder}
+{
+}
+
+ChromeTracingObserver::~ChromeTracingObserver() { _recorder.writeToFile(_ofs); }
+
+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, subgraphTag(op_seq)});
+}
+
+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, subgraphTag(op_seq)});
+}
+
+void ChromeTracingObserver::handleEnd(IExecutor *)
+{
+ _collector.onEvent(EventCollector::Event{EventCollector::Edge::END, "runtime", "Graph"});
+}
+
+std::string ChromeTracingObserver::subgraphTag(const ir::OpSequence *op_seq)
+{
+ if (op_seq->size() == 0)
+ return "Empty OpSequence";
+
+ auto first_op = op_seq->operations().at(0);
+ std::string tag = "$" + std::to_string(first_op.index.value());
+ tag += " " + first_op.node->name();
+ if (op_seq->size() > 1)
+ {
+ tag += " (+" + std::to_string(op_seq->size() - 1) + ")";
+ }
+ return tag;
+}
+
+} // namespace exec
+
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/ExecutorBase.cc b/runtime/neurun/core/src/exec/ExecutorBase.cc
new file mode 100644
index 000000000..9692c2ba7
--- /dev/null
+++ b/runtime/neurun/core/src/exec/ExecutorBase.cc
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "util/logging.h"
+namespace neurun
+{
+namespace exec
+{
+
+ExecutorBase::ExecutorBase(const ir::Graph &graph,
+ const std::shared_ptr<compiler::OperandContext> &operand_context,
+ std::unique_ptr<backend::TensorManagerSet> tensor_mgrs)
+ : _graph{graph}, _operand_context{operand_context}, _tensor_mgrs{std::move(tensor_mgrs)},
+ _mutex()
+{
+ // DO NOTHING
+}
+
+std::unique_ptr<ISource> ExecutorBase::source(const ir::IOIndex &index, const ir::TypeInfo &type,
+ const void *buffer, size_t length,
+ ir::Layout io_layout)
+{
+ using ir::DataType;
+ switch (type.type())
+ {
+ case DataType::FLOAT32:
+ return source<float>(index, buffer, length, io_layout);
+ case DataType::INT32:
+ return source<int32_t>(index, buffer, length, io_layout);
+ case DataType::UINT32:
+ return source<uint32_t>(index, buffer, length, io_layout);
+ case DataType::BOOL8:
+ case DataType::QUANT8_ASYMM:
+ case DataType::UINT8:
+ return source<uint8_t>(index, buffer, length, io_layout);
+ case DataType::QUANT8_SYMM:
+ return source<int8_t>(index, buffer, length, io_layout);
+ default:
+ throw std::runtime_error("Not supported yet");
+ }
+}
+
+std::unique_ptr<ISink> ExecutorBase::sink(const ir::IOIndex &index, const ir::TypeInfo &type,
+ void *buffer, size_t length, ir::Layout io_layout)
+{
+ using ir::DataType;
+ switch (type.type())
+ {
+ case DataType::FLOAT32:
+ return sink<float>(index, buffer, length, io_layout);
+ case DataType::INT32:
+ return sink<int32_t>(index, buffer, length, io_layout);
+ case DataType::UINT32:
+ return sink<uint32_t>(index, buffer, length, io_layout);
+ case DataType::BOOL8:
+ case DataType::QUANT8_ASYMM:
+ case DataType::UINT8:
+ return sink<uint8_t>(index, buffer, length, io_layout);
+ case DataType::QUANT8_SYMM:
+ return sink<int8_t>(index, buffer, length, io_layout);
+ default:
+ throw std::runtime_error("Not supported yet");
+ }
+}
+
+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);
+
+ std::vector<std::unique_ptr<ISource>> sources{_graph.getInputs().size()};
+ std::vector<std::unique_ptr<ISink>> sinks{_graph.getOutputs().size()};
+
+ // Set input(s)
+ for (uint32_t n = 0; n < _graph.getInputs().size(); ++n)
+ {
+ ir::IOIndex input_index{n};
+ ir::OperandIndex index{_graph.getInputs().at(input_index)};
+
+ if (desc.inputs.at(n) == nullptr)
+ {
+ // Optional input
+ continue;
+ }
+
+ const auto operand_li = _graph.getLowerInfo()->operand.at(index).get();
+ if (operand_li->def_factors().empty())
+ {
+ // This input is not used (i.e. constant, EX. reshape's axis)
+ continue;
+ }
+
+ const auto &input = *desc.inputs.at(n);
+ sources.at(n) =
+ source(input_index, input.info.typeInfo(), input.buffer, input.size, input.layout);
+
+ auto setter = [&](::neurun::backend::operand::ITensor &tensor) { sources.at(n)->push(tensor); };
+
+ auto object = _operand_context->at(index);
+
+ object->access(setter);
+ }
+
+ executeImpl();
+
+ // Get output(s)
+ for (uint32_t n = 0; n < _graph.getOutputs().size(); ++n)
+ {
+ ir::IOIndex output_index{n};
+ // Optional output
+ if (desc.outputs.at(n) == nullptr)
+ {
+ continue;
+ }
+ const auto &output = *desc.outputs.at(n);
+ sinks.at(n) =
+ sink(output_index, output.info.typeInfo(), output.buffer, output.size, output.layout);
+
+ auto getter = [&](::neurun::backend::operand::ITensor &tensor) { sinks.at(n)->pull(tensor); };
+
+ ir::OperandIndex index{_graph.getOutputs().at(output_index)};
+ auto object = _operand_context->at(index);
+
+ object->access(getter);
+ }
+}
+
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/ExecutorBase.h b/runtime/neurun/core/src/exec/ExecutorBase.h
new file mode 100644
index 000000000..a93e036a5
--- /dev/null
+++ b/runtime/neurun/core/src/exec/ExecutorBase.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.
+ */
+
+#ifndef __NEURUN_EXEC_EXECUTOR_BASE_H__
+#define __NEURUN_EXEC_EXECUTOR_BASE_H__
+
+#include <mutex>
+
+#include "Source.h"
+#include "exec/ExecutionObservers.h"
+#include "Sink.h"
+#include "exec/IExecutor.h"
+#include "ir/Graph.h"
+#include "ir/LowerInfoMap.h"
+#include "backend/IConfig.h"
+#include "backend/Backend.h"
+#include "compiler/OperandContext.h"
+#include "backend/ExecTime.h"
+#include "exec/IFunction.h"
+#include "backend/ITensorManager.h"
+#include "exec/ExecutionObservee.h"
+#include <list>
+
+namespace neurun
+{
+namespace exec
+{
+
+class ExecutorBase : public IExecutor
+{
+public:
+ ExecutorBase(const ir::Graph &graph,
+ const std::shared_ptr<compiler::OperandContext> &operand_context,
+ std::unique_ptr<backend::TensorManagerSet> tensor_mgrs);
+
+ virtual ~ExecutorBase() = default;
+
+ const ir::Graph &graph() final { return _graph; }
+
+ 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)); };
+
+private:
+ std::unique_ptr<ISource> source(const ir::IOIndex &index, const ir::TypeInfo &type,
+ const void *buffer, size_t length, ir::Layout io_layout);
+ std::unique_ptr<ISink> sink(const ir::IOIndex &index, const ir::TypeInfo &type, void *buffer,
+ size_t length, ir::Layout io_layout);
+
+ template <typename T>
+ std::unique_ptr<ISource> source(const ir::IOIndex &index, const void *buffer, size_t length,
+ ir::Layout io_layout)
+ {
+ const auto operand_index = _graph.getInputs().at(index);
+ const auto &operand = _graph.operands().at(operand_index);
+
+ const auto tensor = _operand_context->at(operand_index);
+ const auto tensor_layout = tensor->layout();
+
+ if (((io_layout == ir::Layout::NHWC) && (tensor_layout == ir::Layout::NCHW)) ||
+ ((io_layout == ir::Layout::NCHW) && (tensor_layout == ir::Layout::NHWC)))
+ {
+ return nnfw::cpp14::make_unique<PermutateSource<T>>(buffer, length, operand.shape(),
+ io_layout);
+ }
+ // TODO Change this to return error
+ assert(io_layout != ir::Layout::UNKNOWN ||
+ (tensor_layout != ir::Layout::NCHW && tensor_layout != ir::Layout::NCHW));
+
+ return nnfw::cpp14::make_unique<CopySource<T>>(buffer, length, operand.shape());
+ }
+
+ template <typename T>
+ std::unique_ptr<ISink> sink(const ir::IOIndex &index, void *buffer, size_t length,
+ ir::Layout io_layout)
+ {
+ const auto operand_index = _graph.getOutputs().at(index);
+ const auto &operand = _graph.operands().at(operand_index);
+ const auto tensor = _operand_context->at(operand_index);
+ const auto tensor_layout = tensor->layout();
+
+ if (((tensor_layout == ir::Layout::NCHW) && (io_layout == ir::Layout::NHWC)) ||
+ ((tensor_layout == ir::Layout::NHWC) && (io_layout == ir::Layout::NCHW)))
+ {
+ return nnfw::cpp14::make_unique<PermutateSink<T>>(buffer, length, operand.shape(), io_layout);
+ }
+ // TODO Change this to return error
+ assert(io_layout != ir::Layout::UNKNOWN ||
+ (tensor_layout != ir::Layout::NCHW && tensor_layout != ir::Layout::NCHW));
+
+ return nnfw::cpp14::make_unique<CopySink<T>>(buffer, length, operand.shape());
+ }
+
+protected:
+ ExecutionObservee _subject;
+ std::shared_ptr<ir::OperationIndexMap<int64_t>> _indexed_ranks;
+ const ir::Graph &_graph;
+ std::shared_ptr<compiler::OperandContext> _operand_context;
+ std::unique_ptr<backend::TensorManagerSet> _tensor_mgrs;
+ std::mutex _mutex;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_EXECUTOR_BASE_H__
diff --git a/runtime/neurun/core/src/exec/FunctionSequence.cc b/runtime/neurun/core/src/exec/FunctionSequence.cc
new file mode 100644
index 000000000..00214fcfa
--- /dev/null
+++ b/runtime/neurun/core/src/exec/FunctionSequence.cc
@@ -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.
+ */
+
+#include "FunctionSequence.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+void FunctionSequence::run()
+{
+ for (const auto &function : _functions)
+ {
+ function->run();
+ }
+}
+
+void FunctionSequence::runSync()
+{
+ for (const auto &function : _functions)
+ {
+ function->runSync();
+ }
+}
+
+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 neurun
diff --git a/runtime/neurun/core/src/exec/FunctionSequence.h b/runtime/neurun/core/src/exec/FunctionSequence.h
new file mode 100644
index 000000000..2ba5c0b08
--- /dev/null
+++ b/runtime/neurun/core/src/exec/FunctionSequence.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 __NEURUN_EXEC_FUNCTION_SEQUENCE_H__
+#define __NEURUN_EXEC_FUNCTION_SEQUENCE_H__
+
+#include <memory>
+#include <vector>
+#include <functional>
+
+#include "exec/IFunction.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+class FunctionSequence : public IFunction
+{
+public:
+ virtual ~FunctionSequence() = default;
+
+ void run() override;
+ void runSync() 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);
+
+private:
+ std::vector<std::unique_ptr<IFunction>> _functions;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_FUNCTION_SEQUENCE_H__
diff --git a/runtime/neurun/core/src/exec/Job.cc b/runtime/neurun/core/src/exec/Job.cc
new file mode 100644
index 000000000..ba02daf30
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+namespace exec
+{
+
+Job::Job(uint32_t index, IFunction *fn) : _index{index}, _fn{fn} {}
+
+void Job::run() { _fn->run(); }
+
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/Job.h b/runtime/neurun/core/src/exec/Job.h
new file mode 100644
index 000000000..1516b9281
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_EXEC_JOB_H__
+#define __NEURUN_EXEC_JOB_H__
+
+#include <unordered_set>
+
+#include "exec/IFunction.h"
+#include "ir/Index.h"
+#include "ir/OperandIndexSequence.h"
+#include "backend/Backend.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+class Job
+{
+public:
+ /**
+ * @brief Constructs a Job object
+ *
+ * @param index Operation index for this job
+ * @param fn compiled code to run this job
+ * @param inputs Input operand list
+ * @param outputs Output operand list
+ */
+ Job(uint32_t index, IFunction *fn);
+ /**
+ * @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
+ */
+ IFunction *fn() { return _fn; }
+
+private:
+ uint32_t _index;
+ IFunction *_fn;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_JOB_H__
diff --git a/runtime/neurun/core/src/exec/LinearExecutor.cc b/runtime/neurun/core/src/exec/LinearExecutor.cc
new file mode 100644
index 000000000..d41dba880
--- /dev/null
+++ b/runtime/neurun/core/src/exec/LinearExecutor.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 "LinearExecutor.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+void LinearExecutor::executeImpl()
+{
+ _subject.notifyModelBegin(this);
+ for (auto &&code : _code)
+ {
+ const auto op_seq = code.elem.op_seq;
+ const auto backend = code.elem.lower_info->backend();
+ _subject.notifyJobBegin(this, op_seq, backend);
+ code.fn->run();
+ _subject.notifyJobEnd(this, op_seq, backend);
+ }
+ _subject.notifyModelEnd(this);
+}
+
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/LinearExecutor.h b/runtime/neurun/core/src/exec/LinearExecutor.h
new file mode 100644
index 000000000..baf063a12
--- /dev/null
+++ b/runtime/neurun/core/src/exec/LinearExecutor.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 LinearExecutor.h
+ * @brief This file contains LinearExecutor class to define and run execution phase
+ */
+
+#ifndef __NEURUN_EXEC_EXECUTOR_H_
+#define __NEURUN_EXEC_EXECUTOR_H_
+
+#include "ExecutorBase.h"
+#include "compiler/Linear.h"
+#include "exec/FunctionSequence.h"
+#include "compiler/CodeWithInfo.h"
+
+namespace neurun
+{
+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[in] plan Execution plan generated by compiled result
+ */
+ LinearExecutor(const ir::Graph &graph,
+ const std::shared_ptr<compiler::OperandContext> &operand_context,
+ std::unique_ptr<backend::TensorManagerSet> tensor_mgrs,
+ std::vector<compiler::CodeWithInfo> &&code)
+ : ExecutorBase{graph, operand_context, std::move(tensor_mgrs)}, _code{std::move(code)}
+ {
+ }
+
+public:
+ void executeImpl(void) override;
+
+private:
+ std::vector<compiler::CodeWithInfo> _code;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_EXECUTOR_H_
diff --git a/runtime/neurun/core/src/exec/ParallelExecutor.cc b/runtime/neurun/core/src/exec/ParallelExecutor.cc
new file mode 100644
index 000000000..c73c353d3
--- /dev/null
+++ b/runtime/neurun/core/src/exec/ParallelExecutor.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 "ParallelExecutor.h"
+
+#include <cassert>
+
+#include "util/logging.h"
+#include "exec/IFunction.h"
+
+namespace neurun
+{
+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();
+ }
+ void runSync() override { throw("runSync is needed just for profiling in Dataflow executor"); }
+
+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(const ir::Graph &graph,
+ const std::shared_ptr<compiler::OperandContext> &operand_context,
+ std::unique_ptr<backend::TensorManagerSet> tensor_mgrs,
+ CodeMap &&code_map)
+ : DataflowExecutor{graph, operand_context, std::move(tensor_mgrs), std::move(code_map)}
+{
+ VERBOSE(ParallelExecutor) << "Constructing Parallel Executor" << std::endl;
+}
+
+void ParallelExecutor::executeImpl()
+{
+ // Init scheduler
+ // TODO Consider to have distinct backend set in LowerInfoMap
+ ir::BackendSet backends;
+ for (auto &itr : _graph.getLowerInfo()->operation)
+ {
+ backends.add(itr.second->backend());
+ }
+ _scheduler = nnfw::cpp14::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 subgraph_index = _job_to_op_seq[job_index];
+ auto op_seq = &_graph.subgraphs()->at(subgraph_index);
+ auto backend = _graph.getLowerInfo()->operation.at(subgraph_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);
+ };
+
+ _scheduler->assign(nnfw::cpp14::make_unique<HookFunction>(job->fn(), 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 neurun
diff --git a/runtime/neurun/core/src/exec/ParallelExecutor.h b/runtime/neurun/core/src/exec/ParallelExecutor.h
new file mode 100644
index 000000000..54377fd9e
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_EXEC_PARALLEL_EXECUTOR_H__
+#define __NEURUN_EXEC_PARALLEL_EXECUTOR_H__
+
+#include <list>
+#include <queue>
+#include <unordered_map>
+
+#include "FunctionSequence.h"
+#include "Job.h"
+#include "ir/OperandIndexSequence.h"
+#include "ir/Index.h"
+#include "cpp14/memory.h"
+#include "exec/DataflowExecutor.h"
+#include "ParallelScheduler.h"
+
+namespace neurun
+{
+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 graph Graph object
+ * @param operand_context (Only for input/output operand data access)
+ * @param code_map Compiled code map
+ * @param ranks Operation ranks for ordering execution
+ */
+ ParallelExecutor(const ir::Graph &graph,
+ const std::shared_ptr<compiler::OperandContext> &operand_context,
+ std::unique_ptr<backend::TensorManagerSet> tensor_mgrs, CodeMap &&code_map);
+
+ void executeImpl() override;
+
+private:
+ std::condition_variable _cv_jobs;
+ std::mutex _mu_jobs;
+ std::unique_ptr<ParallelScheduler> _scheduler;
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_PARALLEL_EXECUTOR_H__
diff --git a/runtime/neurun/core/src/exec/ParallelScheduler.cc b/runtime/neurun/core/src/exec/ParallelScheduler.cc
new file mode 100644
index 000000000..5f9e9e013
--- /dev/null
+++ b/runtime/neurun/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 "cpp14/memory.h"
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+ParallelScheduler::ParallelScheduler(const ir::BackendSet &backends)
+{
+ assert(!backends.empty());
+
+ for (auto backend : backends)
+ {
+ _thread_pools[backend] = nnfw::cpp14::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 neurun
diff --git a/runtime/neurun/core/src/exec/ParallelScheduler.h b/runtime/neurun/core/src/exec/ParallelScheduler.h
new file mode 100644
index 000000000..af1103750
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_EXEC_PARALLEL_SCHEDULER_H__
+#define __NEURUN_EXEC_PARALLEL_SCHEDULER_H__
+
+#include <unordered_map>
+#include <memory>
+
+#include "exec/IFunction.h"
+#include "ir/BackendSet.h"
+#include "ThreadPool.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+class ParallelScheduler
+{
+public:
+ /**
+ * @brief Constructs ParallelScheduler object
+ *
+ * @param backends Backend set
+ */
+ ParallelScheduler(const ir::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 neurun
+
+#endif // __NEURUN_EXEC_PARALLEL_SCHEDULER_H__
diff --git a/runtime/neurun/core/src/exec/Sink.h b/runtime/neurun/core/src/exec/Sink.h
new file mode 100644
index 000000000..bb2a6c58a
--- /dev/null
+++ b/runtime/neurun/core/src/exec/Sink.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_EXEC_SINK_H__
+#define __NEURUN_EXEC_SINK_H__
+
+#include <cassert>
+
+#include "cpp14/memory.h"
+#include "util/feature/nchw/Reader.h"
+#include "util/feature/nchw/View.h"
+#include "util/feature/nhwc/Reader.h"
+#include "util/feature/nhwc/View.h"
+#include "util/Utils.h"
+#include <misc/feature/IndexIterator.h>
+
+namespace neurun
+{
+namespace exec
+{
+struct ISink
+{
+ virtual ~ISink() = default;
+
+ virtual void pull(::neurun::backend::operand::ITensor &tensor) const = 0;
+};
+
+// Create second lever inheritance: the first lever is used as a reference type in use-case places
+template <typename T> class ITemplSink : public ISink
+{
+public:
+ ITemplSink(void *output_buffer, const size_t &output_size, const ir::Shape &shape,
+ const bool copy, ir::Layout io_layout)
+ : _output_buffer{reinterpret_cast<T *>(output_buffer)}, _output_size{output_size},
+ _shape{shape}, _copy{copy}, _io_layout{io_layout}
+ {
+ }
+
+protected:
+ void pullUnif(neurun::backend::operand::ITensor &tensor) const
+ {
+ assert(((_io_layout == ir::Layout::NHWC && tensor.layout() == ir::Layout::NCHW) ||
+ (_io_layout == ir::Layout::NCHW && tensor.layout() == ir::Layout::NHWC)) ||
+ _copy);
+ auto input_buffer = tensor.buffer();
+ auto rank = _shape.rank();
+
+ if (!tensor.has_padding() && rank < 4 + _copy)
+ {
+ memcpy(_output_buffer, input_buffer, _output_size);
+ return;
+ }
+
+ switch (rank)
+ {
+ case 0:
+ case 1:
+ {
+ memcpy(_output_buffer, input_buffer, _output_size);
+ break;
+ }
+ case 2:
+ {
+ const int32_t copy_len = _shape.dim(1);
+
+ for (auto i = 0; i < _shape.dim(0); ++i)
+ {
+ neurun::util::Coordinates coords{i, 0};
+ memcpy(_output_buffer + i * copy_len, input_buffer + tensor.calcOffset(coords),
+ copy_len * sizeof(T));
+ }
+ break;
+ }
+ case 3:
+ {
+ const int32_t dim1 = _shape.dim(1);
+ const int32_t dim2 = _shape.dim(2);
+
+ for (auto i = 0; i < _shape.dim(0); ++i)
+ {
+ for (auto j = 0; j < _shape.dim(1); ++j)
+ {
+ neurun::util::Coordinates coords{i, j, 0};
+ memcpy(_output_buffer + i * dim1 * dim2 + j * dim2,
+ input_buffer + tensor.calcOffset(coords), dim2 * sizeof(T));
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ if (_copy)
+ {
+ const int32_t dim1 = _shape.dim(1);
+ const int32_t dim2 = _shape.dim(2);
+ const int32_t dim3 = _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)
+ {
+ neurun::util::Coordinates coords{i, j, k, 0};
+ memcpy(_output_buffer + i * dim1 * dim2 * dim3 + j * dim2 * dim3 + k * dim3,
+ input_buffer + tensor.calcOffset(coords), dim3 * sizeof(T));
+ }
+ }
+ }
+ }
+ else
+ {
+ const auto shape = _shape.asFeature(_io_layout);
+
+ if (_io_layout == ir::Layout::NHWC)
+ {
+ const util::feature::nchw::Reader<T> from(&tensor);
+ util::feature::nhwc::View<T> into(shape, _output_buffer, _output_size);
+ ::nnfw::misc::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;
+ };
+ }
+ else if (_io_layout == ir::Layout::NCHW)
+ {
+ const util::feature::nhwc::Reader<T> from(&tensor);
+ util::feature::nchw::View<T> into(shape, _output_buffer, _output_size);
+ ::nnfw::misc::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;
+ };
+ }
+ else
+ {
+ throw std::runtime_error("Wrong Layout");
+ }
+ }
+ break;
+ }
+ default:
+ throw std::runtime_error("NYI");
+ break;
+ }
+ }
+
+private:
+ T *_output_buffer;
+ const size_t _output_size;
+ const ir::Shape _shape;
+ const bool _copy;
+ const ir::Layout _io_layout;
+};
+
+template <typename T> class PermutateSink final : public ITemplSink<T>
+{
+public:
+ PermutateSink(void *output_buffer, const size_t &output_size, const ir::Shape &shape,
+ ir::Layout io_layout)
+ : ITemplSink<T>(output_buffer, output_size, shape, false, io_layout)
+ {
+ }
+
+public:
+ void pull(neurun::backend::operand::ITensor &tensor) const override
+ {
+ ITemplSink<T>::pullUnif(tensor);
+ }
+};
+
+// Only supports NHWC format front-end(NNAPI) now
+template <typename T> class CopySink final : public ITemplSink<T>
+{
+public:
+ CopySink(void *output_buffer, const size_t &output_size, const ir::Shape &shape,
+ ir::Layout io_layout = ir::Layout::UNKNOWN)
+ : ITemplSink<T>(output_buffer, output_size, shape, true, io_layout)
+ {
+ }
+
+public:
+ void pull(neurun::backend::operand::ITensor &tensor) const override
+ {
+ ITemplSink<T>::pullUnif(tensor);
+ }
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_SINK_H__
diff --git a/runtime/neurun/core/src/exec/Source.h b/runtime/neurun/core/src/exec/Source.h
new file mode 100644
index 000000000..fd52dd546
--- /dev/null
+++ b/runtime/neurun/core/src/exec/Source.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_EXEC_SOURCE_H__
+#define __NEURUN_EXEC_SOURCE_H__
+
+#include <cassert>
+
+#include "cpp14/memory.h"
+#include "util/feature/nchw/Reader.h"
+#include "util/feature/nchw/View.h"
+#include "util/feature/nhwc/Reader.h"
+#include "util/feature/nhwc/View.h"
+#include "util/Utils.h"
+#include <misc/feature/IndexIterator.h>
+#include <ir/Layout.h>
+#include "ir/Shape.h"
+
+namespace neurun
+{
+namespace exec
+{
+
+struct ISource
+{
+ virtual ~ISource() = default;
+
+ virtual void push(::neurun::backend::operand::ITensor &tensor) const = 0;
+};
+
+// Create second lever inheritance: the first lever is used as a reference type in use-case places
+template <typename T> class ITemplSource : public ISource
+{
+public:
+ ITemplSource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape,
+ const bool copy, ir::Layout io_layout)
+ : _input_buffer{reinterpret_cast<const T *>(input_buffer)}, _input_size{input_size},
+ _shape{shape}, _copy(copy), _io_layout{io_layout}
+ {
+ }
+
+ virtual void push(::neurun::backend::operand::ITensor &tensor) const = 0;
+
+protected:
+ void pushUnif(neurun::backend::operand::ITensor &tensor) const
+ {
+ assert(((_io_layout == ir::Layout::NHWC && tensor.layout() == ir::Layout::NCHW) ||
+ (_io_layout == ir::Layout::NCHW && tensor.layout() == ir::Layout::NHWC)) ||
+ _copy);
+ auto output_buffer = tensor.buffer();
+ auto rank = _shape.rank();
+
+ if (!tensor.has_padding() && rank < 4 + _copy)
+ {
+ memcpy(output_buffer, _input_buffer, _input_size);
+ return;
+ }
+
+ switch (rank)
+ {
+ case 0:
+ case 1:
+ {
+ memcpy(output_buffer, _input_buffer, _input_size);
+ break;
+ }
+ case 2:
+ {
+ const int32_t copy_len = _shape.dim(1);
+
+ for (auto i = 0; i < _shape.dim(0); ++i)
+ {
+ neurun::util::Coordinates coords{i, 0};
+ memcpy(output_buffer + tensor.calcOffset(coords), _input_buffer + i * copy_len,
+ copy_len * sizeof(T));
+ }
+ break;
+ }
+ case 3:
+ {
+ const int32_t dim1 = _shape.dim(1);
+ const int32_t dim2 = _shape.dim(2);
+
+ for (auto i = 0; i < _shape.dim(0); ++i)
+ {
+ for (auto j = 0; j < _shape.dim(1); ++j)
+ {
+ neurun::util::Coordinates coords{i, j, 0};
+ memcpy(output_buffer + tensor.calcOffset(coords),
+ _input_buffer + i * dim1 * dim2 + j * dim2, dim2 * sizeof(T));
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ if (_copy)
+ {
+ const int32_t dim1 = _shape.dim(1);
+ const int32_t dim2 = _shape.dim(2);
+ const int32_t dim3 = _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)
+ {
+ neurun::util::Coordinates coords{i, j, k, 0};
+ memcpy(output_buffer + tensor.calcOffset(coords),
+ _input_buffer + i * dim1 * dim2 * dim3 + j * dim2 * dim3 + k * dim3,
+ dim3 * sizeof(T));
+ }
+ }
+ }
+ }
+ else
+ {
+ const auto shape = _shape.asFeature(_io_layout);
+
+ if (_io_layout == ir::Layout::NCHW)
+ {
+ const util::feature::nchw::Reader<T> from(shape, _input_buffer, _input_size);
+ util::feature::nhwc::View<T> into(&tensor);
+ ::nnfw::misc::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;
+ };
+ }
+ else if (_io_layout == ir::Layout::NHWC)
+ {
+ const util::feature::nhwc::Reader<T> from(shape, _input_buffer, _input_size);
+ util::feature::nchw::View<T> into(&tensor);
+ ::nnfw::misc::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;
+ };
+ }
+ else
+ {
+ throw std::runtime_error("Wrong Layout");
+ }
+ }
+
+ break;
+ }
+ default:
+ throw std::runtime_error("NYI");
+ break;
+ }
+ }
+
+private:
+ const T *_input_buffer;
+ const size_t _input_size;
+ const ir::Shape _shape;
+ const bool _copy;
+ const ir::Layout _io_layout;
+};
+
+template <typename T> class PermutateSource final : public ITemplSource<T>
+{
+public:
+ PermutateSource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape,
+ ir::Layout io_layout)
+ : ITemplSource<T>(input_buffer, input_size, shape, false, io_layout)
+ {
+ }
+
+public:
+ void push(neurun::backend::operand::ITensor &tensor) const override
+ {
+ // do NHWC_TO_NCHW or NCHW_TO_NHWC permutation
+ ITemplSource<T>::pushUnif(tensor);
+ }
+};
+
+template <typename T> class CopySource final : public ITemplSource<T>
+{
+public:
+ CopySource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape,
+ ir::Layout io_layout = ir::Layout::UNKNOWN)
+ : ITemplSource<T>(input_buffer, input_size, shape, true, io_layout)
+ {
+ }
+
+public:
+ void push(neurun::backend::operand::ITensor &tensor) const override
+ {
+ ITemplSource<T>::pushUnif(tensor);
+ }
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_SOURCE_H__
diff --git a/runtime/neurun/core/src/exec/ThreadPool.cc b/runtime/neurun/core/src/exec/ThreadPool.cc
new file mode 100644
index 000000000..d8c706e30
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/exec/ThreadPool.h b/runtime/neurun/core/src/exec/ThreadPool.h
new file mode 100644
index 000000000..a1a027617
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_EXEC_THREAD_POOL_H__
+#define __NEURUN_EXEC_THREAD_POOL_H__
+
+#include <thread>
+#include <memory>
+#include <vector>
+
+#include "WorkQueue.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_EXEC_THREAD_POOL_H__
diff --git a/runtime/neurun/core/src/exec/WorkQueue.cc b/runtime/neurun/core/src/exec/WorkQueue.cc
new file mode 100644
index 000000000..6712554ac
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/exec/WorkQueue.h b/runtime/neurun/core/src/exec/WorkQueue.h
new file mode 100644
index 000000000..cdbadfb8f
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_EXEC_WORK_QUEUE_H__
+#define __NEURUN_EXEC_WORK_QUEUE_H__
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+
+#include "exec/IFunction.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_EXEC_WORK_QUEUE_H__
diff --git a/runtime/neurun/core/src/exec/interp/Buffer.h b/runtime/neurun/core/src/exec/interp/Buffer.h
new file mode 100644
index 000000000..d60b59a2f
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/Buffer.h
@@ -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.
+ */
+
+/**
+ * @file Buffer.h
+ * @brief This file contains Buffer interface and InternalBuffer, ExternalBuffer class
+ */
+#ifndef __NEURUN_EXEC_INTERP_BUFFER_H__
+#define __NEURUN_EXEC_INTERP_BUFFER_H__
+
+#include <cpp14/memory.h>
+
+#include "ir/Data.h"
+
+namespace neurun
+{
+namespace exec
+{
+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{nnfw::cpp14::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 exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_INTERP_BUFFER_H__
diff --git a/runtime/neurun/core/src/exec/interp/ExecEnv.h b/runtime/neurun/core/src/exec/interp/ExecEnv.h
new file mode 100644
index 000000000..0f7d45e2a
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/ExecEnv.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __NEURUN_EXEC_INTERP_EXEC_ENV_H_
+#define __NEURUN_EXEC_INTERP_EXEC_ENV_H_
+
+#include <unordered_set>
+
+#include "ir/Graph.h"
+#include "Tensor.h"
+
+namespace neurun
+{
+namespace exec
+{
+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
+ * @return Tensor pointer
+ */
+ const ITensor *tensorAt(const ir::OperandIndex index) const { 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;
+ }
+
+ auto tensor = std::make_shared<Tensor>(info);
+ 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;
+ }
+ 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();
+ }
+ }
+
+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;
+};
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_INTERP_EXEC_ENV_H_
diff --git a/runtime/neurun/core/src/exec/interp/ExecManager.cc b/runtime/neurun/core/src/exec/interp/ExecManager.cc
new file mode 100644
index 000000000..92f182c06
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/ExecManager.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExecManager.h"
+#include "ExecEnv.h"
+#include "Interpreter.h"
+
+#include "util/logging.h"
+
+#include <cpp14/memory.h>
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+
+void ExecManager::execute(const 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);
+
+ 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;
+ }
+
+ 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);
+
+ auto output_tensor = std::make_shared<Tensor>(output.info);
+ output_tensor->setBuffer(
+ std::make_shared<ExternalBuffer>(reinterpret_cast<uint8_t *>(output.buffer), output.size));
+ tensor_map[output_index] = output_tensor;
+ }
+
+ /************************************************************************
+ * Prepare execution environment
+ Execution environment will be assigned to invoked interpreter instance
+ ***********************************************************************/
+
+ std::unique_ptr<ExecEnv> interp_env = nnfw::cpp14::make_unique<ExecEnv>(_graph);
+
+ // Assign input 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));
+ }
+ }
+
+ // Assign output tensor into interpreter execution environment
+ for (auto index : _graph.getOutputs())
+ {
+ if (tensor_map.find(index) != tensor_map.end())
+ {
+ VERBOSE(INTERPRETER) << "Assign output tensor. operand index: " << index.value() << std::endl;
+ interp_env->assignTensor(index, tensor_map.at(index));
+ }
+ }
+
+ // 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;
+
+ 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
+ ****************************************************************************/
+
+ 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 exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/ExecManager.h b/runtime/neurun/core/src/exec/interp/ExecManager.h
new file mode 100644
index 000000000..f952abf02
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/ExecManager.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.
+ */
+
+/**
+ * @file ExecManager.h
+ * @brief This file contains ExecManager class\n
+ * to manage interpreter execution and environment
+ */
+#ifndef __NEURUN_EXEC_INTERP_EXEC_MANAGER_H_
+#define __NEURUN_EXEC_INTERP_EXEC_MANAGER_H_
+
+#include "ir/Graph.h"
+#include "exec/IExecutor.h"
+#include "Tensor.h"
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+
+/**
+ * @brief Class to execute model using interpreter
+ */
+class ExecManager final : public IExecutor
+{
+public:
+ explicit ExecManager(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 IODescription &desc) final;
+
+private:
+ const ir::Graph &_graph;
+ ir::OperandIndexMap<std::shared_ptr<ITensor>> _tensor_map;
+};
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_INTERP_EXEC_MANAGER_H_
diff --git a/runtime/neurun/core/src/exec/interp/Interpreter.cc b/runtime/neurun/core/src/exec/interp/Interpreter.cc
new file mode 100644
index 000000000..8373419f6
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/Interpreter.cc
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 neurun
+{
+namespace exec
+{
+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 : ir::OperationVisitor
+{
+public:
+ OperationExecutor(ExecEnv *env) : _env{env}
+ {
+ _kernels[ir::OpCode::Add] = getAdd();
+ _kernels[ir::OpCode::Sub] = getSub();
+ _kernels[ir::OpCode::Mul] = getMul();
+ _kernels[ir::OpCode::Conv2D] = getConv2D();
+ _kernels[ir::OpCode::MaxPool2D] = getMaxPool2D();
+ _kernels[ir::OpCode::Concat] = getConcat();
+ _kernels[ir::OpCode::Gather] = getGather();
+ _kernels[ir::OpCode::AvgPool2D] = getAvgPool2D();
+ _kernels[ir::OpCode::FullyConnected] = getFullyConnected();
+ _kernels[ir::OpCode::InstanceNorm] = getInstanceNorm();
+ _kernels[ir::OpCode::Softmax] = getSoftMax();
+ _kernels[ir::OpCode::Reshape] = getReshape();
+ _kernels[ir::OpCode::DepthwiseConv2D] = getDepthwiseConv();
+ _kernels[ir::OpCode::TransposeConv] = getTransposeConv();
+ _kernels[ir::OpCode::Logistic] = getLogistic();
+ _kernels[ir::OpCode::Pad] = getPad();
+ _kernels[ir::OpCode::ReLU] = getReLU();
+ _kernels[ir::OpCode::ReLU1] = getReLU1();
+ _kernels[ir::OpCode::ReLU6] = getReLU6();
+ _kernels[ir::OpCode::Tanh] = getTanh();
+ }
+
+ void execute(const ir::OperationIndex &idx)
+ {
+ const auto nodeName = _env->graph().operations().at(idx).name();
+ VERBOSE(INTERPRETER) << "Prepare output operands and execute " << nodeName
+ << " operation (id: " << idx.value() << ")" << std::endl;
+ _env->graph().operations().at(idx).accept(*this);
+ }
+
+private:
+#define OP(InternalName) \
+ void visit(const ir::operation::InternalName &node) override \
+ { \
+ if (_kernels[ir::OpCode::InternalName]->prepare != nullptr) \
+ { \
+ _kernels[ir::OpCode::InternalName]->prepare(_env, node); \
+ } \
+ _kernels[ir::OpCode::InternalName]->invoke(_env, node); \
+ }
+#include "ir/Operations.lst"
+#undef OP
+
+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;
+ auto use_operators = std::list<ir::OperationIndex>(
+ _env->graph().operands().at(current_operand_index).getUses().list());
+ // Remove operation index duplication
+ // If one operation uses same operand tensor for multiple input,
+ // use-list have duplicated operation index
+ use_operators.unique();
+ for (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 (auto use_operator : use_operators.list())
+ {
+ if (executed.find(use_operator) == executed.end())
+ {
+ dead_buffer = false;
+ break;
+ }
+ }
+
+ if (dead_buffer)
+ {
+ _env->freeIfAllocated(input_index);
+ }
+ }
+ }
+ }
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/Interpreter.h b/runtime/neurun/core/src/exec/interp/Interpreter.h
new file mode 100644
index 000000000..1b73592b3
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/Interpreter.h
@@ -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.
+ */
+
+/**
+ * @file Interpreter.h
+ * @brief This file contains Interpreter class for interpretation
+ */
+#ifndef __NEURUN_EXEC_INTERP_INTERPRETER_H__
+#define __NEURUN_EXEC_INTERP_INTERPRETER_H__
+
+#include "ExecEnv.h"
+
+namespace neurun
+{
+namespace exec
+{
+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 exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_INTERP_INTERPRETER_H__
diff --git a/runtime/neurun/core/src/exec/interp/Registration.h b/runtime/neurun/core/src/exec/interp/Registration.h
new file mode 100644
index 000000000..3ebe3bc9f
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/Registration.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 __NEURUN_EXEC_INTERP_REGISTRATION_H__
+#define __NEURUN_EXEC_INTERP_REGISTRATION_H__
+
+#include "ExecEnv.h"
+
+#include "ir/Operation.h"
+
+namespace neurun
+{
+namespace exec
+{
+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
+OpKernel *getAdd();
+OpKernel *getSub();
+OpKernel *getMul();
+OpKernel *getConv2D();
+OpKernel *getMaxPool2D();
+OpKernel *getConcat();
+OpKernel *getGather();
+OpKernel *getAvgPool2D();
+OpKernel *getFullyConnected();
+OpKernel *getInstanceNorm();
+OpKernel *getSoftMax();
+OpKernel *getDepthwiseConv();
+OpKernel *getReshape();
+OpKernel *getTransposeConv();
+OpKernel *getLogistic();
+OpKernel *getPad();
+OpKernel *getReLU();
+OpKernel *getReLU1();
+OpKernel *getReLU6();
+OpKernel *getTanh();
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_INTERP_REGISTRATION_H__
diff --git a/runtime/neurun/core/src/exec/interp/Tensor.cc b/runtime/neurun/core/src/exec/interp/Tensor.cc
new file mode 100644
index 000000000..5c1da3587
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/Tensor.cc
@@ -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.
+ */
+
+#include "Tensor.h"
+
+#define NO_USE(a) (void)(a)
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+
+void ITensor::access(const std::function<void(backend::operand::ITensor &tensor)> &fn)
+{
+ fn(*this);
+}
+
+size_t ROTensor::calcOffset(const neurun::util::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 neurun::util::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 exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/Tensor.h b/runtime/neurun/core/src/exec/interp/Tensor.h
new file mode 100644
index 000000000..c53fd46a6
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/Tensor.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __NEURUN_EXEC_INTERP_TENSOR_H__
+#define __NEURUN_EXEC_INTERP_TENSOR_H__
+
+#include "Buffer.h"
+
+#include "ir/OperandInfo.h"
+#include "backend/operand/ITensor.h"
+#include "ir/Layout.h"
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+
+/**
+ * @brief Interface to handle Tensor in interpreter
+ */
+class ITensor : public backend::operand::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 util::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::operand::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 util::Coordinates &coords) const override;
+ ir::Layout layout() const override;
+ bool has_padding() const override { return false; }
+ ir::DataType data_type() const override { return _info.typeInfo().type(); }
+ 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 util::Coordinates &coords) const override;
+ ir::Layout layout() const override;
+ bool has_padding() const override { return false; }
+ ir::DataType data_type() const override { return _info.typeInfo().type(); }
+ 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 exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_INTERP_TENSOR_H__
diff --git a/runtime/neurun/core/src/exec/interp/operations/AvgPool2D.cc b/runtime/neurun/core/src/exec/interp/operations/AvgPool2D.cc
new file mode 100644
index 000000000..bd396491f
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/AvgPool2D.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "OperationUtil.h"
+
+#include "exec/interp/Registration.h"
+#include "ir/operation/AvgPool2D.h"
+#include "util/Utils.h"
+#include "util/Padding.h"
+#include "util/ShapeInference.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+namespace avgpool2d
+{
+
+void prepareAvgPool2D(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);
+
+ const auto output_info = env->graph().operands().at(out_index).info();
+ if (output_info.total_size() == 0)
+ {
+ // Handle unspecified output shape
+ const auto &avgpool_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::AvgPool2D &>(node);
+ const auto infered_output_shapes =
+ shape_inference::inferAvgPoolShape(in_tensor->tensorInfo().shape(), avgpool_node.param());
+ env->allocateIfNeeded(out_index, {infered_output_shapes[0], 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 *in_tensor, const ITensor *out_tensor,
+ const ir::operation::AvgPool2D::Param &param)
+{
+ // 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 padding = neurun::util::calculatePadding(param.padding, ifm_shape, ofm_shape,
+ param.stride, param.kw, param.kh);
+ // Calculate
+ nnfw::cker::PoolParams cker_param;
+ calculateActivationRange(param.activation, &cker_param.float_activation_min,
+ &cker_param.float_activation_max);
+ 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 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());
+
+ nnfw::cker::AveragePool(cker_param, in_shape, in_ptr, out_shape, out_ptr);
+}
+
+void invokeAvgPool2D(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &avgpool_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::AvgPool2D &>(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);
+
+ const auto data_type = in_tensor->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(in_tensor, out_tensor, avgpool_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Support float only"};
+ }
+}
+} // namespace avgpool2d
+
+OpKernel *getAvgPool2D()
+{
+ static OpKernel kernel = {avgpool2d::prepareAvgPool2D, avgpool2d::invokeAvgPool2D};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/BinaryArithmeticOps.cc b/runtime/neurun/core/src/exec/interp/operations/BinaryArithmeticOps.cc
new file mode 100644
index 000000000..16469b9db
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/BinaryArithmeticOps.cc
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "exec/interp/Registration.h"
+#include "ir/operation/Add.h"
+#include "ir/operation/Sub.h"
+#include "ir/operation/Mul.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+namespace
+{
+
+enum class OpType
+{
+ ADD,
+ SUB,
+ MUL
+};
+
+template <typename node_type> void prepareAdd(ExecEnv *env, const ir::Operation &node)
+{
+ const auto &add_node = nnfw::misc::polymorphic_downcast<const node_type &>(node);
+
+ const auto lhs_index = node.getInputs().at(add_node.LHS);
+ const auto rhs_index = node.getInputs().at(add_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(Add): 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(Add): Fail to brodcasting"};
+ }
+
+ auto output_info = ir::OperandInfo(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(Add): 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, typename param_type, OpType op_type>
+void invoke(const ITensor *lhs_tensor, const ITensor *rhs_tensor, const ITensor *out_tensor,
+ const param_type &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);
+
+ // Calculate
+ const std::function<raw_type(const raw_type &, const raw_type &)> fn_add =
+ [](const raw_type &a, const raw_type &b) { return a + b; };
+ const std::function<raw_type(const raw_type &, const raw_type &)> fn_sub =
+ [](const raw_type &a, const raw_type &b) { return a - b; };
+ const std::function<raw_type(const raw_type &, const raw_type &)> fn_mul =
+ [](const raw_type &a, const raw_type &b) { return a * b; };
+
+ const std::function<raw_type(const raw_type &, const raw_type &)> fn =
+ (op_type == OpType::ADD) ? fn_add : ((op_type == OpType::SUB) ? fn_sub : fn_mul);
+
+ if (lhs_tensor->tensorInfo().shape() != rhs_tensor->tensorInfo().shape())
+ {
+ const auto lhs_shape = convertExtendShape(lhs_tensor->tensorInfo().shape());
+ const auto rhs_shape = convertExtendShape(rhs_tensor->tensorInfo().shape());
+ const auto out_shape = convertExtendShape(out_tensor->tensorInfo().shape());
+ nnfw::cker::BroadcastBinaryArithmeticOpSlow(cker_param, lhs_shape, lhs_ptr, rhs_shape, rhs_ptr,
+ out_shape, out_ptr, fn);
+ 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_param, lhs_shape, lhs_ptr, rhs_shape, rhs_ptr, out_shape,
+ out_ptr, fn);
+}
+
+template <typename node_type, typename param_type, OpType op_type>
+void invokeAdd(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &arithmetic_node = nnfw::misc::polymorphic_downcast<const node_type &>(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);
+ 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, param_type, op_type>(lhs_tensor, rhs_tensor, out_tensor,
+ arithmetic_node.param());
+ }
+ else if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke<float, param_type, op_type>(lhs_tensor, rhs_tensor, out_tensor, arithmetic_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Unsupported data type"};
+ }
+}
+} // namespace add
+
+OpKernel *getAdd()
+{
+ static OpKernel kernel = {prepareAdd<ir::operation::Add>,
+ invokeAdd<ir::operation::Add, ir::operation::Add::Param, OpType::ADD>};
+ return &kernel;
+}
+
+OpKernel *getSub()
+{
+ static OpKernel kernel = {prepareAdd<ir::operation::Sub>,
+ invokeAdd<ir::operation::Sub, ir::operation::Sub::Param, OpType::SUB>};
+ return &kernel;
+}
+
+OpKernel *getMul()
+{
+ static OpKernel kernel = {prepareAdd<ir::operation::Mul>,
+ invokeAdd<ir::operation::Mul, ir::operation::Mul::Param, OpType::MUL>};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/Concat.cc b/runtime/neurun/core/src/exec/interp/operations/Concat.cc
new file mode 100644
index 000000000..a127e5f30
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/Concat.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "exec/interp/Registration.h"
+#include "ir/operation/Concat.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+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{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 exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/Conv2D.cc b/runtime/neurun/core/src/exec/interp/operations/Conv2D.cc
new file mode 100644
index 000000000..5242247a4
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/Conv2D.cc
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "exec/interp/Registration.h"
+#include "ir/operation/Conv2D.h"
+#include "util/Utils.h"
+#include "util/Padding.h"
+#include "util/ShapeInference.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+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_shapes = shape_inference::inferConv2DShape(
+ in_tensor->tensorInfo().shape(), kernel_tensor->tensorInfo().shape(), conv_node.param());
+ env->allocateIfNeeded(out_index, {infered_output_shapes[0], 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 = neurun::util::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_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(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 exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/DepthwiseConv.cc b/runtime/neurun/core/src/exec/interp/operations/DepthwiseConv.cc
new file mode 100644
index 000000000..1d3649f48
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/DepthwiseConv.cc
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "exec/interp/Registration.h"
+#include "ir/operation/DepthwiseConv2D.h"
+#include "util/Padding.h"
+#include "util/Utils.h"
+#include "util/ShapeInference.h"
+
+namespace neurun
+{
+namespace exec
+{
+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_shapes = shape_inference::inferDepthwiseConv2DShape(
+ in_tensor->tensorInfo().shape(), kernel_tensor->tensorInfo().shape(),
+ depth_conv_node.param());
+ env->allocateIfNeeded(out_index, {infered_output_shapes[0], 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 = neurun::util::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 *getDepthwiseConv()
+{
+ static OpKernel kernel = {prepareDepthwiseConv, invokeDepthwiseConv};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/FullyConnected.cc b/runtime/neurun/core/src/exec/interp/operations/FullyConnected.cc
new file mode 100644
index 000000000..9c1c5d4e2
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/FullyConnected.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 <cker/operation/FullyConnected.h>
+
+#include "OperationUtil.h"
+
+#include "exec/interp/Registration.h"
+#include "ir/operation/FullyConnected.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+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 ir::OperandInfo out_info{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;
+ calculateActivationRange(param.activation, &cker_param.float_activation_min,
+ &cker_param.float_activation_max);
+ const auto cker_ifm_shape = convertExtendShape(ifm_tensor->tensorInfo().shape());
+ const auto cker_ker_shape = convertExtendShape(ker_tensor->tensorInfo().shape());
+ const auto cker_bias_shape = convertExtendShape(bias_tensor->tensorInfo().shape());
+ const auto cker_ofm_shape = convertExtendShape(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 exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/Gather.cc b/runtime/neurun/core/src/exec/interp/operations/Gather.cc
new file mode 100644
index 000000000..8b64d1937
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/Gather.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/Gather.h>
+
+#include "OperationUtil.h"
+
+#include "exec/interp/Registration.h"
+#include "ir/operation/Gather.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+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::QUANT8_ASYMM &&
+ input_tensor->tensorInfo().typeInfo() != output_tensor->tensorInfo().typeInfo())
+ {
+ throw std::runtime_error{
+ "Interp(Gather): Cannot handle different I/O QUANT8_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::QUANT8_ASYMM:
+ invoke<uint8_t>(input_tensor, indices_tensor, output_tensor, axis);
+ break;
+ default:
+ throw std::runtime_error{"Interp(Gather): NYI - Not supported type"};
+ }
+}
+
+} // namespace concat
+
+OpKernel *getGather()
+{
+ static OpKernel kernel = {prepareGather, invokeGather};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/InstanceNorm.cc b/runtime/neurun/core/src/exec/interp/operations/InstanceNorm.cc
new file mode 100644
index 000000000..d1623d53c
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/InstanceNorm.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "exec/interp/Registration.h"
+#include "ir/operation/InstanceNorm.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+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 exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/Logistic.cc b/runtime/neurun/core/src/exec/interp/operations/Logistic.cc
new file mode 100644
index 000000000..2fc68ffd2
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/Logistic.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cker/operation/Logistic.h>
+
+#include "OperationUtil.h"
+
+#include "exec/interp/Registration.h"
+#include "ir/operation/Logistic.h"
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+namespace
+{
+
+void prepareLogistic(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();
+
+ // 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(TConv): 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(Logistic): Invalid output type"};
+ }
+}
+
+void invoke(const ITensor *input_tensor, const ITensor *output_tensor)
+{
+ const auto input_buffer = input_tensor->bufferRO();
+ auto output_buffer = output_tensor->buffer();
+
+ 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);
+ float *output_ptr = reinterpret_cast<float *>(output_buffer);
+
+ nnfw::cker::Logistic(cker_input_shape, input_ptr, cker_output_shape, output_ptr);
+}
+
+void invokeLogistic(const 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_tensor = env->tensorAt(output_index);
+
+ const auto data_type = input_tensor->data_type();
+
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(input_tensor, output_tensor);
+ }
+ else
+ {
+ throw std::runtime_error{"Interp(Logistic): NYI - Unsupported data type"};
+ }
+}
+} // namespace
+
+OpKernel *getLogistic()
+{
+ static OpKernel kernel = {prepareLogistic, invokeLogistic};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/MaxPool2D.cc b/runtime/neurun/core/src/exec/interp/operations/MaxPool2D.cc
new file mode 100644
index 000000000..3e1711d8e
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/MaxPool2D.cc
@@ -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.
+ */
+
+#include <cker/operation/MaxPool.h>
+
+#include "OperationUtil.h"
+
+#include "exec/interp/Registration.h"
+#include "ir/operation/MaxPool2D.h"
+#include "util/Utils.h"
+#include "util/Padding.h"
+#include "util/ShapeInference.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+namespace
+{
+
+void prepareMaxPool2D(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);
+
+ assert(in_tensor->num_dimensions() == 4);
+ UNUSED_RELEASE(in_tensor);
+
+ const auto output_info = env->graph().operands().at(out_index).info();
+ if (output_info.total_size() == 0)
+ {
+ // Handle unspecified output shape
+ const auto &maxpool_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::MaxPool2D &>(node);
+ const auto infered_output_shapes =
+ shape_inference::inferMaxPoolShape(in_tensor->tensorInfo().shape(), maxpool_node.param());
+ env->allocateIfNeeded(out_index, {infered_output_shapes[0], 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 *in_tensor, const ITensor *out_tensor,
+ const ir::operation::MaxPool2D::Param &param)
+{
+ // 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 padding = neurun::util::calculatePadding(param.padding, ifm_shape, ofm_shape,
+ param.stride, param.kw, param.kh);
+ // Calculate
+ nnfw::cker::PoolParams cker_param;
+ calculateActivationRange(param.activation, &cker_param.float_activation_min,
+ &cker_param.float_activation_max);
+ 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 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());
+
+ nnfw::cker::MaxPool(cker_param, in_shape, in_ptr, out_shape, out_ptr);
+}
+
+void invokeMaxPool2D(const ExecEnv *env, const ir::Operation &node)
+{
+ const auto &maxpool_node =
+ nnfw::misc::polymorphic_downcast<const ir::operation::MaxPool2D &>(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 data_type = in_tensor->data_type();
+ if (data_type == ir::DataType::FLOAT32)
+ {
+ invoke(in_tensor, out_tensor, maxpool_node.param());
+ }
+ else
+ {
+ throw std::runtime_error{"NYI: Support float32 only"};
+ }
+}
+} // namespace
+
+OpKernel *getMaxPool2D()
+{
+ static OpKernel kernel = {prepareMaxPool2D, invokeMaxPool2D};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/OperationUtil.h b/runtime/neurun/core/src/exec/interp/operations/OperationUtil.h
new file mode 100644
index 000000000..5f4146bb8
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/OperationUtil.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_EXEC_INTERP_OPERATIONS_OPERATION_UTILS_H_
+#define __NEURUN_EXEC_INTERP_OPERATIONS_OPERATION_UTILS_H_
+
+#include "ir/Shape.h"
+#include "ir/InternalType.h"
+
+#include <cker/Shape.h>
+
+namespace neurun
+{
+namespace exec
+{
+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(4);
+
+ for (uint32_t i = 0; i < 4; ++i)
+ {
+ if (i >= dimensions.size())
+ {
+ raw_shape[i] = 1;
+ }
+ else
+ {
+ 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());
+
+ std::vector<int32_t> raw_shape;
+ raw_shape.resize(4);
+ uint32_t start = 4 - dimensions.size();
+
+ for (uint32_t i = 0; i < 4; ++i)
+ {
+ if (i < start)
+ {
+ raw_shape[i] = 1;
+ }
+ else
+ {
+ raw_shape[i] = dimensions[i - start];
+ }
+ }
+
+ return nnfw::cker::GetShape(raw_shape);
+}
+
+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;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_INTERP_OPERATIONS_OPERATION_UTILS_H_
diff --git a/runtime/neurun/core/src/exec/interp/operations/Pad.cc b/runtime/neurun/core/src/exec/interp/operations/Pad.cc
new file mode 100644
index 000000000..0c8267a90
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/Pad.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 <cker/operation/Pad.h>
+
+#include "OperationUtil.h"
+
+#include "exec/interp/Registration.h"
+#include "ir/operation/Pad.h"
+
+namespace neurun
+{
+namespace exec
+{
+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(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 exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/Reshape.cc b/runtime/neurun/core/src/exec/interp/operations/Reshape.cc
new file mode 100644
index 000000000..a160232de
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/Reshape.cc
@@ -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.
+ */
+
+#include "exec/interp/Registration.h"
+
+namespace neurun
+{
+namespace exec
+{
+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 {anonymous}
+
+OpKernel *getReshape()
+{
+ static OpKernel kernel = {prepare, invoke};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/SoftMax.cc b/runtime/neurun/core/src/exec/interp/operations/SoftMax.cc
new file mode 100644
index 000000000..91d98889f
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/SoftMax.cc
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "exec/interp/Registration.h"
+#include "ir/operation/Softmax.h"
+#include "misc/polymorphic_downcast.h"
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+namespace
+{
+
+void Softmax2D(const float *in, const int input_size, const int batch_size, const float beta,
+ float *out)
+{
+ assert(input_size > 0);
+
+ // For each batch
+ for (int b = 0; b < batch_size; b++)
+ {
+ // Find the max coeff.
+ float max_coeff = in[0];
+ for (int i = 1; i < input_size; i++)
+ {
+ if (in[i] > max_coeff)
+ max_coeff = in[i];
+ }
+
+ // Compute the normalized sum of exps.
+ float exp_sum = 0.0;
+ for (int i = 0; i < input_size; i++)
+ {
+ out[i] = std::exp((in[i] - max_coeff) * beta);
+ exp_sum += out[i];
+ }
+
+ // Divide by the sum of exps.
+ float reciprocal_sum_exp = 1.f / exp_sum;
+ for (int i = 0; i < input_size; i++)
+ {
+ out[i] *= reciprocal_sum_exp;
+ }
+
+ // Advance in and out pointers for the next batch.
+ in += input_size;
+ out += input_size;
+ }
+}
+
+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 ir::OperandInfo output_info{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);
+
+ Softmax2D(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 exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/TransposeConv.cc b/runtime/neurun/core/src/exec/interp/operations/TransposeConv.cc
new file mode 100644
index 000000000..70b72c88d
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/TransposeConv.cc
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "exec/interp/Registration.h"
+#include "ir/operation/TransposeConv.h"
+#include "util/Padding.h"
+
+namespace neurun
+{
+namespace exec
+{
+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 = neurun::util::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 transposeconv
+
+OpKernel *getTransposeConv()
+{
+ static OpKernel kernel = {prepareTransposeConv, invokeTransposeConv};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/exec/interp/operations/UnaryActivations.cc b/runtime/neurun/core/src/exec/interp/operations/UnaryActivations.cc
new file mode 100644
index 000000000..116806fc4
--- /dev/null
+++ b/runtime/neurun/core/src/exec/interp/operations/UnaryActivations.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "exec/interp/Registration.h"
+
+#include "ir/operation/ReLU.h"
+#include "ir/operation/ReLU1.h"
+#include "ir/operation/ReLU6.h"
+#include "ir/operation/Tanh.h"
+
+namespace neurun
+{
+namespace exec
+{
+namespace interp
+{
+namespace
+{
+
+enum class ActivationType
+{
+ ReLU,
+ ReLU1,
+ ReLU6,
+ 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(Activations): Invalid output type"};
+ }
+}
+
+template <ActivationType act_type>
+void evalFloat(const float *input_ptr, float *output_ptr, uint64_t num_elements)
+{
+ std::function<float(const float &)> fn = [](const float &) { return std::nanf(""); };
+ switch (act_type)
+ {
+ case ActivationType::ReLU:
+ fn = [](const float &in) { return std::max(0.f, in); };
+ break;
+ case ActivationType::ReLU1:
+ fn = [](const float &in) { return std::min(std::max(-1.f, in), 1.f); };
+ break;
+ case ActivationType::ReLU6:
+ fn = [](const float &in) { return std::min(std::max(0.f, in), 6.f); };
+ break;
+ case ActivationType::Tanh:
+ fn = [](const float &in) { return std::tanh(in); };
+ break;
+ default:
+ throw std::runtime_error{"Interp(Activations): 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());
+
+ evalFloat<act_type>(input_start, out, elements);
+ }
+ else
+ {
+ throw std::runtime_error{"Interp(ReLU6): NYI - Support float only"};
+ }
+}
+
+} // namespace
+
+OpKernel *getReLU()
+{
+ static OpKernel kernel = {prepare, invoke<ActivationType::ReLU>};
+ return &kernel;
+}
+
+OpKernel *getReLU1()
+{
+ static OpKernel kernel = {prepare, invoke<ActivationType::ReLU1>};
+ return &kernel;
+}
+
+OpKernel *getReLU6()
+{
+ static OpKernel kernel = {prepare, invoke<ActivationType::ReLU6>};
+ return &kernel;
+}
+
+OpKernel *getTanh()
+{
+ static OpKernel kernel = {prepare, invoke<ActivationType::Tanh>};
+ return &kernel;
+}
+
+} // namespace interp
+} // namespace exec
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/Graph.cc b/runtime/neurun/core/src/ir/Graph.cc
new file mode 100644
index 000000000..a84ebb68b
--- /dev/null
+++ b/runtime/neurun/core/src/ir/Graph.cc
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <algorithm>
+#include <bitset>
+#include <sstream>
+
+#include "util/logging.h"
+#include "verifier/Verifier.h"
+#include "cpp14/memory.h"
+#include "ir/operation/LowerInfo.h"
+#include "ir/operand/LowerInfo.h"
+#include "ir/operand/PermuteFactor.h"
+#include "ir/GraphIterator.h"
+#include "operand/Shape4DConvert.h"
+#include "compiler/BackendResolver.h"
+#include "backend/IConfig.h"
+#include "pass/ConstantInsertionPass.h"
+#include "pass/PermutationInsertionPass.h"
+#include "pass/PermutationEliminationPass.h"
+#include "pass/PermutationOperationPass.h"
+
+namespace neurun
+{
+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::unique_ptr<Data> &&data)
+{
+ assert(isBuildingPhase());
+ assert(_operands.exist(ind));
+ _operands.at(ind).data(std::move(data));
+}
+
+void Graph::addInput(const OperandIndex &ind)
+{
+ assert(isBuildingPhase());
+ _inputs.append(ind);
+}
+
+void Graph::addOutput(const OperandIndex &ind)
+{
+ assert(isBuildingPhase());
+ _outputs.append(ind);
+}
+
+void Graph::finishBuilding(void)
+{
+ assert(isBuildingPhase());
+ _phase = Phase::MODEL;
+
+ // Initialize operand use-def
+ initializeUseDef();
+
+ // Call graph verifications for the MODEL phase
+ {
+ assert(verifier::DAGChecker().verify(*this));
+ assert(verifier::EdgeConsistencyChecker().verify(*this));
+ }
+}
+
+void Graph::lower(void)
+{
+ assert(_phase == Phase::MODEL);
+
+ _op_seqs = nnfw::cpp14::make_unique<Subgraphs>();
+
+ // Lower
+ {
+ // operand::LowerInfo holder
+ OperandIndexMap<std::unique_ptr<operand::LowerInfo>> operands_lower_info;
+
+ _operands.iterate([&](const OperandIndex &index, const Operand &object) {
+ operands_lower_info[index] =
+ nnfw::cpp14::make_unique<operand::LowerInfo>(operand::asShape4D(object.shape()));
+ });
+
+ _lower_info_map = nnfw::cpp14::make_unique<LowerInfoMap>();
+
+ // Make subgraphs while checking whether a node can be merged into a op_seq.
+ makeSubgraphs(operands_lower_info);
+
+ _op_seqs->iterate([&](const SubgraphIndex &, OpSequence &subg) {
+ assert(subg.operations().size() > 0);
+ std::reverse(std::begin(subg.operations()), std::end(subg.operations()));
+ });
+
+ _op_seqs->dump("merged and sorted operations without permutation");
+
+ pass::ConstantInsertionPass ci_pass(*this);
+ ci_pass.run();
+
+ // Set LowerInfo for each operand from the operand::LowerInfo holder
+ manipulateLowerInfo(operands_lower_info);
+
+ dumpLowerInfo();
+ }
+
+ // Run Permutation Passes
+ {
+ pass::PermutationOperationPass po_pass(*this);
+ po_pass.run();
+
+ pass::PermutationInsertionPass pi_pass(*this);
+ pi_pass.run();
+ // Implemented code no longer works.
+ // pass::PermutationEliminationPass pe_pass(*this);
+ // pe_pass.run();
+
+ // TODO merge perm subgraphs if possible
+ _op_seqs->dump("merged and sorted operations with permutation");
+ }
+
+ // Graph verifications for the LOWERED phase
+ {
+ assert(verifier::DAGChecker().verify(*this));
+ assert(verifier::EdgeConsistencyChecker().verify(*this));
+ }
+}
+
+void Graph::initializeUseDef()
+{
+ operations().iterate([&](const OperationIndex &index, const Operation &node) -> void {
+ auto outputs = node.getOutputs();
+ for (auto output : outputs)
+ {
+ operands().at(output).appendDef(index);
+ }
+
+ auto inputs = node.getInputs();
+ for (auto input : inputs)
+ {
+ operands().at(input).appendUse(index);
+ }
+ });
+}
+
+const operation::LowerInfo *Graph::getLowerInfo(const SubgraphIndex &subg_index) const
+{
+ if (!_lower_info_map)
+ return nullptr;
+ auto itr = _lower_info_map->operation.find(subg_index);
+ if (itr == _lower_info_map->operation.end())
+ return nullptr;
+ return itr->second.get();
+}
+
+void Graph::setLowerInfo(const SubgraphIndex &subg_index,
+ std::unique_ptr<operation::LowerInfo> &&lower_info)
+{
+ assert(_lower_info_map);
+ _lower_info_map->operation.insert(std::make_pair(subg_index, std::move(lower_info)));
+}
+
+void Graph::removeLowerInfo(const SubgraphIndex &subg_index)
+{
+ auto &subg_lower_info = _lower_info_map->operation;
+ assert(subg_lower_info.find(subg_index) != subg_lower_info.end());
+ for (auto it = subg_lower_info.begin(); it != subg_lower_info.end(); ++it)
+ {
+ if (it->first == subg_index)
+ {
+ subg_lower_info.erase(it);
+ break;
+ }
+ }
+}
+
+const operand::LowerInfo *Graph::getLowerInfo(const OperandIndex &index) const
+{
+ if (!_lower_info_map)
+ return nullptr;
+ auto itr = _lower_info_map->operand.find(index);
+ if (itr == _lower_info_map->operand.end())
+ return nullptr;
+ return itr->second.get();
+}
+
+operand::LowerInfo *Graph::getLowerInfo(const OperandIndex &index)
+{
+ if (!_lower_info_map)
+ return nullptr;
+ auto itr = _lower_info_map->operand.find(index);
+ if (itr == _lower_info_map->operand.end())
+ return nullptr;
+ return itr->second.get();
+}
+
+void Graph::setLowerInfo(const OperandIndex &index,
+ std::unique_ptr<operand::LowerInfo> &&lower_info)
+{
+ assert(_lower_info_map);
+ _lower_info_map->operand.insert(std::make_pair(index, std::move(lower_info)));
+}
+
+void Graph::removeLowerInfo(const OperandIndex &index) { _lower_info_map->operand.erase(index); }
+
+void Graph::makeSubgraphs(OperandIndexMap<std::unique_ptr<operand::LowerInfo>> &operands_lower_info)
+{
+ // if SUBG_MAX_NODE == 0, no limit on nodes of a op_seq
+ const int subg_max_node = util::getConfigInt(util::config::SUBG_MAX_NODE);
+ assert(subg_max_node >= 0);
+
+ bool is_profiling = util::getConfigBool(util::config::PROFILING_MODE);
+ OpSequence *subg = nullptr;
+ SubgraphIndex subg_index;
+
+ // NOTE: The below method appends nodes while making one op_seq if needed. If something better
+ // ways, happy to update this code.
+ PostDfsConstIterator{}.iterate(*this, [&](const OperationIndex &node_index,
+ const Operation &node) {
+ // LowerInfo for in/output operands
+ auto backend = _backend_resolver->getBackend(node_index);
+
+ // TODO How to get frontend layout of this node from IR
+ auto frontend_layout = Layout::NHWC;
+ auto backend_layout = frontend_layout;
+
+ // The layout of each backend should be set at another place
+ // TODO Change setting layout of each backend at another place
+ // TODO Remove getting id of backend
+ if (backend->config()->id() == "acl_cl" || backend->config()->id() == "acl_neon")
+ {
+ const std::string acl_layout_str = util::getConfigString(util::config::ACL_LAYOUT);
+ if (acl_layout_str == "NHWC")
+ {
+ backend_layout = Layout::NHWC;
+ }
+ else if (acl_layout_str == "NCHW")
+ {
+ backend_layout = Layout::NCHW;
+ }
+ }
+ else if (backend->config()->id() == "srcn")
+ {
+ const std::string ncnn_layout_str = util::getConfigString(util::config::NCNN_LAYOUT);
+ if (ncnn_layout_str == "NHWC")
+ {
+ backend_layout = Layout::NHWC;
+ }
+ else if (ncnn_layout_str == "NCHW")
+ {
+ backend_layout = Layout::NCHW;
+ }
+ }
+ else if (backend->config()->id() == "cpu")
+ {
+ backend_layout = Layout::NHWC;
+ }
+
+ for (auto operand : node.getInputs())
+ {
+ auto &&lower_info = operands_lower_info.at(operand);
+ lower_info->addUsePermuteFactor(operand::PermuteFactor{backend, backend_layout});
+ }
+ for (auto operand : node.getOutputs())
+ {
+ auto &&lower_info = operands_lower_info.at(operand);
+ lower_info->addDefPermuteFactor(operand::PermuteFactor{backend, backend_layout});
+ }
+
+ bool new_subg =
+ (subg == nullptr ||
+ (subg_max_node != 0 && subg->operations().size() >= static_cast<size_t>(subg_max_node)));
+
+ // for profiling each op_seq must contain just one node,
+ // so that we can measure a node separately
+ if (new_subg || is_profiling || !mergeable(subg_index, node_index, backend_layout))
+ {
+ auto new_subg_index = appendFreshSingleOpSubgraph(node_index, node, frontend_layout);
+
+ // OpSequence LowerInfo
+ setLowerInfo(new_subg_index,
+ nnfw::cpp14::make_unique<operation::LowerInfo>(backend, backend_layout));
+
+ subg_index = new_subg_index;
+ subg = &(_op_seqs->at(new_subg_index));
+
+ VERBOSE(Lower) << "SUBG#" << subg_index.value() << " is created for "
+ << "NODE#" << node_index.value() << "(" << node.name() << ")" << std::endl;
+ }
+ else
+ {
+ subg->appendOperation(node_index, node);
+ subg->setInputs(node.getInputs());
+
+ VERBOSE(Lower) << "SUBG#" << subg_index.value() << " merges "
+ << "NODE#" << node_index.value() << "(" << node.name() << ")" << std::endl;
+ }
+ });
+}
+
+void Graph::manipulateLowerInfo(
+ OperandIndexMap<std::unique_ptr<operand::LowerInfo>> &operands_lower_info)
+{
+ const auto default_backend = backend::BackendManager::get().getDefault();
+ for (auto index : _inputs)
+ {
+ // Pick just any one from the uses, here the first one is chosen
+ // For the other uses, Permute operations will be inserted later
+ auto &&lower_info = operands_lower_info.at(index);
+ assert(lower_info->use_factors().size() > 0);
+ lower_info->addDefPermuteFactor(*lower_info->use_factors().begin());
+ }
+ for (auto index : _outputs)
+ {
+ auto &&lower_info = operands_lower_info.at(index);
+ if (_operands.at(index).isConstant())
+ {
+ lower_info->addDefPermuteFactor(operand::PermuteFactor{
+ default_backend,
+ Layout::NHWC // TODO Get frontend layout of this node from IR
+ });
+ }
+ }
+
+ // Set LowerInfo for each operand from the operand::LowerInfo holder
+ _operands.iterate([&](const OperandIndex &index, Operand &) {
+ setLowerInfo(index, std::move(operands_lower_info[index]));
+ });
+}
+
+void Graph::dumpLowerInfo()
+{
+ if (::neurun::util::logging::ctx.enabled() == false)
+ return;
+
+ std::map<uint32_t, std::string> dumps;
+
+ _operands.iterate([&](const OperandIndex &index, Operand &object) {
+ std::stringstream sstream;
+ if (!getLowerInfo(index)->def_factors().empty() || !getLowerInfo(index)->use_factors().empty())
+ {
+ auto factors_to_string = [](const 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 OperationIndexList &operations) {
+ std::string str;
+ for (auto op : operations.list())
+ {
+ str += std::to_string(op.value());
+ str += " ";
+ }
+ return "{ " + str + "}";
+ };
+
+ const auto lower_info = getLowerInfo(index);
+ const auto &shape = object.shape();
+ const auto &lower_shape = lower_info->shape();
+ std::string def_ops = operation_index_to_string(object.getDef());
+ 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 : { " << (shape.rank() > 0 ? shape.dim(0) : 0) << " "
+ << (shape.rank() > 1 ? shape.dim(1) : 0) << " "
+ << (shape.rank() > 2 ? shape.dim(2) : 0) << " "
+ << (shape.rank() > 3 ? shape.dim(3) : 0) << " "
+ << "}" << std::endl;
+ sstream << " - Def Operations : " << def_ops << std::endl;
+ sstream << " - Use Operations : " << use_ops << std::endl;
+ sstream << " - Lower Info" << std::endl;
+ sstream << " - 4D Shape (NHWC) : { " << lower_shape.n() << " " << lower_shape.h() << " "
+ << lower_shape.w() << " " << lower_shape.c() << " "
+ << "}" << 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 Graph::mergeable(const SubgraphIndex &subg_index, const OperationIndex &node_index,
+ Layout layout)
+{
+ // Are they mergeable?
+ // 1. the same backend id and layout?
+ // 2. Is op_seq or node branched?
+ // 3. if 1 is true, the subg and a node are connected?
+ const auto &subg = _op_seqs->at(subg_index);
+ const auto &node = _operations.at(node_index);
+
+ // The same backend id and layout?
+ {
+ const auto subg_backend_layout = getLowerInfo(subg_index)->layout();
+ const auto &subg_backend_id = getLowerInfo(subg_index)->backend()->config()->id();
+ const auto &node_backend_id = _backend_resolver->getBackend(node_index)->config()->id();
+ VERBOSE(Lower) << "SUBG#" << subg_index.value() << " { " << subg_backend_id << "("
+ << to_string(subg_backend_layout) << ") } "
+ << " NODE#" << node_index.value() << " (" << node.name() << ") { "
+ << node_backend_id << "(" << to_string(layout) << ") } " << std::endl;
+ if (subg_backend_id != node_backend_id || subg_backend_layout != layout)
+ return false;
+ }
+
+ // Branched?
+ {
+ std::unordered_set<OperationIndex> branched_set;
+
+ // Check for branching up
+ const auto &inputs = subg.getInputs();
+ for (const auto &input : inputs)
+ {
+ const auto &input_obj = _operands.at(input);
+ for (const auto &def : input_obj.getDef().list())
+ {
+ branched_set.insert(def);
+ if (branched_set.size() > 1)
+ {
+ return false;
+ }
+ }
+ }
+ branched_set.clear();
+
+ // Check for branching down
+ const auto &outputs = node.getOutputs();
+ for (const auto &output : outputs)
+ {
+ const auto &output_obj = _operands.at(output);
+ for (const auto &use : output_obj.getUses().list())
+ {
+ 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();
+
+ // subg's operations are in order so that we just check the first and the last
+ std::vector<Element> subg_ops{subg.operations()[0]};
+ if (subg.operations().size() > 1)
+ subg_ops.emplace_back(subg.operations()[subg.operations().size() - 1]);
+
+ for (const auto &elem : subg_ops)
+ {
+ const auto &n_index = elem.index;
+ const auto &n = *elem.node;
+
+ // node's output == subg's input?
+ const auto &n_inputs = n.getInputs();
+ for (auto input : n_inputs)
+ {
+ if (node_outputs.contains(input))
+ {
+ VERBOSE(Lower) << "SUBG#" << subg_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 == subg's output?
+ const auto &n_outputs = n.getOutputs();
+ for (auto output : n_outputs)
+ {
+ if (node_inputs.contains(output))
+ {
+ VERBOSE(Lower) << "SUBG#" << subg_index.value() << " 's NODE#" << n_index.value() << " ("
+ << n.name() << ") is connected to NODE#" << node_index.value()
+ << std::endl;
+ return true;
+ }
+ }
+ }
+
+ VERBOSE(Lower) << "SUBG#" << subg_index.value() << " is not connected to NODE#"
+ << node_index.value() << "(" << node.name() << ")" << std::endl;
+ }
+
+ return false;
+}
+
+SubgraphIndex Graph::appendFreshSingleOpSubgraph(const OperationIndex &node_index,
+ const Operation &node, Layout layout)
+{
+ // Create a fresh op_seq with one operation, and append it to subgraphs
+ // Create a fresh op_seq
+ auto subg = nnfw::cpp14::make_unique<OpSequence>(layout);
+
+ // Add an operation
+ subg->appendOperation(node_index, node);
+
+ // Update input/output
+ subg->setOutputs(node.getOutputs());
+ subg->setInputs(node.getInputs());
+
+ return _op_seqs->emplace(std::move(subg));
+}
+
+void Graph::setBackendResolver(std::unique_ptr<compiler::BackendResolver> &&br)
+{
+ _backend_resolver = std::move(br);
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/GraphIterator.cc b/runtime/neurun/core/src/ir/GraphIterator.cc
new file mode 100644
index 000000000..ce20787ae
--- /dev/null
+++ b/runtime/neurun/core/src/ir/GraphIterator.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GraphIterator.h"
+
+#include "ir/OperationIndexMap.h"
+#include "ir/Graph.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+// Explicit instantiations to have implementation in the source file.
+
+template class DefaultIterator<true>;
+template class DefaultIterator<false>;
+
+template class PostDfsIterator<true>;
+template class PostDfsIterator<false>;
+
+//
+// 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 (auto output : node.getOutputs())
+ {
+ const auto &operand = graph.operands().at(output);
+ for (const auto &use : operand.getUses().list())
+ {
+ 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; }));
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/GraphIterator.h b/runtime/neurun/core/src/ir/GraphIterator.h
new file mode 100644
index 000000000..a5bf1c323
--- /dev/null
+++ b/runtime/neurun/core/src/ir/GraphIterator.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 __NEURUN_IR_GRAPH_ITERATOR_H__
+#define __NEURUN_IR_GRAPH_ITERATOR_H__
+
+#include <type_traits>
+
+#include "ir/Index.h"
+
+namespace neurun
+{
+namespace ir
+{
+
+class Graph;
+class Operation;
+
+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;
+
+public:
+ void iterate(GraphRef graph, const IterFn &fn) const;
+};
+using PostDfsConstIterator = PostDfsIterator<true>;
+
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_IR_GRAPH_ITERATOR_H__
diff --git a/runtime/neurun/core/src/ir/LayoutSet.cc b/runtime/neurun/core/src/ir/LayoutSet.cc
new file mode 100644
index 000000000..025ba45dc
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/LayoutSet.h b/runtime/neurun/core/src/ir/LayoutSet.h
new file mode 100644
index 000000000..e38ef3ce2
--- /dev/null
+++ b/runtime/neurun/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 __NEURUN_IR_LAYOUT_SET_H__
+#define __NEURUN_IR_LAYOUT_SET_H__
+
+#include <initializer_list>
+#include <unordered_set>
+
+#include "ir/Layout.h"
+
+namespace neurun
+{
+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 neurun
+
+#endif // __NEURUN_IR_LAYOUT_SET_H__
diff --git a/runtime/neurun/core/src/ir/OpCode.cc b/runtime/neurun/core/src/ir/OpCode.cc
new file mode 100644
index 000000000..e6552a275
--- /dev/null
+++ b/runtime/neurun/core/src/ir/OpCode.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/OpCode.h"
+
+#include <unordered_map>
+
+namespace neurun
+{
+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);
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/OpSequence.cc b/runtime/neurun/core/src/ir/OpSequence.cc
new file mode 100644
index 000000000..13a6cbe27
--- /dev/null
+++ b/runtime/neurun/core/src/ir/OpSequence.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/OperationVisitor.h"
+#include <sstream>
+
+namespace neurun
+{
+namespace ir
+{
+
+OpSequence::OpSequence(Layout layout) : _layout{layout}
+{
+ // DO NOTHING
+}
+
+void OpSequence::accept(OperationVisitor &v) const { v.visit(*this); }
+
+// TODO: Impl Dumper instead of this method
+std::string OpSequence::getStr() const
+{
+ // " OpSequence IN(xx,xx,xx) -> { op0, op1, op2 } -> OUT(yy,yy,yy)"
+ std::stringstream ss;
+ ss << " OpSequence IN(";
+ for (const auto &index : getInputs())
+ {
+ ss << " " << index.value();
+ }
+ ss << " ) -> {";
+ for (const auto &elem : _operations)
+ {
+ ss << " " << elem.index.value() << "(" << elem.node->name() << ")";
+ }
+ ss << " } -> OUT(";
+ for (const auto &index : getOutputs())
+ {
+ ss << " " << index.value();
+ }
+ ss << " )";
+ return ss.str();
+}
+
+void OpSequence::remove(const OperationIndex &index)
+{
+ assert(exist(index));
+ for (auto it = _operations.cbegin(); it != _operations.cend(); ++it)
+ {
+ if (it->index == index)
+ {
+ _operations.erase(it);
+ break;
+ }
+ }
+}
+
+bool OpSequence::exist(const OperationIndex &index) const
+{
+ for (const auto &element : _operations)
+ {
+ if (element.index == index)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/Operand.cc b/runtime/neurun/core/src/ir/Operand.cc
new file mode 100644
index 000000000..335dd17b9
--- /dev/null
+++ b/runtime/neurun/core/src/ir/Operand.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Operand.h"
+
+namespace neurun
+{
+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::appendUse(const OperationIndex &idx) { _uses.append(idx); }
+
+void Operand::removeUse(const OperationIndex &idx) { _uses.remove(idx); }
+
+void Operand::appendDef(const OperationIndex &idx)
+{
+ assert(!isConstant());
+ assert(_def.size() == 0);
+
+ _def.append(idx);
+}
+
+void Operand::removeDef(const OperationIndex &idx)
+{
+ assert(_def.contains(idx));
+
+ _def.remove(idx);
+}
+
+void Operand::parent_info(std::unique_ptr<operand::ParentInfo> &&parent_info)
+{
+ _parent_info = std::move(parent_info);
+}
+
+const operand::ParentInfo *Operand::parent_info() const { return _parent_info.get(); }
+
+operand::ParentInfo *Operand::parent_info() { return _parent_info.get(); }
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/OperandIndexSequence.cc b/runtime/neurun/core/src/ir/OperandIndexSequence.cc
new file mode 100644
index 000000000..302444125
--- /dev/null
+++ b/runtime/neurun/core/src/ir/OperandIndexSequence.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/OperandIndexSequence.h"
+
+#include <algorithm>
+
+namespace neurun
+{
+namespace ir
+{
+
+OperandIndexSequence::OperandIndexSequence(std::initializer_list<OperandIndex> list) : _set(list)
+{
+ // DO NOTHING
+}
+
+OperandIndexSequence::OperandIndexSequence(std::initializer_list<int32_t> list)
+{
+ for (auto val : list)
+ {
+ _set.emplace_back(static_cast<uint32_t>(val));
+ }
+}
+
+OperandIndexSequence::OperandIndexSequence(std::initializer_list<uint32_t> list)
+{
+ for (auto val : list)
+ {
+ _set.emplace_back(val);
+ }
+}
+
+bool OperandIndexSequence::contains(const OperandIndex &index) const
+{
+ return std::find(_set.begin(), _set.end(), index) != _set.end();
+}
+
+void OperandIndexSequence::replace(const OperandIndex &from, const OperandIndex &to)
+{
+ std::replace(_set.begin(), _set.end(), from, to);
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/Operation.cc b/runtime/neurun/core/src/ir/Operation.cc
new file mode 100644
index 000000000..3e4b606f2
--- /dev/null
+++ b/runtime/neurun/core/src/ir/Operation.cc
@@ -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.
+ */
+
+#include "ir/Operation.h"
+
+#include <cassert>
+
+namespace neurun
+{
+namespace ir
+{
+
+Operation::Operation(OperandConstraint input_constr, const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : _input_constr{input_constr}, _inputs{inputs}, _outputs{outputs}
+{
+}
+
+Operation::Operation(OperandConstraint input_constr) : _input_constr{input_constr} {}
+
+Operation::~Operation() = default;
+
+void Operation::setInputs(const OperandIndexSequence &indexes)
+{
+ assert(_input_constr.check(indexes.size()));
+ _inputs = indexes;
+}
+
+void Operation::setOutputs(const OperandIndexSequence &indexes) { _outputs = indexes; }
+
+void Operation::replaceInput(const OperandIndex &from, const OperandIndex &to)
+{
+ _inputs.replace(from, to);
+}
+
+void Operation::replaceOutput(const OperandIndex &from, const OperandIndex &to)
+{
+ _outputs.replace(from, to);
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/OperationIndexList.cc b/runtime/neurun/core/src/ir/OperationIndexList.cc
new file mode 100644
index 000000000..261cc5ce6
--- /dev/null
+++ b/runtime/neurun/core/src/ir/OperationIndexList.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/OperationIndexList.h"
+
+#include <algorithm>
+
+namespace neurun
+{
+namespace ir
+{
+
+OperationIndexList::OperationIndexList(std::initializer_list<OperationIndex> list) : _list(list)
+{
+ // DO NOTHING
+}
+
+bool OperationIndexList::contains(const OperationIndex &index) const
+{
+ return std::find(_list.begin(), _list.end(), index) != _list.end();
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/Shape.cc b/runtime/neurun/core/src/ir/Shape.cc
new file mode 100644
index 000000000..2679f83c6
--- /dev/null
+++ b/runtime/neurun/core/src/ir/Shape.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/Shape.h"
+#include "util/Utils.h"
+
+#include <cassert>
+#include <functional>
+#include <numeric>
+
+namespace neurun
+{
+namespace ir
+{
+
+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
+{
+ // All of the nodes must have non-negative dimension
+ assert(std::all_of(_dimensions.begin(), _dimensions.end(),
+ [](const int32_t &v) { return (v >= 0); }));
+
+ return std::accumulate(_dimensions.cbegin(), _dimensions.cend(), UINT64_C(1),
+ std::multiplies<uint64_t>());
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/Subgraphs.cc b/runtime/neurun/core/src/ir/Subgraphs.cc
new file mode 100644
index 000000000..780fc8c28
--- /dev/null
+++ b/runtime/neurun/core/src/ir/Subgraphs.cc
@@ -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.
+ */
+
+#include "ir/Subgraphs.h"
+#include "util/logging.h"
+#include "cpp14/memory.h"
+
+#include <cassert>
+#include <string>
+
+namespace neurun
+{
+namespace ir
+{
+
+SubgraphIndex Subgraphs::emplace(const OperationIndex &index, const Operation &node, Layout layout)
+{
+ std::unique_ptr<OpSequence> subg = nnfw::cpp14::make_unique<OpSequence>(layout);
+ subg->appendOperation(index, node);
+ return push(std::move(subg));
+}
+
+SubgraphIndex Subgraphs::emplace(std::unique_ptr<OpSequence> &&subg)
+{
+ return push(std::move(subg));
+}
+
+bool Subgraphs::containsOperation(const OperationIndex &operation_index) const
+{
+ return findOperation(operation_index).valid();
+}
+
+SubgraphIndex Subgraphs::getOperation(const OperationIndex &operation_index) const
+{
+ SubgraphIndex ret = findOperation(operation_index);
+ assert(ret.valid());
+ return ret;
+}
+
+// TODO: Extract this into external helper function
+void Subgraphs::dump(const std::string &msg) const
+{
+ VERBOSE(Subgraphs) << "Subgraphs(" << msg << ")" << std::endl;
+ iterate([&](const SubgraphIndex &idx, const OpSequence &subg) {
+ VERBOSE(Subgraphs) << idx.value() << "] " << subg.getStr() << std::endl;
+ });
+}
+
+void Subgraphs::removeFromSubgraph(const OperationIndex &operation_index)
+{
+ const auto subg_index = findOperation(operation_index);
+ auto &subg = at(subg_index);
+ subg.remove(operation_index);
+ if (subg.size() == 0)
+ {
+ remove(subg_index);
+ }
+}
+
+SubgraphIndex Subgraphs::findOperation(const OperationIndex &operation_index) const
+{
+ SubgraphIndex ret;
+ iterate([&](const SubgraphIndex &index, const OpSequence &object) {
+ for (const auto &elem : object.operations())
+ {
+ if (elem.index == operation_index)
+ ret = index;
+ }
+ });
+ return ret;
+}
+
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/TypeInfo.cc b/runtime/neurun/core/src/ir/TypeInfo.cc
new file mode 100644
index 000000000..280146b51
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/dumper/Dumper.cc b/runtime/neurun/core/src/ir/dumper/Dumper.cc
new file mode 100644
index 000000000..ddfd1a47a
--- /dev/null
+++ b/runtime/neurun/core/src/ir/dumper/Dumper.cc
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dumper.h"
+
+#include <string>
+
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace dumper
+{
+
+using namespace operation;
+
+void Dumper::visit(const Abs &node)
+{
+ VERBOSE(LIR) << "* Abs" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Abs::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Add &node)
+{
+ VERBOSE(LIR) << "* Add" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Add::Input::LHS).value() << ", "
+ << node.getInputs().at(Add::Input::RHS).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const ArgMax &node)
+{
+ VERBOSE(LIR) << "* ArgMax" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ArgMax::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const AvgPool2D &node)
+{
+ VERBOSE(LIR) << "* AvgPool2D(Implicit)" << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(AvgPool2D::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Cast &node)
+{
+ VERBOSE(LIR) << "* Cast" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Cast::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Comparison &node)
+{
+ VERBOSE(LIR) << "* Comparison" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Comparison::Input::INPUT0).value()
+ << ", " << node.getInputs().at(Comparison::Input::INPUT1).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Concat &node)
+{
+ VERBOSE(LIR) << "* Concat" << std::endl;
+ std::string inputs;
+ for (auto i : node.getInputs())
+ {
+ inputs += std::to_string(i.value()) + ",";
+ }
+ VERBOSE(LIR) << " - Inputs : IFM(" << inputs << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Conv2D &node)
+{
+ std::string padding_type =
+ node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
+ VERBOSE(LIR) << "* Conv2D(" << padding_type << ")" << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(Conv2D::Input::INPUT).value()
+ << ") Kernel(" << node.getInputs().at(Conv2D::Input::KERNEL).value() << ") Bias("
+ << node.getInputs().at(Conv2D::Input::BIAS).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const DepthToSpace &node)
+{
+ VERBOSE(LIR) << "* DepthToSpace" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(DepthToSpace::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const DepthwiseConv2D &node)
+{
+ std::string padding_type =
+ node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
+ VERBOSE(LIR) << "* DepthwiseConv2D(" << padding_type << ")" << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(DepthwiseConv2D::Input::INPUT).value()
+ << ") Kernel(" << node.getInputs().at(DepthwiseConv2D::Input::KERNEL).value()
+ << ") Bias(" << node.getInputs().at(DepthwiseConv2D::Input::BIAS).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Dequantize &node)
+{
+ VERBOSE(LIR) << "* Dequantize" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Dequantize::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Div &node)
+{
+ VERBOSE(LIR) << "* Div" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Div::Input::LHS).value() << ", "
+ << node.getInputs().at(Div::Input::RHS).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const EmbeddingLookup &node)
+{
+ VERBOSE(LIR) << "* EmbeddingLookup" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Lookups("
+ << node.getInputs().at(EmbeddingLookup::Input::LOOKUPS).value() << ") VALUES("
+ << node.getInputs().at(EmbeddingLookup::Input::VALUES).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Exp &node)
+{
+ VERBOSE(LIR) << "* Exp" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Exp::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Floor &node)
+{
+ VERBOSE(LIR) << "* Floor" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Floor::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const FullyConnected &node)
+{
+ VERBOSE(LIR) << "* FullyConnected" << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(FullyConnected::Input::INPUT).value()
+ << ") Weight(" << node.getInputs().at(FullyConnected::Input::WEIGHT).value()
+ << ") Bias(" << node.getInputs().at(FullyConnected::Input::BIAS).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Gather &node)
+{
+ VERBOSE(LIR) << "* Gather" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Gather::Input::INPUT).value()
+ << ") Indices(" << node.getInputs().at(Gather::Input::INDICES).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const HashtableLookup &node)
+{
+ VERBOSE(LIR) << "* HashTableLookup" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Lookups("
+ << node.getInputs().at(HashtableLookup::Input::LOOKUPS).value() << ") Keys("
+ << node.getInputs().at(HashtableLookup::Input::KEYS).value() << ") Values("
+ << node.getInputs().at(HashtableLookup::Input::VALUES).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Outputs : Output("
+ << node.getInputs().at(HashtableLookup::Output::OUTPUT).value() << ") Hits("
+ << node.getInputs().at(HashtableLookup::Output::HITS).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const InstanceNorm &node)
+{
+ VERBOSE(LIR) << "* InstanceNorm" << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(InstanceNorm::Input::INPUT).value()
+ << ") Gamma(" << node.getInputs().at(InstanceNorm::Input::GAMMA).value() << ") Beta("
+ << node.getInputs().at(InstanceNorm::Input::BETA).value() << ") Epsilon("
+ << node.param().epsilon << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const L2Normalization &node)
+{
+ VERBOSE(LIR) << "* L2Normalization" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input("
+ << node.getInputs().at(L2Normalization::Input::INPUT).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const L2Pool2D &node)
+{
+ VERBOSE(LIR) << "* L2Pool2D" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(L2Pool2D::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const LocalResponseNormalization &node)
+{
+ VERBOSE(LIR) << "* LocalResponseNormalization" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input("
+ << node.getInputs().at(LocalResponseNormalization::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const LSTM &node)
+{
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(LSTM::Input::INPUT).value()
+ << ") Input To Input Weights("
+ << node.getInputs().at(LSTM::Input::INPUT_TO_INPUT_WEIGHTS).value()
+ << ") Input To Forget Weights("
+ << node.getInputs().at(LSTM::Input::INPUT_TO_FORGET_WEIGHTS).value()
+ << ") Input To Cell Weights("
+ << node.getInputs().at(LSTM::Input::INPUT_TO_CELL_WEIGHTS).value()
+ << ") Input To Output Weights("
+ << node.getInputs().at(LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS).value()
+ << ") Recurrent To Input Weights("
+ << node.getInputs().at(LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS).value()
+ << ") Recurrent To Forget Weights("
+ << node.getInputs().at(LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS).value()
+ << ") Recurrent To Cell Weights("
+ << node.getInputs().at(LSTM::Input::RECURRENT_TO_CELL_WEIGHTS).value()
+ << ") Recurrent To Output Weights("
+ << node.getInputs().at(LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS).value()
+ << ") Cell To Input Weights("
+ << node.getInputs().at(LSTM::Input::CELL_TO_INPUT_WEIGHTS).value()
+ << ") Cell To Forget Weights("
+ << node.getInputs().at(LSTM::Input::CELL_TO_FORGET_WEIGHTS).value()
+ << ") Cell To OUTPUT Weights("
+ << node.getInputs().at(LSTM::Input::CELL_TO_OUTPUT_WEIGHTS).value()
+ << ") Input Gate Bias(" << node.getInputs().at(LSTM::Input::INPUT_GATE_BIAS).value()
+ << ") Forget Gate Bias("
+ << node.getInputs().at(LSTM::Input::FORGET_GATE_BIAS).value() << ") Cell Bias("
+ << node.getInputs().at(LSTM::Input::CELL_BIAS).value() << ") Output Gate Bias("
+ << node.getInputs().at(LSTM::Input::OUTPUT_GATE_BIAS).value()
+ << ") Projection Weights("
+ << node.getInputs().at(LSTM::Input::PROJECTION_WEIGHTS).value()
+ << ") Projection Bias(" << node.getInputs().at(LSTM::Input::PROJECTION_BIAS).value()
+ << ") Output State In(" << node.getInputs().at(LSTM::Input::OUTPUT_STATE_IN).value()
+ << ") Cell State In(" << node.getInputs().at(LSTM::Input::CELL_STATE_IN).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Scratch Buffer("
+ << node.getOutputs().at(LSTM::Output::SCRATCH_BUFFER).value()
+ << ") Output State Out("
+ << node.getInputs().at(LSTM::Output::OUTPUT_STATE_OUT).value() << ") Cell State Out("
+ << node.getInputs().at(LSTM::Output::CELL_STATE_OUT).value() << ") Output("
+ << node.getInputs().at(LSTM::Output::OUTPUT).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const LogicalAnd &node)
+{
+ VERBOSE(LIR) << "* LogicalAnd" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(LogicalAnd::Input::INPUT0).value()
+ << ", " << node.getInputs().at(LogicalAnd::Input::INPUT1).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const LogicalNot &node)
+{
+ VERBOSE(LIR) << "* LogicalNot" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(LogicalNot::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const LogicalOr &node)
+{
+ VERBOSE(LIR) << "* LogicalOr" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(LogicalOr::Input::INPUT0).value()
+ << ", " << node.getInputs().at(LogicalOr::Input::INPUT1).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Logistic &node)
+{
+ VERBOSE(LIR) << "* Logistic" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Logistic::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const MaxPool2D &node)
+{
+ std::string padding_type =
+ node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
+ VERBOSE(LIR) << "* MaxPool2D(" << padding_type << ")" << std::endl;
+ VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(MaxPool2D::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Mean &node)
+{
+ VERBOSE(LIR) << "* Mean" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Mean::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Mul &node)
+{
+ VERBOSE(LIR) << "* Mul" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Mul::Input::LHS).value() << ", "
+ << node.getInputs().at(Mul::Input::RHS).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Neg &node)
+{
+ VERBOSE(LIR) << "* Neg" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Neg::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Pack &node)
+{
+ VERBOSE(LIR) << "* Pack" << 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 : Inputs(" << inputs << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::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).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const PReLU &node)
+{
+ VERBOSE(LIR) << "* PReLU" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(PReLU::Input::INPUT).value()
+ << ") Alpha(" << node.getInputs().at(PReLU::Input::ALPHA).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const ReduceMax &node)
+{
+ VERBOSE(LIR) << "* ReduceMax" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReduceMax::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const ReduceMin &node)
+{
+ VERBOSE(LIR) << "* ReduceMin" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReduceMin::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const ReduceSum &node)
+{
+ VERBOSE(LIR) << "* ReduceSum" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReduceSum::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const ReLU &node)
+{
+ VERBOSE(LIR) << "* ReLU" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReLU::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const ReLU1 &node)
+{
+ VERBOSE(LIR) << "* ReLU1" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReLU1::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const ReLU6 &node)
+{
+ VERBOSE(LIR) << "* ReLU6" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReLU6::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Reshape &node)
+{
+ VERBOSE(LIR) << "* Reshape" << std::endl;
+ // TODO The shape index should be "node.getInputs().at(1).value()" but not valid for now
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Reshape::Input::INPUT).value()
+ << ") Shape("
+ << "?"
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const ResizeBilinear &node)
+{
+ VERBOSE(LIR) << "* ResizeBilinear" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ResizeBilinear::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const RNN &node)
+{
+ VERBOSE(LIR) << "* RNN" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(RNN::Input::INPUT).value()
+ << ") Weights" << node.getInputs().at(RNN::Input::WEIGHTS).value()
+ << ") Recurrent Weights"
+ << node.getInputs().at(RNN::Input::RECURRENT_WEIGHTS).value() << ") Bias"
+ << node.getInputs().at(RNN::Input::BIAS).value() << ") Hidden State"
+ << node.getInputs().at(RNN::Input::HIDDEN_STATE_IN).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(RNN::Output::OUTPUT).value()
+ << ") Hidden State" << node.getInputs().at(RNN::Output::HIDDEN_STATE_OUT).value()
+ << ")" << std::endl;
+}
+
+void Dumper::visit(const RSQRT &node)
+{
+ VERBOSE(LIR) << "* RSQRT" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(RSQRT::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Softmax &node)
+{
+ VERBOSE(LIR) << "* Softmax" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Softmax::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const SpaceToDepth &node)
+{
+ VERBOSE(LIR) << "* SpaceToDepth" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(SpaceToDepth::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Split &node)
+{
+ VERBOSE(LIR) << "* Split" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Split::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const SQRT &node)
+{
+ VERBOSE(LIR) << "* SQRT" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(SQRT::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const SquaredDifference &node)
+{
+ VERBOSE(LIR) << "* SquaredDifference" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input("
+ << node.getInputs().at(SquaredDifference::Input::LHS).value() << ", "
+ << node.getInputs().at(SquaredDifference::Input::RHS).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Squeeze &node)
+{
+ VERBOSE(LIR) << "* Squeeze" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Squeeze::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Slice &node)
+{
+ VERBOSE(LIR) << "* Slice" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Slice::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const StridedSlice &node)
+{
+ VERBOSE(LIR) << "* StridedSlice" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(StridedSlice::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Sub &node)
+{
+ VERBOSE(LIR) << "* Sub" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Sub::Input::LHS).value() << ", "
+ << node.getInputs().at(Sub::Input::RHS).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Tanh &node)
+{
+ VERBOSE(LIR) << "* TanH" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Tanh::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const TopKV2 &node)
+{
+ VERBOSE(LIR) << "* TopKV2" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(TopKV2::Input::INPUT).value() << ")"
+ << std::endl;
+ VERBOSE(LIR) << " - Outputs : Values("
+ << node.getOutputs().at(TopKV2::Output::OUTPUT_VALUES).value() << ") Indices("
+ << node.getOutputs().at(TopKV2::Output::OUTPUT_INDICES).value() << ")" << std::endl;
+}
+
+void Dumper::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).value() << ") KERNEL("
+ << node.getInputs().at(TransposeConv::Input::KERNEL).value() << ") IFM("
+ << node.getInputs().at(TransposeConv::Input::INPUT).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Transpose &node)
+{
+ VERBOSE(LIR) << "* Transpose" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Transpose::Input::INPUT).value()
+ << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Unpack &node)
+{
+ VERBOSE(LIR) << "* Unpack" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Unpack::Input::INPUT).value() << ")"
+ << 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 Dumper::visit(const Min &node)
+{
+ VERBOSE(LIR) << "* Min" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Min::Input::LHS).value() << ", "
+ << node.getInputs().at(Min::Input::RHS).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const Max &node)
+{
+ VERBOSE(LIR) << "* Max" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Max::Input::LHS).value() << ", "
+ << node.getInputs().at(Max::Input::RHS).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+void Dumper::visit(const OneHot &node)
+{
+ VERBOSE(LIR) << "* OneHot" << std::endl;
+ VERBOSE(LIR) << " - Inputs : "
+ << "Indices(" << node.getInputs().at(OneHot::Input::INDICES).value() << ") "
+ << "Depth(" << node.getInputs().at(OneHot::Input::DEPTH).value() << ") "
+ << "OnValue(" << node.getInputs().at(OneHot::Input::ON_VALUE).value() << ") "
+ << "OffValue(" << node.getInputs().at(OneHot::Input::OFF_VALUE).value() << ") "
+ << "Axis(" << node.param().axis << ") " << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
+} // namespace dumper
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/dumper/Dumper.h b/runtime/neurun/core/src/ir/dumper/Dumper.h
new file mode 100644
index 000000000..458f1c81f
--- /dev/null
+++ b/runtime/neurun/core/src/ir/dumper/Dumper.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 __NEURUN_GRAPH_DUMPER_H__
+#define __NEURUN_GRAPH_DUMPER_H__
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace dumper
+{
+
+class Dumper : public OperationVisitor
+{
+public:
+ Dumper() = default;
+
+public:
+ void visit(const operation::Abs &) override;
+ void visit(const operation::Add &node) override;
+ void visit(const operation::ArgMax &) override;
+ void visit(const operation::AvgPool2D &node) override;
+ void visit(const operation::Cast &) 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::DepthToSpace &) override;
+ void visit(const operation::DepthwiseConv2D &node) override;
+ void visit(const operation::Dequantize &) override;
+ void visit(const operation::Div &) override;
+ void visit(const operation::EmbeddingLookup &) override;
+ void visit(const operation::Exp &) override;
+ void visit(const operation::Floor &) 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::L2Pool2D &) override;
+ void visit(const operation::LocalResponseNormalization &) override;
+ void visit(const operation::LogicalAnd &) override;
+ void visit(const operation::LogicalNot &) override;
+ void visit(const operation::LogicalOr &) override;
+ void visit(const operation::Logistic &) override;
+ void visit(const operation::LSTM &) override;
+ void visit(const operation::MaxPool2D &node) override;
+ void visit(const operation::Mean &) override;
+ void visit(const operation::Mul &) override;
+ void visit(const operation::Neg &) override;
+ void visit(const operation::Pack &) override;
+ void visit(const operation::Permute &node) override;
+ void visit(const operation::PReLU &) override;
+ void visit(const operation::ReduceMax &) override;
+ void visit(const operation::ReduceMin &) override;
+ void visit(const operation::ReduceSum &) override;
+ void visit(const operation::ReLU &) override;
+ void visit(const operation::ReLU1 &) override;
+ void visit(const operation::ReLU6 &) override;
+ void visit(const operation::Reshape &node) override;
+ void visit(const operation::ResizeBilinear &) override;
+ void visit(const operation::RNN &) override;
+ void visit(const operation::RSQRT &) override;
+ void visit(const operation::Softmax &node) override;
+ void visit(const operation::SpaceToDepth &) override;
+ void visit(const operation::Split &) override;
+ void visit(const operation::SQRT &) 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::Sub &) override;
+ void visit(const operation::Tanh &) 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::Min &) override;
+ void visit(const operation::Max &) override;
+ void visit(const operation::OneHot &) override;
+};
+
+} // namespace dumper
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_DUMPER_H__
diff --git a/runtime/neurun/core/src/ir/operand/Shape4DConvert.h b/runtime/neurun/core/src/ir/operand/Shape4DConvert.h
new file mode 100644
index 000000000..feffee89f
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operand/Shape4DConvert.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_GRAPH_OPERAND_SHAPE4D_CONVERT_H__
+#define __NEURUN_GRAPH_OPERAND_SHAPE4D_CONVERT_H__
+
+#include "ir/operand/LowerInfo.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operand
+{
+
+inline LowerInfo::Shape4D asShape4D(const Shape &shape)
+{
+ switch (shape.rank())
+ {
+ case 0u:
+ return LowerInfo::Shape4D(1, 1, 1, 1);
+
+ case 1u:
+ return LowerInfo::Shape4D(1, 1, 1, shape.dim(0));
+
+ case 2u:
+ return LowerInfo::Shape4D(1, 1, shape.dim(0), shape.dim(1));
+
+ case 3u:
+ return LowerInfo::Shape4D(1, shape.dim(0), shape.dim(1), shape.dim(2));
+
+ case 4u:
+ return LowerInfo::Shape4D(shape.dim(0), shape.dim(1), shape.dim(2), shape.dim(3));
+
+ default:
+ throw "Unsupported rank > 4";
+ }
+}
+
+} // namespace operand
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_OPERAND_SHAPE4D_CONVERT_H__
diff --git a/runtime/neurun/core/src/ir/operation/Abs.cc b/runtime/neurun/core/src/ir/operation/Abs.cc
new file mode 100644
index 000000000..9506f83d2
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Abs.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/Abs.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Abs::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Abs::Abs(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Add.cc b/runtime/neurun/core/src/ir/operation/Add.cc
new file mode 100644
index 000000000..a7c40c37a
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Add.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/Add.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Add::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Add::Add(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/ArgMax.cc b/runtime/neurun/core/src/ir/operation/ArgMax.cc
new file mode 100644
index 000000000..200abc7dd
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/AvgPool2D.cc b/runtime/neurun/core/src/ir/operation/AvgPool2D.cc
new file mode 100644
index 000000000..21ec052eb
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/AvgPool2D.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/AvgPool2D.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void AvgPool2D::accept(OperationVisitor &v) const { v.visit(*this); }
+
+AvgPool2D::AvgPool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/BatchToSpaceND.cc b/runtime/neurun/core/src/ir/operation/BatchToSpaceND.cc
new file mode 100644
index 000000000..042144c12
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void BatchToSpaceND::accept(OperationVisitor &v) const { v.visit(*this); }
+
+BatchToSpaceND::BatchToSpaceND(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Cast.cc b/runtime/neurun/core/src/ir/operation/Cast.cc
new file mode 100644
index 000000000..095225eca
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Cast.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/Cast.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Cast::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Cast::Cast(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Comparison.cc b/runtime/neurun/core/src/ir/operation/Comparison.cc
new file mode 100644
index 000000000..995d56764
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Concat.cc b/runtime/neurun/core/src/ir/operation/Concat.cc
new file mode 100644
index 000000000..1772da1fc
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Conv2D.cc b/runtime/neurun/core/src/ir/operation/Conv2D.cc
new file mode 100644
index 000000000..505e916a9
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Custom.cc b/runtime/neurun/core/src/ir/operation/Custom.cc
new file mode 100644
index 000000000..67f36d588
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Custom.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Custom.h"
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+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; }
+
+Custom::~Custom() { delete[] _userdata.data; }
+
+std::string Custom::name() const { return id(); }
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/DepthToSpace.cc b/runtime/neurun/core/src/ir/operation/DepthToSpace.cc
new file mode 100644
index 000000000..fd1d1f1aa
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/DepthwiseConv2D.cc b/runtime/neurun/core/src/ir/operation/DepthwiseConv2D.cc
new file mode 100644
index 000000000..ed76594a3
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Dequantize.cc b/runtime/neurun/core/src/ir/operation/Dequantize.cc
new file mode 100644
index 000000000..e99a59cb7
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Dequantize.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/Dequantize.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Dequantize::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Dequantize::Dequantize(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Div.cc b/runtime/neurun/core/src/ir/operation/Div.cc
new file mode 100644
index 000000000..484406ff3
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Div.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/Div.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Div::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Div::Div(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/EmbeddingLookup.cc b/runtime/neurun/core/src/ir/operation/EmbeddingLookup.cc
new file mode 100644
index 000000000..206e6bfaa
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Exp.cc b/runtime/neurun/core/src/ir/operation/Exp.cc
new file mode 100644
index 000000000..3c0e0cf9b
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Exp.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/Exp.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Exp::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Exp::Exp(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Floor.cc b/runtime/neurun/core/src/ir/operation/Floor.cc
new file mode 100644
index 000000000..75373cd41
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Floor.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/Floor.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Floor::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Floor::Floor(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/FullyConnected.cc b/runtime/neurun/core/src/ir/operation/FullyConnected.cc
new file mode 100644
index 000000000..9560c0593
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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::createExact(3u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Gather.cc b/runtime/neurun/core/src/ir/operation/Gather.cc
new file mode 100644
index 000000000..f98cef9ae
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/HashtableLookup.cc b/runtime/neurun/core/src/ir/operation/HashtableLookup.cc
new file mode 100644
index 000000000..ecb9d3195
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/InstanceNorm.cc b/runtime/neurun/core/src/ir/operation/InstanceNorm.cc
new file mode 100644
index 000000000..69e47abd4
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/L2Normalization.cc b/runtime/neurun/core/src/ir/operation/L2Normalization.cc
new file mode 100644
index 000000000..67085989e
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void L2Normalization::accept(OperationVisitor &v) const { v.visit(*this); }
+
+L2Normalization::L2Normalization(const OperandIndexSequence &inputs,
+ const OperandIndexSequence &outputs, const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/L2Pool2D.cc b/runtime/neurun/core/src/ir/operation/L2Pool2D.cc
new file mode 100644
index 000000000..0815cb5ab
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/L2Pool2D.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/L2Pool2D.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void L2Pool2D::accept(OperationVisitor &v) const { v.visit(*this); }
+
+L2Pool2D::L2Pool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/LSTM.cc b/runtime/neurun/core/src/ir/operation/LSTM.cc
new file mode 100644
index 000000000..58e2aa32e
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/LSTM.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/LSTM.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+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::createExact(23u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/LocalResponseNormalization.cc b/runtime/neurun/core/src/ir/operation/LocalResponseNormalization.cc
new file mode 100644
index 000000000..dcba7f1cb
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/LogicalAnd.cc b/runtime/neurun/core/src/ir/operation/LogicalAnd.cc
new file mode 100644
index 000000000..51f4f0ee0
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/LogicalAnd.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/LogicalAnd.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void LogicalAnd::accept(OperationVisitor &v) const { v.visit(*this); }
+
+LogicalAnd::LogicalAnd(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/LogicalNot.cc b/runtime/neurun/core/src/ir/operation/LogicalNot.cc
new file mode 100644
index 000000000..48c25142a
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/LogicalNot.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/LogicalNot.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void LogicalNot::accept(OperationVisitor &v) const { v.visit(*this); }
+
+LogicalNot::LogicalNot(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/LogicalOr.cc b/runtime/neurun/core/src/ir/operation/LogicalOr.cc
new file mode 100644
index 000000000..663b7deb5
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/LogicalOr.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/LogicalOr.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void LogicalOr::accept(OperationVisitor &v) const { v.visit(*this); }
+
+LogicalOr::LogicalOr(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Logistic.cc b/runtime/neurun/core/src/ir/operation/Logistic.cc
new file mode 100644
index 000000000..3ed2f3453
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Logistic.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/Logistic.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Logistic::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Logistic::Logistic(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/LowerInfo.cc b/runtime/neurun/core/src/ir/operation/LowerInfo.cc
new file mode 100644
index 000000000..6133be3f8
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+LowerInfo::LowerInfo(const backend::Backend *backend, Layout layout)
+ : _permute_factor{backend, layout}
+{
+ // DO NOTHING
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Max.cc b/runtime/neurun/core/src/ir/operation/Max.cc
new file mode 100644
index 000000000..be4bdd365
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Max.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/Max.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Max::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Max::Max(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/MaxPool2D.cc b/runtime/neurun/core/src/ir/operation/MaxPool2D.cc
new file mode 100644
index 000000000..8f1b70cd6
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/MaxPool2D.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/MaxPool2D.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void MaxPool2D::accept(OperationVisitor &v) const { v.visit(*this); }
+
+MaxPool2D::MaxPool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Mean.cc b/runtime/neurun/core/src/ir/operation/Mean.cc
new file mode 100644
index 000000000..016b5dd85
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Mean.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/Mean.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Mean::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Mean::Mean(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Min.cc b/runtime/neurun/core/src/ir/operation/Min.cc
new file mode 100644
index 000000000..a864405dc
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Min.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/Min.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Min::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Min::Min(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Mul.cc b/runtime/neurun/core/src/ir/operation/Mul.cc
new file mode 100644
index 000000000..0b2d67a9d
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Mul.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/Mul.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Mul::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Mul::Mul(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Neg.cc b/runtime/neurun/core/src/ir/operation/Neg.cc
new file mode 100644
index 000000000..65922d57c
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Neg.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/Neg.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Neg::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Neg::Neg(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/OneHot.cc b/runtime/neurun/core/src/ir/operation/OneHot.cc
new file mode 100644
index 000000000..0ba3c9d60
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/PReLU.cc b/runtime/neurun/core/src/ir/operation/PReLU.cc
new file mode 100644
index 000000000..b8555ccbd
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Pack.cc b/runtime/neurun/core/src/ir/operation/Pack.cc
new file mode 100644
index 000000000..412c744ea
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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(3u), inputs, outputs}, _param{param}
+{
+}
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Pad.cc b/runtime/neurun/core/src/ir/operation/Pad.cc
new file mode 100644
index 000000000..a08be12a6
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Pad.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/Pad.h"
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Pad::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Pad::Pad(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Permute.cc b/runtime/neurun/core/src/ir/operation/Permute.cc
new file mode 100644
index 000000000..ec3d969c8
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Permute.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Permute.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Permute::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Permute::Permute(const OperandIndex &input, const OperandIndex &output,
+ const backend::BackendContext *input_backend_ctx,
+ const backend::BackendContext *output_backend_ctx, Type type, DataType data_type)
+ : Operation{OperandConstraint::createExact(1u)}, _param{input_backend_ctx, output_backend_ctx},
+ _type{type}, _dataType{data_type}
+{
+ setInputs({input});
+ setOutputs({output});
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/RNN.cc b/runtime/neurun/core/src/ir/operation/RNN.cc
new file mode 100644
index 000000000..8db5cbceb
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/RSQRT.cc b/runtime/neurun/core/src/ir/operation/RSQRT.cc
new file mode 100644
index 000000000..ec13b20ec
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/RSQRT.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/RSQRT.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void RSQRT::accept(OperationVisitor &v) const { v.visit(*this); }
+
+RSQRT::RSQRT(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/ReLU.cc b/runtime/neurun/core/src/ir/operation/ReLU.cc
new file mode 100644
index 000000000..6b3f7e72d
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/ReLU.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/ReLU.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void ReLU::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ReLU::ReLU(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/ReLU1.cc b/runtime/neurun/core/src/ir/operation/ReLU1.cc
new file mode 100644
index 000000000..d7b4e1b11
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/ReLU1.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/ReLU1.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void ReLU1::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ReLU1::ReLU1(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/ReLU6.cc b/runtime/neurun/core/src/ir/operation/ReLU6.cc
new file mode 100644
index 000000000..245eb923f
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/ReLU6.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/ReLU6.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void ReLU6::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ReLU6::ReLU6(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/ReduceMax.cc b/runtime/neurun/core/src/ir/operation/ReduceMax.cc
new file mode 100644
index 000000000..b7ef2c5a9
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/ReduceMax.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/ReduceMax.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void ReduceMax::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ReduceMax::ReduceMax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/ReduceMin.cc b/runtime/neurun/core/src/ir/operation/ReduceMin.cc
new file mode 100644
index 000000000..84d7e0cc5
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/ReduceMin.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/ReduceMin.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void ReduceMin::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ReduceMin::ReduceMin(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/ReduceSum.cc b/runtime/neurun/core/src/ir/operation/ReduceSum.cc
new file mode 100644
index 000000000..7e3b19bd6
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/ReduceSum.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/ReduceSum.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void ReduceSum::accept(OperationVisitor &v) const { v.visit(*this); }
+
+ReduceSum::ReduceSum(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Reshape.cc b/runtime/neurun/core/src/ir/operation/Reshape.cc
new file mode 100644
index 000000000..bae37e12f
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Reshape.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/operation/Reshape.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Reshape::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Reshape::Reshape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/ResizeBilinear.cc b/runtime/neurun/core/src/ir/operation/ResizeBilinear.cc
new file mode 100644
index 000000000..55ae4815d
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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::createExact(1u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/SQRT.cc b/runtime/neurun/core/src/ir/operation/SQRT.cc
new file mode 100644
index 000000000..6c6daa3a0
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/SQRT.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/SQRT.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void SQRT::accept(OperationVisitor &v) const { v.visit(*this); }
+
+SQRT::SQRT(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Slice.cc b/runtime/neurun/core/src/ir/operation/Slice.cc
new file mode 100644
index 000000000..88014d1e4
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Slice.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/Slice.h"
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Slice::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Slice::Slice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Softmax.cc b/runtime/neurun/core/src/ir/operation/Softmax.cc
new file mode 100644
index 000000000..6b3a6b164
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/SpaceToBatchND.cc b/runtime/neurun/core/src/ir/operation/SpaceToBatchND.cc
new file mode 100644
index 000000000..a07453504
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/SpaceToDepth.cc b/runtime/neurun/core/src/ir/operation/SpaceToDepth.cc
new file mode 100644
index 000000000..ca16bd92f
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Split.cc b/runtime/neurun/core/src/ir/operation/Split.cc
new file mode 100644
index 000000000..a4b15a9b2
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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(1u), inputs, outputs}, _param{param}
+{
+}
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/SquaredDifference.cc b/runtime/neurun/core/src/ir/operation/SquaredDifference.cc
new file mode 100644
index 000000000..141fb7560
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Squeeze.cc b/runtime/neurun/core/src/ir/operation/Squeeze.cc
new file mode 100644
index 000000000..22ee5763d
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/StridedSlice.cc b/runtime/neurun/core/src/ir/operation/StridedSlice.cc
new file mode 100644
index 000000000..f764dccc0
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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(3u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Sub.cc b/runtime/neurun/core/src/ir/operation/Sub.cc
new file mode 100644
index 000000000..7d83e3d74
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Sub.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/Sub.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Sub::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Sub::Sub(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/Tanh.cc b/runtime/neurun/core/src/ir/operation/Tanh.cc
new file mode 100644
index 000000000..a3125e947
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Tanh.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/Tanh.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Tanh::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Tanh::Tanh(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs)
+ : Operation{OperandConstraint::createExact(1u), inputs, outputs}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/TopKV2.cc b/runtime/neurun/core/src/ir/operation/TopKV2.cc
new file mode 100644
index 000000000..6fabd34a3
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Transpose.cc b/runtime/neurun/core/src/ir/operation/Transpose.cc
new file mode 100644
index 000000000..74239b0f6
--- /dev/null
+++ b/runtime/neurun/core/src/ir/operation/Transpose.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/Transpose.h"
+
+#include <cassert>
+
+#include "ir/OperationVisitor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace operation
+{
+
+void Transpose::accept(OperationVisitor &v) const { v.visit(*this); }
+
+Transpose::Transpose(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs,
+ const Param &param)
+ : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param}
+{
+}
+
+} // namespace operation
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/operation/TransposeConv.cc b/runtime/neurun/core/src/ir/operation/TransposeConv.cc
new file mode 100644
index 000000000..30664e974
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/operation/Unpack.cc b/runtime/neurun/core/src/ir/operation/Unpack.cc
new file mode 100644
index 000000000..7c2c24892
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/ir/pass/ConstantInsertionPass.cc b/runtime/neurun/core/src/ir/pass/ConstantInsertionPass.cc
new file mode 100644
index 000000000..8f8ebff1b
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/ConstantInsertionPass.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 "ConstantInsertionPass.h"
+
+#include "backend/Backend.h"
+#include <ir/Graph.h>
+#include "ir/operand/Shape4DConvert.h"
+#include <util/Utils.h>
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+void ConstantInsertionPass::callback(const OperationIndex &node_index, Operation &node)
+{
+ const auto &subgraph_index = _graph.subgraphs().getOperation(node_index);
+ const auto subg_lower_info = _graph.getLowerInfo(subgraph_index);
+ const auto backend = subg_lower_info->backend();
+ const auto layout = subg_lower_info->layout();
+ const auto factor = operand::PermuteFactor{backend, layout};
+
+ for (const auto input : node.getInputs())
+ {
+ auto &object = _graph.operands().at(input);
+
+ if (object.isConstant())
+ {
+ const auto key = ReplaceKey{input, factor};
+ if (_replace_operands_map.count(key) == 0)
+ {
+ auto new_object = object;
+ // TODO Remove const_case
+ const_cast<std::list<OperationIndex> &>(new_object.getDef().list()).clear();
+ const_cast<std::list<OperationIndex> &>(new_object.getUses().list()).clear();
+ const auto new_index = _graph.operands().emplace(new_object);
+ _replace_operands_map[key] = new_index;
+
+ _graph.setLowerInfo(new_index, nnfw::cpp14::make_unique<operand::LowerInfo>(
+ operand::asShape4D(new_object.shape())));
+ _graph.getLowerInfo(new_index)->addDefPermuteFactor(factor);
+ }
+
+ const auto replaced_input = _replace_operands_map[key];
+ // Update op_seq
+ if (_graph.subgraphs().at(subgraph_index).getInputs().contains(input))
+ {
+ _graph.subgraphs().at(subgraph_index).replaceInput(input, replaced_input);
+ }
+
+ // Update node
+ node.replaceInput(input, replaced_input);
+
+ // Update operand
+ auto &replaced_object = _graph.operands().at(replaced_input);
+ replaced_object.appendUse(node_index);
+
+ // Update lower_info
+ auto replaced_lower_info = _graph.getLowerInfo(replaced_input);
+ replaced_lower_info->addUsePermuteFactor(factor);
+
+ // Remove this node from def and uses of origin operand
+ if (object.getDef().contains(node_index))
+ {
+ object.removeDef(node_index);
+ }
+ object.removeUse(node_index);
+
+ // Remove origin operand
+ if (object.getDef().size() == 0 && object.getUses().size() == 0)
+ {
+ _graph.removeOperand(input);
+ _graph.removeLowerInfo(input);
+ }
+ }
+ }
+
+ // Now this runtime does not support the node making output as constant
+ for (const auto &output : node.getOutputs())
+ {
+ UNUSED_RELEASE(output);
+ assert(!_graph.operands().at(output).isConstant());
+ }
+}
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/pass/ConstantInsertionPass.h b/runtime/neurun/core/src/ir/pass/ConstantInsertionPass.h
new file mode 100644
index 000000000..40476b20e
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/ConstantInsertionPass.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 __NEURUN_GRAPH_PASS_CONSTANT_INSERTION_PASS_H__
+#define __NEURUN_GRAPH_PASS_CONSTANT_INSERTION_PASS_H__
+
+#include <ir/operand/PermuteFactor.h>
+#include <ir/Index.h>
+#include "OperationPass.h"
+#include <unordered_map>
+#include <utility>
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+class ConstantInsertionPass : public OperationPass
+{
+public:
+ using OperationPass::OperationPass;
+
+public:
+ std::string id() final { return "ConstantInsertionPass"; }
+
+public:
+ void callback(const OperationIndex &index, Operation &node) final;
+
+private:
+ struct ReplaceKey
+ {
+ OperandIndex index;
+ 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<OperandIndex>()(key.index) ^ (hash<operand::PermuteFactor>()(key.factor) << 1);
+ }
+ };
+
+ std::unordered_map<ReplaceKey, OperandIndex, KeyHasher> _replace_operands_map;
+};
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_CONSTANT_INSERTION_PASS_H__
diff --git a/runtime/neurun/core/src/ir/pass/OperandPass.cc b/runtime/neurun/core/src/ir/pass/OperandPass.cc
new file mode 100644
index 000000000..f31d0d850
--- /dev/null
+++ b/runtime/neurun/core/src/ir/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 neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+void OperandPass::run()
+{
+ _graph.operands().iterate(
+ [&](const OperandIndex &index, Operand &object) { callback(index, object); });
+}
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/pass/OperandPass.h b/runtime/neurun/core/src/ir/pass/OperandPass.h
new file mode 100644
index 000000000..c9fbf541d
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/OperandPass.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_GRAPH_PASS_OPERAND_PASS_H__
+#define __NEURUN_GRAPH_PASS_OPERAND_PASS_H__
+
+#include "Pass.h"
+#include "ir/Index.h"
+
+namespace neurun
+{
+namespace ir
+{
+class Operand;
+} // namespace ir
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+class OperandPass : public Pass
+{
+public:
+ using Pass::Pass;
+
+public:
+ std::string id() override = 0;
+ void run() override final;
+ virtual void callback(const OperandIndex &i, Operand &o) = 0;
+};
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_OPERAND_PASS_H__
diff --git a/runtime/neurun/core/src/ir/pass/OperationPass.cc b/runtime/neurun/core/src/ir/pass/OperationPass.cc
new file mode 100644
index 000000000..c9438ee39
--- /dev/null
+++ b/runtime/neurun/core/src/ir/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 neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+void OperationPass::run()
+{
+ _graph.operations().iterate(
+ [&](const OperationIndex &index, Operation &node) { callback(index, node); });
+}
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/pass/OperationPass.h b/runtime/neurun/core/src/ir/pass/OperationPass.h
new file mode 100644
index 000000000..4b7de7109
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/OperationPass.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file OperationPass.h
+ * @brief This file contains OperationPass class
+ */
+
+#ifndef __NEURUN_GRAPH_PASS_OPERATION_PASS_H__
+#define __NEURUN_GRAPH_PASS_OPERATION_PASS_H__
+
+#include "Pass.h"
+#include "ir/Index.h"
+
+namespace neurun
+{
+namespace ir
+{
+class Operation;
+} // namespace ir
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+/**
+ * @brief Class to iterate over operations and calls callback() method
+ */
+class OperationPass : public Pass
+{
+public:
+ using Pass::Pass;
+
+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 OperationIndex &index, Operation &node) = 0;
+
+ /**
+ * @brief Run the pass
+ */
+ void run() final;
+};
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_OPERATION_PASS_H__
diff --git a/runtime/neurun/core/src/ir/pass/Pass.h b/runtime/neurun/core/src/ir/pass/Pass.h
new file mode 100644
index 000000000..0aa0f36a6
--- /dev/null
+++ b/runtime/neurun/core/src/ir/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 __NEURUN_GRAPH_PASS_PASS_H__
+#define __NEURUN_GRAPH_PASS_PASS_H__
+
+#include <string>
+
+namespace neurun
+{
+namespace ir
+{
+class Graph;
+} // namespace ir
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+class Pass
+{
+public:
+ Pass(Graph &graph) : _graph{graph} {}
+ virtual ~Pass() = default;
+
+public:
+ virtual std::string id() = 0;
+ virtual void run() = 0;
+
+protected:
+ Graph &_graph;
+};
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_PASS_H__
diff --git a/runtime/neurun/core/src/ir/pass/PermutationEliminationPass.cc b/runtime/neurun/core/src/ir/pass/PermutationEliminationPass.cc
new file mode 100644
index 000000000..71f3d7e82
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/PermutationEliminationPass.cc
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "ir/Operand.h"
+#include "ir/operand/LowerInfo.h"
+#include "ir/Graph.h"
+#include "backend/IConfig.h"
+#include "util/logging.h"
+#include "compiler/BackendResolver.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+void PermutationEliminationPass::callback(const OperandIndex &inp_index, Operand &object)
+{
+ if (_graph.getInputs().contains(inp_index))
+ {
+ eliminateInput(inp_index, object);
+ }
+ else if (_graph.getOutputs().contains(inp_index))
+ {
+ eliminateOutput(inp_index, object);
+ }
+}
+
+void PermutationEliminationPass::eliminateInput(const OperandIndex &inp_index, Operand &object)
+{
+ auto &model_inputs = _graph.getInputs();
+
+ // get uses of the model's given input
+ auto uses = object.getUses();
+
+ // input must be used just by permutation
+ if (uses.size() != 1)
+ {
+ return;
+ }
+
+ for (auto input_use : uses.list())
+ {
+ auto &perm_operation = _graph.operations().at(input_use);
+ auto perm_inputs = perm_operation.getInputs();
+
+ auto perm_outputs = perm_operation.getOutputs();
+
+ if (!isPermuteLayerToEliminate(perm_inputs, perm_outputs, true))
+ {
+ return;
+ }
+
+ assert(perm_inputs.at(0) == inp_index);
+
+ VERBOSE(PermutationEliminationPass::EliminateInput) << "remove NHWC_TO_NCHW permutation\n";
+
+ // set model's new input, which was output of permutation
+ model_inputs.replace(inp_index, perm_outputs.at(0));
+
+ // remove model's input, which is also input of permutation
+ _graph.removeOperand(inp_index);
+
+ // remove permutation operation
+ assert(_graph.subgraphs().containsOperation(input_use));
+ auto subg_idx = _graph.subgraphs().getOperation(input_use);
+ _graph.subgraphs().remove(subg_idx);
+ _graph.operations().remove(input_use);
+
+ VERBOSE(PermutationEliminationPass::EliminateInput)
+ << inp_index.value() << " is model's input and is removed. New input is "
+ << perm_outputs.at(0).value() << "\n"
+ << input_use.value() << " is removed permutation operation\n";
+ }
+}
+
+void PermutationEliminationPass::eliminateOutput(const OperandIndex &out_index, Operand &object)
+{
+ auto &model_outputs = _graph.getOutputs();
+
+ // get defs of the model's given output
+ auto defs = object.getDef();
+
+ // output must use just permutation
+ if (defs.size() != 1)
+ {
+ return;
+ }
+
+ for (auto output_def : defs.list())
+ {
+ auto &perm_operation = _graph.operations().at(output_def);
+ auto perm_outputs = perm_operation.getOutputs();
+
+ auto perm_inputs = perm_operation.getInputs();
+ if (!isPermuteLayerToEliminate(perm_inputs, perm_outputs, false))
+ {
+ return;
+ }
+
+ assert(perm_outputs.at(0) == out_index);
+
+ VERBOSE(PermutationEliminationPass::EliminateOutput) << "remove NCHW_TO_NHWC permutation\n";
+
+ // Update operations' output that is used by permute operand
+ for (auto perm_input_index : perm_inputs)
+ {
+ auto &perm_input_operand = _graph.operands().at(perm_input_index);
+ perm_input_operand.removeUse(output_def);
+ }
+
+ // set model's new output, which was input of permutation
+ model_outputs.replace(out_index, perm_inputs.at(0));
+
+ // remove model's output, which is also output of permutation
+ _graph.removeOperand(out_index);
+
+ // remove permutation operation
+ assert(_graph.subgraphs().containsOperation(output_def));
+ auto subg_idx = _graph.subgraphs().getOperation(output_def);
+ _graph.subgraphs().remove(subg_idx);
+ _graph.operations().remove(output_def);
+
+ VERBOSE(PermutationEliminationPass::EliminateOutput)
+ << out_index.value() << " is model's output and is removed. New output is "
+ << perm_inputs.at(0).value() << "\n"
+ << output_def.value() << " is removed permutation operation\n";
+ }
+}
+
+bool PermutationEliminationPass::isPermuteLayerToEliminate(const OperandIndexSequence &inp_indexes,
+ const OperandIndexSequence &out_indexes,
+ bool is_for_model_input)
+{
+ auto input_def_factors = _graph.getLowerInfo(inp_indexes.at(0))->def_factors();
+ auto output_def_factors = _graph.getLowerInfo(out_indexes.at(0))->def_factors();
+
+ auto input_layout = input_def_factors.getOnlyElement().layout();
+ auto output_layout = output_def_factors.getOnlyElement().layout();
+
+ if (input_def_factors.size() != 1 || output_def_factors.size() != 1)
+ {
+ return false;
+ }
+
+ // all operands' factor must be the same
+ for (auto index : inp_indexes)
+ {
+ auto op_factor_set = _graph.getLowerInfo(index)->def_factors();
+ if (op_factor_set.size() != 1 ||
+ input_layout != _graph.getLowerInfo(index)->def_factors().getOnlyElement().layout())
+ {
+ return false;
+ }
+ }
+ // all operands' factor must be the same
+ for (auto index : out_indexes)
+ {
+ auto op_factor_set = _graph.getLowerInfo(index)->def_factors();
+ if (op_factor_set.size() != 1 ||
+ output_layout != _graph.getLowerInfo(index)->def_factors().getOnlyElement().layout())
+ {
+ return false;
+ }
+ }
+
+ if (is_for_model_input)
+ {
+ // check if this is NHWC_TO_NCHW permutation: must have single input, which is model's input
+ return (inp_indexes.size() == 1 && input_layout == Layout::NHWC &&
+ output_layout == Layout::NCHW);
+ }
+
+ // check if this is NCHW_TO_NHWC permutation: must have single output, which is model's output
+ return (out_indexes.size() == 1 && input_layout == Layout::NCHW && output_layout == Layout::NHWC);
+}
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/pass/PermutationEliminationPass.h b/runtime/neurun/core/src/ir/pass/PermutationEliminationPass.h
new file mode 100644
index 000000000..4431eabbc
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/PermutationEliminationPass.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__
+#define __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__
+
+#include "OperandPass.h"
+#include "ir/Operand.h"
+#include "ir/OperandIndexSequence.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+class PermutationEliminationPass : public OperandPass
+{
+public:
+ using OperandPass::OperandPass;
+
+public:
+ std::string id() override { return "PermutationEliminationPass"; }
+
+ void callback(const OperandIndex &index, Operand &object) override;
+
+private:
+ /**
+ * @brief Remove Permute operation that permutates input
+ *
+ * Note: This function aslo removes model's input and
+ * sets output of permutation as model's new input
+ *
+ * @param inp_index is the target operand index for the elimination
+ * @param object is the target operand object for the elimination
+ *
+ * @return
+ */
+ void eliminateInput(const OperandIndex &inp_index, Operand &object);
+
+ /**
+ * @brief Remove Permute operation that permutates output of a model
+ *
+ * Note: This function aslo removes model's output and
+ * sets input of permutation as model's new output
+ *
+ * @param out_index is the target operand index for the elimination
+ * @param object is the target operand object for the elimination
+ *
+ * @return
+ */
+ void eliminateOutput(const OperandIndex &out_index, Operand &object);
+
+ /**
+ * @brief Determine if passed operands are permute layer's input and output, that must be
+ * eliminated
+ *
+ * @param inp_index indexes of the input operand to operation
+ * @param out_index indexes of the output operand to operation
+ * @param is_for_model_input checking for model's input or output
+ *
+ * @return if it is permutation layer
+ */
+ bool isPermuteLayerToEliminate(const OperandIndexSequence &inp_indexes,
+ const OperandIndexSequence &out_indexes, bool is_for_model_input);
+};
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__
diff --git a/runtime/neurun/core/src/ir/pass/PermutationInsertionPass.cc b/runtime/neurun/core/src/ir/pass/PermutationInsertionPass.cc
new file mode 100644
index 000000000..052e3026a
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/PermutationInsertionPass.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 "PermutationInsertionPass.h"
+
+#include <cassert>
+#include <utility>
+#include <unordered_map>
+
+#include "ir/Operand.h"
+#include "ir/operation/LowerInfo.h"
+#include "ir/Graph.h"
+#include "backend/IConfig.h"
+#include "util/logging.h"
+#include "cpp14/memory.h"
+#include "ir/operation/Permute.h"
+#include "ir/operand/Shape4DConvert.h"
+#include "compiler/BackendResolver.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+void PermutationInsertionPass::callback(const OperandIndex &index, Operand &object)
+{
+ auto &&operand_li = _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<OperationIndex> permute_indexes;
+
+ // Build a map for all necessary type of operands
+ std::unordered_map<operand::PermuteFactor, 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);
+ VERBOSE(PermutationInsertionPass) << "Insert 'Permute' operation for operand "
+ << index.value() << std::endl;
+ 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<OperationIndex> remove_list;
+
+ auto uses = object.getUses();
+ for (auto use : uses.list())
+ {
+ // 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(_graph.subgraphs().containsOperation(use));
+ auto subg_index = _graph.subgraphs().getOperation(use);
+ auto subg_li = _graph.getLowerInfo(subg_index);
+ assert(subg_li);
+ const auto subg_layout = subg_li->layout();
+ const backend::Backend *backend = subg_li->backend();
+ assert(backend);
+ auto use_node_inputs = operation.getInputs();
+ assert(use_node_inputs.contains(index));
+
+ auto new_index = factor_to_index.at({backend, subg_layout});
+ if (index != new_index)
+ {
+ // Update from op_seq
+ _graph.subgraphs().at(subg_index).replaceInput(index, new_index);
+
+ // Update from operation
+ operation.replaceInput(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).appendUse(use);
+ }
+ }
+
+ for (auto &operation : remove_list)
+ {
+ object.removeUse(operation);
+ }
+ }
+}
+
+OperationIndex PermutationInsertionPass::insertPermute(const OperandIndex &operand_index,
+ const 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_backend = _graph.getLowerInfo(operand_index)->def_factors().getOnlyElement().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 = Layout::UNKNOWN;
+ const auto permute_node_backend = backend::BackendManager::get().getDefault();
+ const operand::PermuteFactor permute_node_factor{permute_node_backend, permute_node_layout};
+
+ // Update LowerInfo of input operand
+ auto operand_lower_info = _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 =
+ nnfw::cpp14::make_unique<operand::LowerInfo>(operand::asShape4D(operand.shape()));
+
+ // 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);
+ _graph.setLowerInfo(out_operand_index, std::move(out_operand_li));
+
+ auto input_backend_ctx = _graph.backend_resolver()->getBackendContext(input_backend);
+ auto output_backend_ctx = _graph.backend_resolver()->getBackendContext(output_backend);
+
+ // Insert permute operation to the graph
+ const auto input_layout =
+ _graph.getLowerInfo(operand_index)->def_factors().getOnlyElement().layout();
+ const auto output_layout = factor.layout();
+ using Permute = operation::Permute;
+ const auto permute_type = [&]() {
+ if (input_layout == Layout::NHWC && output_layout == Layout::NCHW)
+ {
+ return Permute::Type::NHWC_TO_NCHW;
+ }
+ else if (input_layout == Layout::NCHW && output_layout == Layout::NHWC)
+ {
+ return Permute::Type::NCHW_TO_NHWC;
+ }
+ else
+ {
+ return Permute::Type::COPY;
+ }
+ }();
+ auto insert_node = nnfw::cpp14::make_unique<Permute>(
+ operand_index, out_operand_index, input_backend_ctx, output_backend_ctx, permute_type);
+
+ auto node_index = _graph.operations().push(std::move(insert_node));
+ const auto &node = _graph.operations().at(node_index);
+
+ // OpSequence
+ {
+ auto subg_index = _graph.subgraphs().emplace(node_index, node, permute_node_layout);
+ auto &subg = _graph.subgraphs().at(subg_index);
+ subg.setInputs(node.getInputs());
+ subg.setOutputs(node.getOutputs());
+ _graph.setLowerInfo(subg_index, nnfw::cpp14::make_unique<operation::LowerInfo>(
+ permute_node_backend, permute_node_layout));
+ }
+
+ // Update Use/Def info
+ {
+ _graph.operands().at(operand_index).appendUse(node_index);
+ _graph.operands().at(out_operand_index).appendDef(node_index);
+ }
+ return node_index;
+}
+} // namespace pass
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/pass/PermutationInsertionPass.h b/runtime/neurun/core/src/ir/pass/PermutationInsertionPass.h
new file mode 100644
index 000000000..4065fc6ac
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/PermutationInsertionPass.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__
+#define __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__
+
+#include "OperandPass.h"
+#include "ir/Operand.h" //for OperationIndex
+#include "backend/BackendManager.h"
+#include "ir/operand/PermuteFactor.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+class PermutationInsertionPass : public OperandPass
+{
+public:
+ using OperandPass::OperandPass;
+
+public:
+ std::string id() override { return "PermutationInsertionPass"; }
+ void callback(const OperandIndex &index, Operand &object) override;
+
+ /**
+ * @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 OperationIndex
+ */
+ OperationIndex insertPermute(const OperandIndex &operand_index,
+ const operand::PermuteFactor &factor);
+
+private:
+};
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__
diff --git a/runtime/neurun/core/src/ir/pass/PermutationOperationPass.cc b/runtime/neurun/core/src/ir/pass/PermutationOperationPass.cc
new file mode 100644
index 000000000..41a1ad903
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/PermutationOperationPass.cc
@@ -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.
+ */
+
+#include "PermutationOperationPass.h"
+
+#include "backend/Backend.h"
+#include "backend/IConfig.h"
+#include "ir/Graph.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+void PermutationOperationPass::callback(const OperationIndex &, Operation &node)
+{
+ node.accept(*this);
+};
+
+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().size() == 1);
+ const auto &node_index = output_obj.getDef().list().front();
+ const auto &subg_index = _graph.subgraphs().getOperation(node_index);
+
+ const auto frontend_layout = _graph.subgraphs().at(subg_index).getLayout();
+ const auto backend_layout = _graph.getLowerInfo(subg_index)->layout();
+
+ if (frontend_layout == backend_layout)
+ {
+ return;
+ }
+
+ // CPU supports only NHWC now
+ if (_graph.getLowerInfo(subg_index)->backend()->config()->id() != "cpu")
+ {
+ // TODO Change backend of this node
+ assert(frontend_layout == Layout::NHWC || backend_layout == Layout::UNKNOWN);
+ }
+
+ // Divide op_seq based on target operation
+ {
+ auto &above_subg = _graph.subgraphs().at(subg_index);
+
+ // 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 = above_subg.begin();
+ // Find iterator of target node in op_seq
+ while ((it++)->index != node_index)
+ ;
+ if (it != above_subg.end())
+ {
+ const auto &below_subg_index =
+ _graph.subgraphs().emplace(it->index, *it->node, above_subg.getLayout());
+ auto &below_subg = _graph.subgraphs().at(below_subg_index);
+ below_subg.setInputs(it->node->getInputs());
+ below_subg.setOutputs(it->node->getOutputs());
+
+ std::vector<OperationIndex> remove_list;
+ remove_list.emplace_back(it->index);
+ while (++it != above_subg.end())
+ {
+ below_subg.appendOperation(it->index, *it->node);
+ below_subg.setOutputs(it->node->getOutputs());
+ remove_list.emplace_back(it->index);
+ }
+
+ above_subg.setOutputs(node.getOutputs());
+ for (const auto &index : remove_list)
+ {
+ above_subg.remove(index);
+ }
+
+ const auto subg_li = _graph.getLowerInfo(subg_index);
+ _graph.setLowerInfo(below_subg_index, nnfw::cpp14::make_unique<operation::LowerInfo>(
+ subg_li->backend(), subg_li->layout()));
+ }
+ }
+
+ // Remove target operation from op_seq and insert the target operation to new op_seq
+ {
+ const auto backend = _graph.getLowerInfo(subg_index)->backend();
+
+ // Remove target operation from subraph
+ _graph.subgraphs().removeFromSubgraph(node_index);
+
+ if (!_graph.subgraphs().exist(subg_index))
+ {
+ // Remove lowerinfo for op_seq of target operation if the op_seq does not exist
+ _graph.removeLowerInfo(subg_index);
+ }
+ else
+ {
+ // Update op_seq of target operation if the op_seq exists
+ auto &above_subg = _graph.subgraphs().at(subg_index);
+ const auto last_node = (--above_subg.end())->node;
+ above_subg.setOutputs(last_node->getOutputs());
+ }
+
+ // Create new op_seq and set information to the op_seq
+ auto new_subg_index = _graph.subgraphs().emplace(node_index, node, frontend_layout);
+ auto &new_subg = _graph.subgraphs().at(new_subg_index);
+ new_subg.setInputs(node.getInputs());
+ new_subg.setOutputs(node.getOutputs());
+ _graph.setLowerInfo(new_subg_index,
+ nnfw::cpp14::make_unique<operation::LowerInfo>(backend, frontend_layout));
+ }
+
+ // Change PermuteFactors of operands of target node
+ {
+ const auto &subg_index = _graph.subgraphs().getOperation(node_index);
+ const auto subg_li = _graph.getLowerInfo(subg_index);
+ const auto backend = subg_li->backend();
+ const operand::PermuteFactor removed_factor{backend, backend_layout};
+ const operand::PermuteFactor new_factor{backend, frontend_layout};
+ for (const auto &input : node.getInputs())
+ {
+ bool canRemove = true;
+ for (const auto &use : _graph.operands().at(input).getUses().list())
+ {
+ if (use != node_index)
+ {
+ const auto &use_subg_index = _graph.subgraphs().getOperation(use);
+ auto use_subg_li = _graph.getLowerInfo(use_subg_index);
+ if (use_subg_li->backend() == backend && use_subg_li->layout() == backend_layout)
+ {
+ canRemove = false;
+ break;
+ }
+ }
+ }
+
+ auto lower_info = _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().size() == 0)
+ {
+ 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())
+ {
+ auto lower_info = _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 operation::FullyConnected &node)
+{
+ const auto &input_ind = node.getInputs().at(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 operation::Gather &node)
+{
+ const auto &input_ind = node.getInputs().at(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 operation::Reshape &node)
+{
+ const auto &input_ind = node.getInputs().at(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 ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/pass/PermutationOperationPass.h b/runtime/neurun/core/src/ir/pass/PermutationOperationPass.h
new file mode 100644
index 000000000..896e0176a
--- /dev/null
+++ b/runtime/neurun/core/src/ir/pass/PermutationOperationPass.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_GRAPH_PASS_PERMUTATION_OPERATION_PASS_H__
+#define __NEURUN_GRAPH_PASS_PERMUTATION_OPERATION_PASS_H__
+
+#include "ir/OperationVisitor.h"
+#include "OperationPass.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace pass
+{
+
+class PermutationOperationPass : public OperationPass, public OperationVisitor
+{
+public:
+ using OperationPass::OperationPass;
+
+public:
+ std::string id() final { return "PermutationOperationPass"; }
+
+public:
+ void callback(const OperationIndex &i, Operation &n) final;
+
+public:
+ void visit(const operation::FullyConnected &) final;
+ void visit(const operation::Gather &) final;
+ void visit(const operation::Reshape &) final;
+
+private:
+ void changeToKeepLayout(const Operation &);
+};
+
+} // namespace pass
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_PERMUTATION_OPERATION_PASS_H__
diff --git a/runtime/neurun/core/src/ir/verifier/Verifier.cc b/runtime/neurun/core/src/ir/verifier/Verifier.cc
new file mode 100644
index 000000000..7bd8ac512
--- /dev/null
+++ b/runtime/neurun/core/src/ir/verifier/Verifier.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Verifier.h"
+
+#include "ir/Graph.h"
+#include "ir/OperationIndexMap.h"
+
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace ir
+{
+namespace verifier
+{
+
+//
+// DAGChecker
+//
+
+bool DAGChecker::verify(const Graph &graph) const
+{
+ 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())
+ {
+ const auto &operand = graph.operands().at(output);
+ for (const auto &use : operand.getUses().list())
+ {
+ 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
+{
+ auto &operations = graph.operations();
+ uint32_t mismatches = 0;
+ operations.iterate([&](const OperationIndex &index, const Operation &node) {
+ for (auto operand_index : node.getInputs())
+ {
+ auto &operand = graph.operands().at(operand_index);
+ mismatches += (operand.getUses().contains(index) ? 0 : 1);
+ }
+ for (auto operand_index : node.getOutputs())
+ {
+ auto &operand = graph.operands().at(operand_index);
+ mismatches += (operand.getDef().contains(index) ? 0 : 1);
+ }
+ });
+ return mismatches == 0;
+}
+
+} // namespace verifier
+} // namespace ir
+} // namespace neurun
diff --git a/runtime/neurun/core/src/ir/verifier/Verifier.h b/runtime/neurun/core/src/ir/verifier/Verifier.h
new file mode 100644
index 000000000..0993a239e
--- /dev/null
+++ b/runtime/neurun/core/src/ir/verifier/Verifier.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NEURUN_GRAPH_VERIFIER_VERIFIER_H__
+#define __NEURUN_GRAPH_VERIFIER_VERIFIER_H__
+
+namespace neurun
+{
+namespace ir
+{
+class Graph;
+} // namespace ir
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+namespace verifier
+{
+
+struct IVerifier
+{
+ virtual ~IVerifier() = default;
+ virtual bool verify(const Graph &graph) const = 0;
+};
+
+} // namespace verifier
+} // namespace ir
+} // namespace neurun
+
+namespace neurun
+{
+namespace ir
+{
+namespace verifier
+{
+
+class DAGChecker : public IVerifier
+{
+public:
+ bool verify(const Graph &graph) const override;
+};
+
+class EdgeConsistencyChecker : public IVerifier
+{
+public:
+ bool verify(const Graph &graph) const override;
+};
+
+} // namespace verifier
+} // namespace ir
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_VERIFIER_VERIFIER_H__
diff --git a/runtime/neurun/core/src/library_info.cc b/runtime/neurun/core/src/library_info.cc
new file mode 100644
index 000000000..601d09185
--- /dev/null
+++ b/runtime/neurun/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=neurun";
diff --git a/runtime/neurun/core/src/util/ConfigSource.cc b/runtime/neurun/core/src/util/ConfigSource.cc
new file mode 100644
index 000000000..7d57ec178
--- /dev/null
+++ b/runtime/neurun/core/src/util/ConfigSource.cc
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "cpp14/memory.h"
+
+namespace neurun
+{
+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 = nnfw::cpp14::make_unique<EnvConfigSource>();
+#else
+ _source = nnfw::cpp14::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 getConfigBool(const std::string &key)
+{
+ auto raw = getConfigOrDefault(key);
+ 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(), raw);
+
+ return (false_found == false_list.end());
+}
+
+int getConfigInt(const std::string &key)
+{
+ auto raw = getConfigOrDefault(key);
+ return std::stoi(raw);
+}
+
+std::string getConfigString(const std::string &key) { return getConfigOrDefault(key); }
+
+} // namespace util
+} // namespace neurun
+
+namespace neurun
+{
+namespace util
+{
+namespace config
+{
+
+#define CONFIG(Name, Type, Default) const char *Name = #Name;
+
+#include "util/Config.lst"
+
+#undef CONFIG
+
+} // namespace config
+} // namespace util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/EnvConfigSource.cc b/runtime/neurun/core/src/util/EnvConfigSource.cc
new file mode 100644
index 000000000..52a6bf2a4
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/util/EventCollectorGlobal.cc b/runtime/neurun/core/src/util/EventCollectorGlobal.cc
new file mode 100644
index 000000000..6c3594f5f
--- /dev/null
+++ b/runtime/neurun/core/src/util/EventCollectorGlobal.cc
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/EventCollectorGlobal.h"
+
+#include <cassert>
+#include <fstream>
+
+#include "util/ConfigSource.h"
+
+namespace neurun
+{
+namespace util
+{
+
+EventCollectorGlobal::EventCollectorGlobal() : _recorder{}, _collector{&_recorder}
+{
+ // DO NOTHING
+}
+
+EventCollectorGlobal::~EventCollectorGlobal()
+{
+ auto path = util::getConfigString(util::config::TRACE_FILEPATH);
+ if (!path.empty())
+ {
+ // TODO Need better way for saved file path than just appending ".global" to the trace file path
+ std::ofstream ofs{path + ".global"};
+ _recorder.writeToFile(ofs);
+ }
+}
+
+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 neurun
diff --git a/runtime/neurun/core/src/util/GeneralConfigSource.cc b/runtime/neurun/core/src/util/GeneralConfigSource.cc
new file mode 100644
index 000000000..084e4c109
--- /dev/null
+++ b/runtime/neurun/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 neurun
+{
+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 neurun
diff --git a/runtime/neurun/core/src/util/Padding.cc b/runtime/neurun/core/src/util/Padding.cc
new file mode 100644
index 000000000..2e2202b58
--- /dev/null
+++ b/runtime/neurun/core/src/util/Padding.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/Padding.h"
+#include "util/Utils.h"
+
+#include <algorithm>
+#include <stdexcept>
+
+namespace neurun
+{
+namespace util
+{
+
+ir::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.
+ //
+ ir::ExplicitPadding padding;
+
+ padding.top = 0;
+ padding.bottom = 0;
+ padding.left = 0;
+ padding.right = 0;
+
+ return padding;
+}
+
+ir::ExplicitPadding samePaddingUsingIFM(const ir::FeatureShape &ifm_shape, const ir::Stride &stride,
+ uint32_t kw, uint32_t kh)
+{
+ ir::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 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 + kh;
+ 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 + kw;
+ 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;
+}
+
+ir::ExplicitPadding samePadding(const ir::FeatureShape &ifm_shape,
+ const ir::FeatureShape &ofm_shape, const ir::Stride &stride,
+ uint32_t kw, uint32_t kh)
+{
+ 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);
+}
+
+ir::ExplicitPadding calculatePadding(const ir::Padding &padding, const ir::FeatureShape &ifm_shape,
+ const ir::FeatureShape &ofm_shape, const ir::Stride &stride,
+ uint32_t kw, uint32_t kh)
+{
+ if (padding.type == ir::PaddingType::EXPLICIT)
+ {
+ return padding.param;
+ }
+ else if (padding.type == ir::PaddingType::SAME)
+ {
+ return samePadding(ifm_shape, ofm_shape, stride, kw, kh);
+ }
+ else if (padding.type == ir::PaddingType::VALID)
+ {
+ return validPadding();
+ }
+ else
+ {
+ throw std::runtime_error{"Cannot handle padding type"};
+ }
+}
+
+} // namespace util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/ShapeInference.cc b/runtime/neurun/core/src/util/ShapeInference.cc
new file mode 100644
index 000000000..6fa29e7d8
--- /dev/null
+++ b/runtime/neurun/core/src/util/ShapeInference.cc
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "ir/operation/AvgPool2D.h"
+#include "ir/operation/MaxPool2D.h"
+#include "util/ShapeInference.h"
+
+namespace neurun
+{
+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;
+}
+
+// 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)
+{
+ int32_t out_h = 0, out_w = 0;
+
+ 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 - ker_h + 1, stride.vertical);
+ out_w = ceil_div(in_w - ker_w + 1, stride.horizontal);
+ break;
+ case ir::PaddingType::EXPLICIT:
+ out_h = (in_h + pad.param.top + pad.param.bottom - ker_h) / stride.vertical + 1;
+ out_w = (in_w + pad.param.left + pad.param.right - ker_w) / stride.horizontal + 1;
+ break;
+ default:
+ assert(false);
+ }
+
+ return {out_h, out_w};
+}
+
+} // namespace
+
+//
+// Shape inference
+//
+
+Shapes inferEltwiseShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape)
+{
+ return {broadcastShapes(lhs_shape, rhs_shape)};
+}
+
+Shapes inferAvgPoolShape(const ir::Shape &in_shape, const ir::operation::AvgPool2D::Param &param,
+ const ir::Layout layout)
+{
+ 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}};
+}
+
+Shapes inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param &param)
+{
+ const int32_t concat_axis = 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)
+ {
+ assert(in_shape.rank() == first_in_shape.rank());
+ for (int64_t dim_idx = 0; dim_idx < in_shape.rank(); ++dim_idx)
+ assert(dim_idx == concat_axis || in_shape.dim(dim_idx) == first_in_shape.dim(dim_idx));
+ }
+
+ // 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};
+}
+
+Shapes inferMaxPoolShape(const ir::Shape &in_shape, const ir::operation::MaxPool2D::Param &param,
+ const ir::Layout layout)
+{
+ 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}};
+}
+
+Shapes inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::Conv2D::Param &param, ir::Layout layout)
+{
+ assert(layout == ir::Layout::NHWC);
+ 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);
+
+ return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.N}};
+}
+
+Shapes inferDepthwiseConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape,
+ const ir::operation::DepthwiseConv2D::Param &param,
+ ir::Layout layout)
+{
+ 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);
+
+ return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.C}};
+}
+
+Shapes 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})}};
+}
+
+} // namespace shape_inference
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/Utils.cc b/runtime/neurun/core/src/util/Utils.cc
new file mode 100644
index 000000000..1e24e28d4
--- /dev/null
+++ b/runtime/neurun/core/src/util/Utils.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util/Utils.h"
+
+#include <cassert>
+
+namespace neurun
+{
+namespace util
+{
+
+const char *to_string(const ir::PaddingType type)
+{
+ assert((type == ir::PaddingType::EXPLICIT) || (type == ir::PaddingType::SAME) ||
+ (type == ir::PaddingType::VALID));
+
+ switch (type)
+ {
+ case ir::PaddingType::EXPLICIT:
+ return "Padding::EXPLICIT";
+ case ir::PaddingType::SAME:
+ return "Padding::SAME";
+ case ir::PaddingType::VALID:
+ return "Padding::VALID";
+ }
+
+ return nullptr;
+}
+
+Coordinates convertCoordinates(const Coordinates &from_coordinates, ir::Layout from_layout,
+ ir::Layout to_layout)
+{
+ assert(from_coordinates.size() == 4);
+ Coordinates to{from_coordinates};
+ if (from_layout == ir::Layout::NHWC && to_layout == ir::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 == ir::Layout::NCHW && to_layout == ir::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 util
+} // namespace neurun
diff --git a/runtime/neurun/core/src/util/logging.cc b/runtime/neurun/core/src/util/logging.cc
new file mode 100644
index 000000000..c23e2b53c
--- /dev/null
+++ b/runtime/neurun/core/src/util/logging.cc
@@ -0,0 +1,7 @@
+#include "util/logging.h"
+
+neurun::util::logging::Context &neurun::util::logging::Context::get() noexcept
+{
+ static Context ctx;
+ return ctx;
+}