summaryrefslogtreecommitdiff
path: root/compiler/moco
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/moco')
-rw-r--r--compiler/moco/CMakeLists.txt5
-rw-r--r--compiler/moco/README.md3
-rw-r--r--compiler/moco/import/CMakeLists.txt26
-rw-r--r--compiler/moco/import/README.md3
-rw-r--r--compiler/moco/import/include/moco/GraphHelper.h59
-rw-r--r--compiler/moco/import/include/moco/Import/GraphBuilder.h40
-rw-r--r--compiler/moco/import/include/moco/Import/GraphBuilderContext.h144
-rw-r--r--compiler/moco/import/include/moco/Import/GraphBuilderRegistry.h87
-rw-r--r--compiler/moco/import/include/moco/Import/ModelSignature.h80
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes.h53
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Add.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/AvgPool.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/BiasAdd.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Concat.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Const.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Conv2D.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Conv2DBackpropInput.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/DepthwiseConv2dNative.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/FakeQuantWithMinMaxVars.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/FusedBatchNorm.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Identity.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/MaxPool.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Maximum.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Mean.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Mul.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Pack.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Pad.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Placeholder.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/RealDiv.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Relu.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Relu6.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Reshape.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Rsqrt.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Shape.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Softmax.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Sqrt.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/SquaredDifference.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Squeeze.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/StopGradient.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/StridedSlice.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Sub.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Tanh.h37
-rw-r--r--compiler/moco/import/include/moco/Importer.h54
-rw-r--r--compiler/moco/import/src/Convert.cpp34
-rw-r--r--compiler/moco/import/src/Convert.h31
-rw-r--r--compiler/moco/import/src/GraphBuilderContext.cpp80
-rw-r--r--compiler/moco/import/src/GraphBuilderContext.test.cpp77
-rw-r--r--compiler/moco/import/src/GraphBuilderRegistry.cpp63
-rw-r--r--compiler/moco/import/src/Importer.cpp197
-rw-r--r--compiler/moco/import/src/Importer.test.cpp223
-rw-r--r--compiler/moco/import/src/ModelSignature.cpp66
-rw-r--r--compiler/moco/import/src/Nodes/Add.cpp85
-rw-r--r--compiler/moco/import/src/Nodes/Add.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/AvgPool.cpp140
-rw-r--r--compiler/moco/import/src/Nodes/AvgPool.test.cpp99
-rw-r--r--compiler/moco/import/src/Nodes/BiasAdd.cpp122
-rw-r--r--compiler/moco/import/src/Nodes/BiasAdd.test.cpp112
-rw-r--r--compiler/moco/import/src/Nodes/Concat.cpp109
-rw-r--r--compiler/moco/import/src/Nodes/Concat.test.cpp134
-rw-r--r--compiler/moco/import/src/Nodes/Const.cpp242
-rw-r--r--compiler/moco/import/src/Nodes/Const.test.cpp465
-rw-r--r--compiler/moco/import/src/Nodes/Conv2D.cpp139
-rw-r--r--compiler/moco/import/src/Nodes/Conv2D.test.cpp119
-rw-r--r--compiler/moco/import/src/Nodes/Conv2DBackpropInput.cpp140
-rw-r--r--compiler/moco/import/src/Nodes/Conv2DBackpropInput.test.cpp98
-rw-r--r--compiler/moco/import/src/Nodes/DepthwiseConv2dNative.cpp148
-rw-r--r--compiler/moco/import/src/Nodes/DepthwiseConv2dNative.test.cpp97
-rw-r--r--compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.cpp123
-rw-r--r--compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.test.cpp65
-rw-r--r--compiler/moco/import/src/Nodes/FusedBatchNorm.cpp102
-rw-r--r--compiler/moco/import/src/Nodes/FusedBatchNorm.test.cpp88
-rw-r--r--compiler/moco/import/src/Nodes/Identity.cpp95
-rw-r--r--compiler/moco/import/src/Nodes/MaxPool.cpp145
-rw-r--r--compiler/moco/import/src/Nodes/MaxPool.test.cpp98
-rw-r--r--compiler/moco/import/src/Nodes/Maximum.cpp87
-rw-r--r--compiler/moco/import/src/Nodes/Maximum.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Mean.cpp99
-rw-r--r--compiler/moco/import/src/Nodes/Mean.test.cpp120
-rw-r--r--compiler/moco/import/src/Nodes/Mul.cpp85
-rw-r--r--compiler/moco/import/src/Nodes/Mul.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Pack.cpp102
-rw-r--r--compiler/moco/import/src/Nodes/Pack.test.cpp84
-rw-r--r--compiler/moco/import/src/Nodes/Pad.cpp91
-rw-r--r--compiler/moco/import/src/Nodes/Pad.test.cpp65
-rw-r--r--compiler/moco/import/src/Nodes/Placeholder.cpp90
-rw-r--r--compiler/moco/import/src/Nodes/Placeholder.test.cpp71
-rw-r--r--compiler/moco/import/src/Nodes/RealDiv.cpp86
-rw-r--r--compiler/moco/import/src/Nodes/RealDiv.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Relu.cpp86
-rw-r--r--compiler/moco/import/src/Nodes/Relu.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Relu6.cpp80
-rw-r--r--compiler/moco/import/src/Nodes/Relu6.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Reshape.cpp102
-rw-r--r--compiler/moco/import/src/Nodes/Reshape.test.cpp61
-rw-r--r--compiler/moco/import/src/Nodes/Rsqrt.cpp82
-rw-r--r--compiler/moco/import/src/Nodes/Rsqrt.test.cpp57
-rw-r--r--compiler/moco/import/src/Nodes/Shape.cpp100
-rw-r--r--compiler/moco/import/src/Nodes/Shape.test.cpp65
-rw-r--r--compiler/moco/import/src/Nodes/Softmax.cpp86
-rw-r--r--compiler/moco/import/src/Nodes/Softmax.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Sqrt.cpp81
-rw-r--r--compiler/moco/import/src/Nodes/Sqrt.test.cpp57
-rw-r--r--compiler/moco/import/src/Nodes/SquaredDifference.cpp92
-rw-r--r--compiler/moco/import/src/Nodes/SquaredDifference.test.cpp59
-rw-r--r--compiler/moco/import/src/Nodes/Squeeze.cpp112
-rw-r--r--compiler/moco/import/src/Nodes/Squeeze.test.cpp109
-rw-r--r--compiler/moco/import/src/Nodes/StopGradient.cpp87
-rw-r--r--compiler/moco/import/src/Nodes/StopGradient.test.cpp57
-rw-r--r--compiler/moco/import/src/Nodes/StridedSlice.cpp187
-rw-r--r--compiler/moco/import/src/Nodes/StridedSlice.test.cpp107
-rw-r--r--compiler/moco/import/src/Nodes/Sub.cpp85
-rw-r--r--compiler/moco/import/src/Nodes/Sub.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Tanh.cpp81
-rw-r--r--compiler/moco/import/src/Nodes/Tanh.test.cpp57
-rw-r--r--compiler/moco/import/src/TestHelper.h83
-rw-r--r--compiler/moco/import/src/TestHelper.test.cpp101
-rw-r--r--compiler/moco/lang/CMakeLists.txt21
-rw-r--r--compiler/moco/lang/README.md3
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFAdd.h56
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFAvgPool.h101
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFBiasAdd.h68
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFConcatV2.h90
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFConst.h94
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFConv2D.h55
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFConv2DBackpropInput.h102
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFDepthwiseConv2dNative.h56
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFFakeQuantWithMinMaxVars.h54
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFFusedBatchNorm.h55
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFIdentity.h52
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFMaxPool.h101
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFMaximum.h56
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFMean.h71
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFMul.h56
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFPack.h86
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFPad.h61
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFPlaceholder.h90
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFPush.h84
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFRealDiv.h56
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFRelu.h52
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFRelu6.h50
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFReshape.h54
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFRsqrt.h52
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFShape.h60
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFSoftmax.h37
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFSqrt.h52
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFSquaredDifference.h56
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFSqueeze.h71
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFStopGradient.h52
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFStridedSlice.h123
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFSub.h56
-rw-r--r--compiler/moco/lang/include/moco/IR/Nodes/TFTanh.h37
-rw-r--r--compiler/moco/lang/include/moco/IR/TFDataLayout.h29
-rw-r--r--compiler/moco/lang/include/moco/IR/TFDialect.h43
-rw-r--r--compiler/moco/lang/include/moco/IR/TFNode.h23
-rw-r--r--compiler/moco/lang/include/moco/IR/TFNodeDecl.h104
-rw-r--r--compiler/moco/lang/include/moco/IR/TFNodeImpl.h68
-rw-r--r--compiler/moco/lang/include/moco/IR/TFNodeVisitor.forward.h30
-rw-r--r--compiler/moco/lang/include/moco/IR/TFNodeVisitor.h83
-rw-r--r--compiler/moco/lang/include/moco/IR/TFNodes.h55
-rw-r--r--compiler/moco/lang/include/moco/IR/TFNodes.lst48
-rw-r--r--compiler/moco/lang/include/moco/IR/TFOpcode.h35
-rw-r--r--compiler/moco/lang/include/moco/IR/TFPadding.h29
-rw-r--r--compiler/moco/lang/include/moco/IR/VariadicArityNode.h77
-rw-r--r--compiler/moco/lang/include/moco/Names.h96
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFAdd.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFAvgPool.test.cpp34
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFBiasAdd.test.cpp32
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFConcatV2.test.cpp34
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFConst.cpp113
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFConst.test.cpp95
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFConv2D.test.cpp34
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFConv2DBackpropInput.test.cpp35
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFDepthwiseConv2dNative.test.cpp34
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFFakeQuantWithMinMaxVars.test.cpp34
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFFusedBatchNorm.test.cpp35
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFIdentity.test.cpp30
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFMaxPool.test.cpp34
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFMaximum.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFMean.test.cpp32
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFMul.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFPack.test.cpp34
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFPad.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFPlaceholder.test.cpp46
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFRealDiv.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFRelu.test.cpp30
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFRelu6.test.cpp30
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFReshape.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFRsqrt.test.cpp30
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFShape.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFSoftmax.test.cpp30
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFSqrt.test.cpp30
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFSquaredDifference.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFSqueeze.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFStopGradient.test.cpp30
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFStridedSlice.test.cpp38
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFSub.test.cpp31
-rw-r--r--compiler/moco/lang/src/IR/Nodes/TFTanh.test.cpp30
-rw-r--r--compiler/moco/lang/src/IR/TFDialect.cpp91
-rw-r--r--compiler/moco/lang/src/IR/TFDialect.test.cpp29
-rw-r--r--compiler/moco/lang/src/IR/TFNode.cpp137
-rw-r--r--compiler/moco/lang/src/IR/TFNode.test.cpp44
-rw-r--r--compiler/moco/lang/src/IR/VariadicArityNode.test.cpp55
-rw-r--r--compiler/moco/pass/CMakeLists.txt26
-rw-r--r--compiler/moco/pass/README.md3
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes.h32
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldAdd.h41
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldMul.h41
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldPack.h43
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldStridedSlice.h41
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/FuseBinaryIntoPreceding.h41
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/RemoveTFIdentityNode.h49
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/ResolveConstantShape.h41
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/ResolveFusedBatchNorm.h41
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/ResolveReshapeWildcardDim.h42
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/ResolveSquaredDifference.h41
-rw-r--r--compiler/moco/pass/include/moco/Pass/Passes/SqueezeReduceNode.h42
-rw-r--r--compiler/moco/pass/src/ConstantFoldAdd.test.cpp109
-rw-r--r--compiler/moco/pass/src/ConstantFoldHelper.cpp238
-rw-r--r--compiler/moco/pass/src/ConstantFoldHelper.h64
-rw-r--r--compiler/moco/pass/src/ConstantFoldMul.test.cpp109
-rw-r--r--compiler/moco/pass/src/ConstantFoldPack.test.cpp90
-rw-r--r--compiler/moco/pass/src/ConstantFoldStridedSlice.test.cpp268
-rw-r--r--compiler/moco/pass/src/Passes/ConstantFoldAdd.cpp116
-rw-r--r--compiler/moco/pass/src/Passes/ConstantFoldMul.cpp116
-rw-r--r--compiler/moco/pass/src/Passes/ConstantFoldPack.cpp191
-rw-r--r--compiler/moco/pass/src/Passes/ConstantFoldStridedSlice.cpp292
-rw-r--r--compiler/moco/pass/src/Passes/FuseBinaryIntoPreceding.cpp539
-rw-r--r--compiler/moco/pass/src/Passes/RemoveTFIdentityNode.cpp66
-rw-r--r--compiler/moco/pass/src/Passes/ResolveConstantShape.cpp129
-rw-r--r--compiler/moco/pass/src/Passes/ResolveFusedBatchNorm.cpp254
-rw-r--r--compiler/moco/pass/src/Passes/ResolveReshapeWildcardDim.cpp153
-rw-r--r--compiler/moco/pass/src/Passes/ResolveSquaredDifference.cpp97
-rw-r--r--compiler/moco/pass/src/Passes/SqueezeReduceNode.cpp105
-rw-r--r--compiler/moco/pass/src/TensorPackEnumerator.cpp134
-rw-r--r--compiler/moco/pass/src/TensorPackEnumerator.h66
-rw-r--r--compiler/moco/pass/src/TensorSliceEnumerator.cpp84
-rw-r--r--compiler/moco/pass/src/TensorSliceEnumerator.h62
-rw-r--r--compiler/moco/pass/src/TensorSliceEnumerator.test.cpp83
-rw-r--r--compiler/moco/pass/src/TestHelper.h67
-rw-r--r--compiler/moco/pass/src/TestHelper.test.cpp38
-rw-r--r--compiler/moco/requires.cmake8
-rw-r--r--compiler/moco/service/CMakeLists.txt24
-rw-r--r--compiler/moco/service/README.md3
-rw-r--r--compiler/moco/service/include/moco/Service/TFShapeInferenceRule.h38
-rw-r--r--compiler/moco/service/include/moco/Service/TFTypeInferenceRule.h36
-rw-r--r--compiler/moco/service/src/Service/TFShapeInferenceRule.cpp891
-rw-r--r--compiler/moco/service/src/Service/TFShapeInferenceRule.test.cpp500
-rw-r--r--compiler/moco/service/src/Service/TFTypeInferenceRule.cpp113
-rw-r--r--compiler/moco/service/src/TestHelper.h69
-rw-r--r--compiler/moco/service/src/TestHelper.test.cpp38
-rw-r--r--compiler/moco/support/CMakeLists.txt9
-rw-r--r--compiler/moco/support/README.md3
-rw-r--r--compiler/moco/support/include/moco/Support/NodeAs.h29
-rw-r--r--compiler/moco/support/include/moco/Support/TFShapeInferenceHelper.h221
-rw-r--r--compiler/moco/support/src/TFShapeInferenceHelper.cpp354
255 files changed, 19805 insertions, 0 deletions
diff --git a/compiler/moco/CMakeLists.txt b/compiler/moco/CMakeLists.txt
new file mode 100644
index 000000000..9fdd4398e
--- /dev/null
+++ b/compiler/moco/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_subdirectory(lang)
+add_subdirectory(support)
+add_subdirectory(service)
+add_subdirectory(import)
+add_subdirectory(pass)
diff --git a/compiler/moco/README.md b/compiler/moco/README.md
new file mode 100644
index 000000000..13c7aaae3
--- /dev/null
+++ b/compiler/moco/README.md
@@ -0,0 +1,3 @@
+# moco
+
+_moco_ provides building blocks to load and process TensorFlow models and to produce graph of loco canonical IR
diff --git a/compiler/moco/import/CMakeLists.txt b/compiler/moco/import/CMakeLists.txt
new file mode 100644
index 000000000..43107776e
--- /dev/null
+++ b/compiler/moco/import/CMakeLists.txt
@@ -0,0 +1,26 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(moco_import SHARED ${SOURCES})
+target_include_directories(moco_import PRIVATE src)
+target_include_directories(moco_import PUBLIC include)
+target_link_libraries(moco_import PUBLIC moco_lang)
+target_link_libraries(moco_import PUBLIC mio_tf)
+target_link_libraries(moco_import PUBLIC stdex)
+target_link_libraries(moco_import PRIVATE nncc_common)
+target_link_libraries(moco_import PRIVATE plier_tf)
+target_link_libraries(moco_import PRIVATE oops)
+install(TARGETS moco_import DESTINATION lib) # moco_tf_frontend requires moco_import
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
+
+GTest_AddTest(moco_import_test ${TESTS})
+target_include_directories(moco_import_test PRIVATE src)
+target_link_libraries(moco_import_test moco_import)
+target_link_libraries(moco_import_test plier_tf)
+target_link_libraries(moco_import_test oops)
diff --git a/compiler/moco/import/README.md b/compiler/moco/import/README.md
new file mode 100644
index 000000000..2704d35d6
--- /dev/null
+++ b/compiler/moco/import/README.md
@@ -0,0 +1,3 @@
+# moco-import
+
+_moco-import_ provides importing TensorFlow model file to _moco_ TensorFlow Dialect IR
diff --git a/compiler/moco/import/include/moco/GraphHelper.h b/compiler/moco/import/include/moco/GraphHelper.h
new file mode 100644
index 000000000..fad62af4e
--- /dev/null
+++ b/compiler/moco/import/include/moco/GraphHelper.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 __MOCO_GRAPH_HELPER_H__
+#define __MOCO_GRAPH_HELPER_H__
+
+#include <moco/IR/TFNode.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief find_node_byname() will return a node with type T with given name
+ * in graph g
+ *
+ * @note this uses simple linear search, but can speed up with better
+ * algorithms when needed.
+ */
+template <typename T> T *find_node_byname(loco::Graph *g, const char *name)
+{
+ T *first_node = nullptr;
+ loco::Graph::NodeContext *nodes = g->nodes();
+ uint32_t count = nodes->size();
+
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ auto tfnode = dynamic_cast<TFNode *>(nodes->at(i));
+ if (tfnode != nullptr)
+ {
+ if (tfnode->name() == name)
+ {
+ // if tfnode is NOT type of T then return will be nullptr
+ // this is OK cause the user wanted to get type T but it isn't
+ return dynamic_cast<T *>(tfnode);
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+} // namespace moco
+
+#endif // __MOCO_GRAPH_HELPER_H__
diff --git a/compiler/moco/import/include/moco/Import/GraphBuilder.h b/compiler/moco/import/include/moco/Import/GraphBuilder.h
new file mode 100644
index 000000000..c19918def
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/GraphBuilder.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IMPORT_GRAPH_BUILDER_H__
+#define __MOCO_IMPORT_GRAPH_BUILDER_H__
+
+#include "GraphBuilderContext.h"
+
+#include <tensorflow/core/framework/graph.pb.h>
+
+namespace moco
+{
+
+/**
+ * @brief Interface of convert TF NodeDef to loco::Node (e.g., Conv2DGraphBuilder)
+ */
+class GraphBuilder
+{
+public:
+ virtual bool validate(const tensorflow::NodeDef &) const = 0;
+ virtual void build(const tensorflow::NodeDef &, GraphBuilderContext *) const = 0;
+ virtual ~GraphBuilder() {}
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_GRAPH_BUILDER_H__
diff --git a/compiler/moco/import/include/moco/Import/GraphBuilderContext.h b/compiler/moco/import/include/moco/Import/GraphBuilderContext.h
new file mode 100644
index 000000000..ae4f02c2a
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/GraphBuilderContext.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 __MOCO_IMPORT_GRAPH_BUILDER_CONTEXT_H__
+#define __MOCO_IMPORT_GRAPH_BUILDER_CONTEXT_H__
+
+#include <moco/Names.h>
+
+#include <loco.h>
+
+#include <tensorflow/core/framework/graph.pb.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace moco
+{
+
+/**
+ * @brief Class to store and query tensorflow::NodeDef* with string name key
+ */
+class NodeDefTable
+{
+public:
+ /**
+ * @brief Registers a name with corresponding tensorflow::NodeDef*
+ */
+ void enroll(const std::string &node_name, const tensorflow::NodeDef *node);
+ /**
+ * @brief Queries enrolled(registered) with name and return node if found
+ * Will throw runtime_error if not found
+ */
+ const tensorflow::NodeDef *node(const std::string &node_name) const;
+
+private:
+ using MapNameNode_t = std::map<std::string, const tensorflow::NodeDef *>;
+
+ MapNameNode_t _table;
+};
+
+/**
+ * @brief Class to store and query loco::Node* with string name key
+ */
+class SymbolTable
+{
+public:
+ /**
+ * @brief Registers a name with corresponding loco::Node *
+ */
+ void enroll(const TensorName &tensor_name, loco::Node *node);
+ /**
+ * @brief Queries enrolled(registered) with name and return node if found
+ * Will throw runtime_error if not found
+ */
+ loco::Node *node(const TensorName &tensor_name) const;
+
+private:
+ using MapNameNode_t = std::map<TensorName, loco::Node *, TensorNameCompare>;
+
+ MapNameNode_t _table;
+};
+
+/**
+ * @brief Interface to connect the graph
+ */
+class GraphUpdate
+{
+public:
+ virtual ~GraphUpdate() = default;
+
+public:
+ /**
+ * @brief Do the graph input connections using the SymbolTable
+ */
+ virtual void input(const SymbolTable *) const = 0;
+};
+
+/**
+ * @brief Class to store GraphUpdate objects
+ */
+class UpdateQueue final
+{
+public:
+ /**
+ * @brief Registers GraphUpdate objects
+ */
+ void enroll(std::unique_ptr<GraphUpdate> &&update);
+
+public:
+ using Queue = std::vector<std::unique_ptr<GraphUpdate>>;
+
+ const Queue &queue() const { return _queue; }
+
+private:
+ Queue _queue;
+};
+
+/**
+ * @brief Class to store context to build loco graph IR from TensorFlow
+ */
+class GraphBuilderContext
+{
+public:
+ GraphBuilderContext(loco::Graph *g, NodeDefTable *nodedef, SymbolTable *tensor_names,
+ UpdateQueue *updates)
+ : _g(g), _nodedef(nodedef), _tensor_names(tensor_names), _updates(updates)
+ {
+ // DO NOTHING
+ }
+
+ GraphBuilderContext(const GraphBuilderContext &) = delete;
+ GraphBuilderContext(GraphBuilderContext &&) = delete;
+
+public:
+ loco::Graph *graph() { return _g; }
+ NodeDefTable *nodedef() { return _nodedef; }
+ SymbolTable *tensor_names() { return _tensor_names; }
+ UpdateQueue *updates() { return _updates; }
+
+private:
+ loco::Graph *_g;
+ NodeDefTable *_nodedef;
+ SymbolTable *_tensor_names;
+ UpdateQueue *_updates;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_GRAPH_BUILDER_CONTEXT_H__
diff --git a/compiler/moco/import/include/moco/Import/GraphBuilderRegistry.h b/compiler/moco/import/include/moco/Import/GraphBuilderRegistry.h
new file mode 100644
index 000000000..da65cffb8
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/GraphBuilderRegistry.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 __MOCO_IMPORT_GRAPH_BUILDER_REGISTRY_H__
+#define __MOCO_IMPORT_GRAPH_BUILDER_REGISTRY_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+namespace moco
+{
+
+struct GraphBuilderSource
+{
+ virtual ~GraphBuilderSource() = default;
+
+ /**
+ * @brief Returns registered GraphBuilder pointer for operator (nullptr if not present)
+ */
+ virtual const GraphBuilder *lookup(const std::string &op) const = 0;
+};
+
+/**
+ * @brief Class to return graph builder for TF nodes
+ */
+class GraphBuilderRegistry final : public GraphBuilderSource
+{
+public:
+ GraphBuilderRegistry();
+
+public:
+ GraphBuilderRegistry(const GraphBuilderSource *parent) : _parent{parent}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Returns registered GraphBuilder pointer for operator or
+ * nullptr if not registered
+ */
+ const GraphBuilder *lookup(const std::string &op) const final
+ {
+ if (_builder_map.find(op) == _builder_map.end())
+ return (_parent == nullptr) ? nullptr : _parent->lookup(op);
+
+ return _builder_map.at(op).get();
+ }
+
+ static GraphBuilderRegistry &get()
+ {
+ static GraphBuilderRegistry me;
+ return me;
+ }
+
+public:
+ void add(const std::string op, std::unique_ptr<GraphBuilder> &&builder)
+ {
+ _builder_map[op] = std::move(builder);
+ }
+
+private:
+ const GraphBuilderSource *_parent = nullptr;
+
+private:
+ std::map<const std::string, std::unique_ptr<GraphBuilder>> _builder_map;
+};
+
+} // namespace mono
+
+#endif // __MOCO_IMPORT_GRAPH_BUILDER_REGISTRY_H__
diff --git a/compiler/moco/import/include/moco/Import/ModelSignature.h b/compiler/moco/import/include/moco/Import/ModelSignature.h
new file mode 100644
index 000000000..0db7c2795
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/ModelSignature.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IMPORT_MODELSIGNATURE_H__
+#define __MOCO_IMPORT_MODELSIGNATURE_H__
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <angkor/TensorShape.h>
+
+#include <string>
+#include <vector>
+
+namespace moco
+{
+
+/**
+ * @brief Class to store information to run a model. Normally this info comes from users
+ * via CLI params or configuration file.
+ */
+struct ModelSignature
+{
+public:
+ void add_input(const TensorName &input) { _inputs.push_back(input); }
+ void add_input(const TensorName &&input) { _inputs.push_back(input); }
+ void add_output(const TensorName &output) { _outputs.push_back(output); }
+ void add_output(const TensorName &&output) { _outputs.push_back(output); }
+
+ const std::vector<TensorName> &inputs() const { return _inputs; }
+ const std::vector<TensorName> &outputs() const { return _outputs; }
+
+ /**
+ * @brief Adds customop op type (not name of node) provided from user
+ */
+ void add_customop(const std::string &op);
+ const std::vector<std::string> &customops() const { return _customops; }
+
+ /**
+ * @brief Adds node name and its shape provided from user
+ */
+ void shape(const std::string &node_name, const angkor::TensorShape &shape);
+ const angkor::TensorShape *shape(const std::string &node_name) const;
+
+ /**
+ * @brief Adds node name and its dtype provided from user
+ */
+ void dtype(const std::string &node_name, loco::DataType dtype);
+ loco::DataType dtype(const std::string &node_name) const;
+
+private:
+ std::vector<TensorName> _inputs; // graph inputs
+ std::vector<TensorName> _outputs; // graph outputs
+
+ // For custom op types passed from user (e.g., via CLI)
+ std::vector<std::string> _customops;
+
+ // For and node names and shapes passed from user (e.g., via CLI)
+ std::map<std::string, angkor::TensorShape> _shapes;
+
+ // For and node names and dtype passed from user (e.g., via CLI)
+ std::map<std::string, loco::DataType> _dtypes;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_MODELSIGNATURE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes.h b/compiler/moco/import/include/moco/Import/Nodes.h
new file mode 100644
index 000000000..8c940a28c
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes.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 __MOCO_IMPORT_NODES_H__
+#define __MOCO_IMPORT_NODES_H__
+
+#include "Nodes/Add.h"
+#include "Nodes/AvgPool.h"
+#include "Nodes/BiasAdd.h"
+#include "Nodes/Concat.h"
+#include "Nodes/Const.h"
+#include "Nodes/Conv2DBackpropInput.h"
+#include "Nodes/Conv2D.h"
+#include "Nodes/DepthwiseConv2dNative.h"
+#include "Nodes/FakeQuantWithMinMaxVars.h"
+#include "Nodes/FusedBatchNorm.h"
+#include "Nodes/Identity.h"
+#include "Nodes/Maximum.h"
+#include "Nodes/MaxPool.h"
+#include "Nodes/Mean.h"
+#include "Nodes/Mul.h"
+#include "Nodes/Pack.h"
+#include "Nodes/Pad.h"
+#include "Nodes/Placeholder.h"
+#include "Nodes/RealDiv.h"
+#include "Nodes/Relu6.h"
+#include "Nodes/Relu.h"
+#include "Nodes/Reshape.h"
+#include "Nodes/Rsqrt.h"
+#include "Nodes/Shape.h"
+#include "Nodes/Softmax.h"
+#include "Nodes/Sqrt.h"
+#include "Nodes/SquaredDifference.h"
+#include "Nodes/Squeeze.h"
+#include "Nodes/StopGradient.h"
+#include "Nodes/StridedSlice.h"
+#include "Nodes/Sub.h"
+#include "Nodes/Tanh.h"
+
+#endif // __MOCO_IMPORT_NODES_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Add.h b/compiler/moco/import/include/moco/Import/Nodes/Add.h
new file mode 100644
index 000000000..3d0d0f30f
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Add.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_ADD_H__
+#define __MOCO_IMPORT_OP_ADD_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Add node
+ */
+class AddGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_ADD_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/AvgPool.h b/compiler/moco/import/include/moco/Import/Nodes/AvgPool.h
new file mode 100644
index 000000000..4c8087afe
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/AvgPool.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 __MOCO_IMPORT_OP_AVG_POOL_H__
+#define __MOCO_IMPORT_OP_AVG_POOL_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class AvgPoolGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_AVG_POOL_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/BiasAdd.h b/compiler/moco/import/include/moco/Import/Nodes/BiasAdd.h
new file mode 100644
index 000000000..214df03de
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/BiasAdd.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 __MOCO_IMPORT_OP_BIAS_ADD_H__
+#define __MOCO_IMPORT_OP_BIAS_ADD_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class BiasAddGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_BIAS_ADD_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Concat.h b/compiler/moco/import/include/moco/Import/Nodes/Concat.h
new file mode 100644
index 000000000..2341fb00c
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Concat.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 __MOCO_IMPORT_OP_CONCAT_H__
+#define __MOCO_IMPORT_OP_CONCAT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class ConcatV2GraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_CONCAT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Const.h b/compiler/moco/import/include/moco/Import/Nodes/Const.h
new file mode 100644
index 000000000..1ce378219
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Const.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 __MOCO_IMPORT_OP_CONST_H__
+#define __MOCO_IMPORT_OP_CONST_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class ConstGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_CONST_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Conv2D.h b/compiler/moco/import/include/moco/Import/Nodes/Conv2D.h
new file mode 100644
index 000000000..3bd3dc74a
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Conv2D.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 __MOCO_IMPORT_OP_CONV_2D_H__
+#define __MOCO_IMPORT_OP_CONV_2D_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class Conv2DGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_CONV_2D_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Conv2DBackpropInput.h b/compiler/moco/import/include/moco/Import/Nodes/Conv2DBackpropInput.h
new file mode 100644
index 000000000..262a443fe
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Conv2DBackpropInput.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_CONV_2D_BACKPROP_INPUT_H__
+#define __MOCO_IMPORT_OP_CONV_2D_BACKPROP_INPUT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Conv2DBackpropInput node
+ */
+class Conv2DBackpropInputGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_CONV_2D_BACKPROP_INPUT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/DepthwiseConv2dNative.h b/compiler/moco/import/include/moco/Import/Nodes/DepthwiseConv2dNative.h
new file mode 100644
index 000000000..1dcbba1eb
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/DepthwiseConv2dNative.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_DEPTHWISE_CONV_2D_NATIVE_H__
+#define __MOCO_IMPORT_OP_DEPTHWISE_CONV_2D_NATIVE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for DepthwiseConv2dNative node
+ */
+class DepthwiseConv2dNativeGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_DEPTHWISE_CONV_2D_NATIVE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/FakeQuantWithMinMaxVars.h b/compiler/moco/import/include/moco/Import/Nodes/FakeQuantWithMinMaxVars.h
new file mode 100644
index 000000000..9e223c18e
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/FakeQuantWithMinMaxVars.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_FAKE_QUANT_WITH_MINMAX_VARS_H__
+#define __MOCO_IMPORT_OP_FAKE_QUANT_WITH_MINMAX_VARS_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for FakeQuantWithMinMaxVars node
+ */
+class FakeQuantWithMinMaxVarsGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_FAKE_QUANT_WITH_MINMAX_VARS_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/FusedBatchNorm.h b/compiler/moco/import/include/moco/Import/Nodes/FusedBatchNorm.h
new file mode 100644
index 000000000..38d1d5682
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/FusedBatchNorm.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_FUSED_BATCH_NORM_H__
+#define __MOCO_IMPORT_OP_FUSED_BATCH_NORM_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for FusedBatchNorm node
+ */
+class FusedBatchNormGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_FUSED_BATCH_NORM_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Identity.h b/compiler/moco/import/include/moco/Import/Nodes/Identity.h
new file mode 100644
index 000000000..29e04800f
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Identity.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 __MOCO_IMPORT_OP_IDENTITY_H__
+#define __MOCO_IMPORT_OP_IDENTITY_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class IdentityGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_IDENTITY_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/MaxPool.h b/compiler/moco/import/include/moco/Import/Nodes/MaxPool.h
new file mode 100644
index 000000000..696fa71e6
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/MaxPool.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 __MOCO_IMPORT_OP_MAX_POOL_H__
+#define __MOCO_IMPORT_OP_MAX_POOL_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class MaxPoolGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_MAX_POOL_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Maximum.h b/compiler/moco/import/include/moco/Import/Nodes/Maximum.h
new file mode 100644
index 000000000..69d897742
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Maximum.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IMPORT_OP_MAXIMUM_H__
+#define __MOCO_IMPORT_OP_MAXIMUM_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Maximum node
+ */
+class MaximumGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_MAXIMUM_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Mean.h b/compiler/moco/import/include/moco/Import/Nodes/Mean.h
new file mode 100644
index 000000000..7bae1bb39
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Mean.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_MEAN_H__
+#define __MOCO_IMPORT_OP_MEAN_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Mean node
+ */
+class MeanGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_MEAN_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Mul.h b/compiler/moco/import/include/moco/Import/Nodes/Mul.h
new file mode 100644
index 000000000..667c81954
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Mul.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_MUL_H__
+#define __MOCO_IMPORT_OP_MUL_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Mul node
+ */
+class MulGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_MUL_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Pack.h b/compiler/moco/import/include/moco/Import/Nodes/Pack.h
new file mode 100644
index 000000000..94666ad51
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Pack.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 __MOCO_IMPORT_OP_PACK_H__
+#define __MOCO_IMPORT_OP_PACK_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class PackGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_PACK_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Pad.h b/compiler/moco/import/include/moco/Import/Nodes/Pad.h
new file mode 100644
index 000000000..22eab32ac
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Pad.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_PAD_H__
+#define __MOCO_IMPORT_OP_PAD_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Pad node
+ */
+class PadGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_PAD_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Placeholder.h b/compiler/moco/import/include/moco/Import/Nodes/Placeholder.h
new file mode 100644
index 000000000..458600915
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Placeholder.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_PLACEHOLDER_H__
+#define __MOCO_IMPORT_OP_PLACEHOLDER_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Placeholder node
+ */
+class PlaceholderGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_PLACEHOLDER_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/RealDiv.h b/compiler/moco/import/include/moco/Import/Nodes/RealDiv.h
new file mode 100644
index 000000000..142e8b5f8
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/RealDiv.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_REALDIV_H__
+#define __MOCO_IMPORT_OP_REALDIV_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for RealDiv node
+ */
+class RealDivGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_REALDIV_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Relu.h b/compiler/moco/import/include/moco/Import/Nodes/Relu.h
new file mode 100644
index 000000000..0bd9cff04
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Relu.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_RELU_H__
+#define __MOCO_IMPORT_OP_RELU_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Relu node
+ */
+class ReluGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_RELU_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Relu6.h b/compiler/moco/import/include/moco/Import/Nodes/Relu6.h
new file mode 100644
index 000000000..d211b0543
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Relu6.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_RELU6_H__
+#define __MOCO_IMPORT_OP_RELU6_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Relu6 node
+ */
+class Relu6GraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_RELU6_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Reshape.h b/compiler/moco/import/include/moco/Import/Nodes/Reshape.h
new file mode 100644
index 000000000..e8bfeee23
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Reshape.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_RESHAPE_H__
+#define __MOCO_IMPORT_OP_RESHAPE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Reshape node
+ */
+class ReshapeGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_RESHAPE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Rsqrt.h b/compiler/moco/import/include/moco/Import/Nodes/Rsqrt.h
new file mode 100644
index 000000000..dedc52323
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Rsqrt.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_RSQRT_H__
+#define __MOCO_IMPORT_OP_RSQRT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Rsqrt node
+ */
+class RsqrtGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_RSQRT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Shape.h b/compiler/moco/import/include/moco/Import/Nodes/Shape.h
new file mode 100644
index 000000000..e36e1d546
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Shape.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_SHAPE_H__
+#define __MOCO_IMPORT_OP_SHAPE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Shape node
+ */
+class ShapeGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SHAPE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Softmax.h b/compiler/moco/import/include/moco/Import/Nodes/Softmax.h
new file mode 100644
index 000000000..43fbb8852
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Softmax.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_SOFTMAX_H__
+#define __MOCO_IMPORT_OP_SOFTMAX_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+* @brief GraphBuilder for Softmax node
+*/
+class SoftmaxGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SOFTMAX_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Sqrt.h b/compiler/moco/import/include/moco/Import/Nodes/Sqrt.h
new file mode 100644
index 000000000..d17dc3494
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Sqrt.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_SQRT_H__
+#define __MOCO_IMPORT_OP_SQRT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Sqrt node
+ */
+class SqrtGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SQRT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/SquaredDifference.h b/compiler/moco/import/include/moco/Import/Nodes/SquaredDifference.h
new file mode 100644
index 000000000..501464d65
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/SquaredDifference.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_SQUARED_DIFFERENCE_H__
+#define __MOCO_IMPORT_OP_SQUARED_DIFFERENCE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for SquaredDifference node
+ */
+class SquaredDifferenceGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SQUARED_DIFFERENCE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Squeeze.h b/compiler/moco/import/include/moco/Import/Nodes/Squeeze.h
new file mode 100644
index 000000000..64ead074b
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Squeeze.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_SQUEEZE_H__
+#define __MOCO_IMPORT_OP_SQUEEZE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Squeeze node
+ */
+class SqueezeGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SQUEEZE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/StopGradient.h b/compiler/moco/import/include/moco/Import/Nodes/StopGradient.h
new file mode 100644
index 000000000..e547a8a8b
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/StopGradient.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_STOP_GRADIENT_H__
+#define __MOCO_IMPORT_OP_STOP_GRADIENT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for StopGradient node
+ */
+class StopGradientGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_STOP_GRADIENT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/StridedSlice.h b/compiler/moco/import/include/moco/Import/Nodes/StridedSlice.h
new file mode 100644
index 000000000..61170ebbf
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/StridedSlice.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 __MOCO_IMPORT_OP_STRIDEDSLICE_H__
+#define __MOCO_IMPORT_OP_STRIDEDSLICE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class StridedSliceGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_STRIDEDSLICE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Sub.h b/compiler/moco/import/include/moco/Import/Nodes/Sub.h
new file mode 100644
index 000000000..d6351e34a
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Sub.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_SUB_H__
+#define __MOCO_IMPORT_OP_SUB_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Sub node
+ */
+class SubGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SUB_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Tanh.h b/compiler/moco/import/include/moco/Import/Nodes/Tanh.h
new file mode 100644
index 000000000..183e117ef
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Tanh.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_TANH_H__
+#define __MOCO_IMPORT_OP_TANH_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Tanh node
+ */
+class TanhGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_TANH_H__
diff --git a/compiler/moco/import/include/moco/Importer.h b/compiler/moco/import/include/moco/Importer.h
new file mode 100644
index 000000000..ee0660c52
--- /dev/null
+++ b/compiler/moco/import/include/moco/Importer.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 __MOCO_IMPORTER_H__
+#define __MOCO_IMPORTER_H__
+
+#include "moco/Import/ModelSignature.h"
+#include "moco/Import/GraphBuilderRegistry.h"
+
+#include <moco/Names.h>
+
+#include <loco.h>
+
+#include <tensorflow/core/framework/graph.pb.h>
+
+#include <memory>
+
+namespace moco
+{
+
+class Importer final
+{
+public:
+ Importer();
+
+public:
+ explicit Importer(const GraphBuilderSource *source) : _source{source}
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::unique_ptr<loco::Graph> import(const ModelSignature &, tensorflow::GraphDef &) const;
+
+private:
+ const GraphBuilderSource *_source = nullptr;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORTER_H__
diff --git a/compiler/moco/import/src/Convert.cpp b/compiler/moco/import/src/Convert.cpp
new file mode 100644
index 000000000..6285f5eab
--- /dev/null
+++ b/compiler/moco/import/src/Convert.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Convert.h"
+
+#include <algorithm>
+#include <cctype>
+
+// TODO move to some common file
+namespace moco
+{
+
+std::string str_toupper(std::string s)
+{
+ // from https://en.cppreference.com/w/cpp/string/byte/toupper
+ std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); });
+ return s;
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Convert.h b/compiler/moco/import/src/Convert.h
new file mode 100644
index 000000000..77dab3700
--- /dev/null
+++ b/compiler/moco/import/src/Convert.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONVERT_H__
+#define __CONVERT_H__
+
+#include <string>
+
+// TODO move to some common file
+namespace moco
+{
+
+std::string str_toupper(std::string s);
+
+} // namespace moco
+
+#endif // __CONVERT_H__
diff --git a/compiler/moco/import/src/GraphBuilderContext.cpp b/compiler/moco/import/src/GraphBuilderContext.cpp
new file mode 100644
index 000000000..bbc1d8bd0
--- /dev/null
+++ b/compiler/moco/import/src/GraphBuilderContext.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/GraphBuilderContext.h"
+
+#include <oops/UserExn.h>
+
+#include <stdexcept>
+#include <string>
+
+namespace moco
+{
+
+void NodeDefTable::enroll(const std::string &node_name, const tensorflow::NodeDef *node)
+{
+ MapNameNode_t::iterator iter = _table.find(node_name);
+
+ if (iter != _table.end())
+ {
+ throw oops::UserExn("Duplicate node name in GraphDef", node_name);
+ }
+
+ _table[node_name] = node;
+}
+
+const tensorflow::NodeDef *NodeDefTable::node(const std::string &node_name) const
+{
+ MapNameNode_t::const_iterator iter = _table.find(node_name);
+
+ if (iter == _table.end())
+ {
+ throw oops::UserExn("Cannot find node with name in GraphDef", node_name);
+ }
+
+ return iter->second;
+}
+
+void SymbolTable::enroll(const TensorName &tensor_name, loco::Node *node)
+{
+ MapNameNode_t::iterator iter = _table.find(tensor_name);
+
+ if (iter != _table.end())
+ {
+ throw oops::UserExn("Duplicate node name in GraphDef", tensor_name.name());
+ }
+
+ _table[tensor_name] = node;
+}
+
+loco::Node *SymbolTable::node(const TensorName &tensor_name) const
+{
+ MapNameNode_t::const_iterator iter = _table.find(tensor_name);
+
+ if (iter == _table.end())
+ {
+ throw oops::UserExn("Cannot find node with name in GraphDef", tensor_name.name());
+ }
+
+ return iter->second;
+}
+
+void UpdateQueue::enroll(std::unique_ptr<GraphUpdate> &&update)
+{
+ _queue.push_back(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/GraphBuilderContext.test.cpp b/compiler/moco/import/src/GraphBuilderContext.test.cpp
new file mode 100644
index 000000000..51f6db245
--- /dev/null
+++ b/compiler/moco/import/src/GraphBuilderContext.test.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/GraphBuilderContext.h"
+#include <moco/Names.h>
+
+#include <loco.h>
+
+#include <oops/UserExn.h>
+
+#include <gtest/gtest.h>
+
+TEST(GraphBuilderContext, ctor)
+{
+ auto graph = loco::make_graph();
+ moco::NodeDefTable nodedef;
+ moco::SymbolTable nodes;
+ moco::UpdateQueue updates;
+
+ moco::GraphBuilderContext context(graph.get(), &nodedef, &nodes, &updates);
+
+ ASSERT_EQ(context.graph(), graph.get());
+ ASSERT_EQ(context.nodedef(), &nodedef);
+ ASSERT_EQ(context.tensor_names(), &nodes);
+ ASSERT_EQ(context.updates(), &updates);
+}
+
+TEST(SymbolTable, node_name)
+{
+ moco::SymbolTable table;
+ loco::Pull pull_node;
+ moco::TensorName name("input", 0);
+ moco::TensorName invalid("invalid", 0);
+
+ table.enroll(name, &pull_node);
+ ASSERT_EQ(table.node(name), &pull_node);
+ // duplicate name should throw
+ EXPECT_THROW(table.enroll(name, &pull_node), oops::UserExn);
+ // unregistered name should throw
+ EXPECT_THROW(table.node(invalid), oops::UserExn);
+}
+
+namespace
+{
+
+class TestGraphUpdate final : public moco::GraphUpdate
+{
+public:
+ void input(const moco::SymbolTable *) const override;
+};
+
+void TestGraphUpdate::input(const moco::SymbolTable *) const {}
+
+} // namespace
+
+TEST(GraphUpdateQueue, queue)
+{
+ std::unique_ptr<TestGraphUpdate> update(new TestGraphUpdate());
+ moco::UpdateQueue updates;
+
+ updates.enroll(std::move(update));
+ auto &queue = updates.queue();
+ ASSERT_EQ(queue.size(), 1);
+}
diff --git a/compiler/moco/import/src/GraphBuilderRegistry.cpp b/compiler/moco/import/src/GraphBuilderRegistry.cpp
new file mode 100644
index 000000000..3a028513f
--- /dev/null
+++ b/compiler/moco/import/src/GraphBuilderRegistry.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/GraphBuilderRegistry.h"
+#include "moco/Import/Nodes.h"
+
+#include <stdex/Memory.h>
+
+namespace moco
+{
+
+GraphBuilderRegistry::GraphBuilderRegistry()
+{
+ add("Add", stdex::make_unique<AddGraphBuilder>());
+ add("AvgPool", stdex::make_unique<AvgPoolGraphBuilder>());
+ add("BiasAdd", stdex::make_unique<BiasAddGraphBuilder>());
+ add("ConcatV2", stdex::make_unique<ConcatV2GraphBuilder>());
+ add("Const", stdex::make_unique<ConstGraphBuilder>());
+ add("Conv2D", stdex::make_unique<Conv2DGraphBuilder>());
+ add("Conv2DBackpropInput", stdex::make_unique<Conv2DBackpropInputGraphBuilder>());
+ add("DepthwiseConv2dNative", stdex::make_unique<DepthwiseConv2dNativeGraphBuilder>());
+ add("FakeQuantWithMinMaxVars", stdex::make_unique<FakeQuantWithMinMaxVarsGraphBuilder>());
+ add("FusedBatchNorm", stdex::make_unique<FusedBatchNormGraphBuilder>());
+ add("Identity", stdex::make_unique<IdentityGraphBuilder>());
+ add("Maximum", stdex::make_unique<MaximumGraphBuilder>());
+ add("MaxPool", stdex::make_unique<MaxPoolGraphBuilder>());
+ add("Mean", stdex::make_unique<MeanGraphBuilder>());
+ add("Mul", stdex::make_unique<MulGraphBuilder>());
+ add("Pack", stdex::make_unique<PackGraphBuilder>());
+ add("Pad", stdex::make_unique<PadGraphBuilder>());
+ add("Placeholder", stdex::make_unique<PlaceholderGraphBuilder>());
+ add("RealDiv", stdex::make_unique<RealDivGraphBuilder>());
+ add("Relu", stdex::make_unique<ReluGraphBuilder>());
+ add("Relu6", stdex::make_unique<Relu6GraphBuilder>());
+ add("Reshape", stdex::make_unique<ReshapeGraphBuilder>());
+ add("Rsqrt", stdex::make_unique<RsqrtGraphBuilder>());
+ add("Shape", stdex::make_unique<ShapeGraphBuilder>());
+ add("Softmax", stdex::make_unique<SoftmaxGraphBuilder>());
+ add("Sqrt", stdex::make_unique<SqrtGraphBuilder>());
+ add("SquaredDifference", stdex::make_unique<SquaredDifferenceGraphBuilder>());
+ add("Squeeze", stdex::make_unique<SqueezeGraphBuilder>());
+ add("StopGradient", stdex::make_unique<StopGradientGraphBuilder>());
+ add("StridedSlice", stdex::make_unique<StridedSliceGraphBuilder>());
+ add("Sub", stdex::make_unique<SubGraphBuilder>());
+ add("Tanh", stdex::make_unique<TanhGraphBuilder>());
+
+ // Virtual node like `TFPush` need not to be added here
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Importer.cpp b/compiler/moco/import/src/Importer.cpp
new file mode 100644
index 000000000..8d3ca6cfc
--- /dev/null
+++ b/compiler/moco/import/src/Importer.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Importer.h"
+#include "moco/Import/GraphBuilder.h"
+#include "moco/Import/GraphBuilderContext.h"
+
+#include "moco/Import/GraphBuilderRegistry.h"
+
+#include <moco/IR/Nodes/TFPlaceholder.h>
+#include <moco/IR/TFNode.h>
+
+#include <stdex/Memory.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <sstream>
+#include <stdexcept>
+
+namespace
+{
+
+void convert_graph(const moco::GraphBuilderSource &source, const moco::ModelSignature &signature,
+ tensorflow::GraphDef &tf_graph_def, loco::Graph *graph)
+{
+ auto nodedef = stdex::make_unique<moco::NodeDefTable>();
+ auto tensor_names = stdex::make_unique<moco::SymbolTable>();
+ auto updates = stdex::make_unique<moco::UpdateQueue>();
+
+ moco::GraphBuilderContext gb_context(graph, nodedef.get(), tensor_names.get(), updates.get());
+
+ // Building a loco graph
+ // 1. Convert all the nodes to moco::TFNode
+ // 2. Connect inputs: set all node input(from a string) to actual node object
+ // 3. Set graph input
+ // 4. Create moco::TFPush node and set graph output
+
+ /**
+ * @brief Prepare tensorflow::NodeDef search table from name
+ */
+ for (const auto &n : tf_graph_def.node())
+ {
+ nodedef->enroll(n.name(), &n);
+ }
+
+ /**
+ * @brief 1. Convert all the nodes to moco::TFNode
+ *
+ * @note In each build for a TF node, four things happen
+ * 1) create corresponding moco::TFNode(s)
+ * 2) read and set the attributes to created moco::TFNode(s)
+ * 3) register name-moco::TFNode(last one of Nodes) that will be used as the output
+ * 4) queue a task to set the input of the moco::TFNode(first one of the Nodes)
+ * this is done only for required nodes depending on the operator
+ *
+ * @example Placeholder("in") - Identity("out")
+ * %1 = Placeholder --> 0x1001 (moco::TFNode* object address)
+ * (symboltable: register %1, after the registeration table will contain as below;
+ * "in" : 0x1001
+ * )
+ * (queue: this will be empty as Pull does not queue a task to set input;
+ * )
+ *
+ * %2 = Forward --> 0x1002
+ * (symboltable: register %2 and table will look like below;
+ * "in" : 0x1001
+ * "out" : 0x1002
+ * )
+ * (queue: Forward will queue a task with input "in";
+ * 0x1002: {"in"}
+ * )
+ */
+ for (const auto &n : tf_graph_def.node())
+ {
+ if (const auto *graph_builder = source.lookup(n.op()))
+ {
+ if (!graph_builder->validate(n))
+ {
+ throw oops::UserExn("Invalid operator", n.op());
+ }
+
+ graph_builder->build(n, &gb_context);
+ }
+ else
+ {
+ throw oops::UserExn("Not supported", n.op());
+ }
+ }
+
+ /**
+ * @brief 2. Connect inputs: Iterate updates and call each update input method
+ *
+ * @note Continue from above example graph, connecting inputs is done in following steps
+ * a) iterate queue
+ * b) call the input method for each update
+ * c) each update has the moco::TFNode *node and names of the input to connect
+ * node = 0x1002 and names = {"in"}
+ * d) from symbol table, "in" will return 0x1001
+ * e) set input of 0x1002 with 0x1001
+ */
+ for (auto &update : updates->queue())
+ {
+ update->input(tensor_names.get());
+ }
+
+ /**
+ * @brief 3. Set graph input
+ */
+ for (auto input : signature.inputs())
+ {
+ auto node = tensor_names->node(input);
+ assert(node != nullptr);
+
+ auto graph_input = graph->inputs()->create();
+
+ auto placeholder_node = dynamic_cast<moco::TFPlaceholder *>(node);
+ assert(placeholder_node != nullptr);
+
+ graph_input->name(input.nodeName());
+
+ // annotate index that should be passed to loco::Pull
+ moco::index(placeholder_node, graph_input->index());
+
+ // This implementation works as "PlaceholderGraphBuilder in Nodes/Placeholder.cpp"
+ // accepts only TF_FLOAT32 as of now.
+ //
+ // TODO Support other types
+ graph_input->dtype(loco::DataType::FLOAT32);
+ }
+
+ /**
+ * @brief 4. Create moco::TFPush node and set graph output
+ */
+ for (auto output : signature.outputs())
+ {
+ auto output_node = tensor_names->node(output);
+ assert(output_node);
+
+ // create moco::TFPush for output of graph
+ auto push_node = graph->nodes()->create<moco::TFPush>();
+ push_node->from(output_node); // set input of TFPush to output node
+
+ // set the graph output name and node object
+ auto graph_output = graph->outputs()->create();
+ graph_output->name(output.nodeName());
+ push_node->index(graph_output->index());
+
+ // TODO Support other types
+ graph_output->dtype(loco::DataType::FLOAT32);
+ }
+
+ // validate graph
+ assert(loco::valid(graph));
+}
+
+} // namespace
+
+namespace moco
+{
+
+Importer::Importer()
+{
+ // DO NOTHING
+}
+
+std::unique_ptr<loco::Graph> Importer::import(const ModelSignature &signature,
+ tensorflow::GraphDef &tf_graph_def) const
+{
+ auto graph = loco::make_graph();
+
+ const GraphBuilderSource *source_ptr = &moco::GraphBuilderRegistry::get();
+
+ if (_source != nullptr)
+ {
+ // Use user-defined GraphBuilderSource
+ source_ptr = _source;
+ }
+
+ convert_graph(*source_ptr, signature, tf_graph_def, graph.get());
+
+ return std::move(graph);
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Importer.test.cpp b/compiler/moco/import/src/Importer.test.cpp
new file mode 100644
index 000000000..23873390c
--- /dev/null
+++ b/compiler/moco/import/src/Importer.test.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Importer.h"
+#include "moco/GraphHelper.h"
+
+#include <moco/IR/Nodes/TFIdentity.h>
+
+#include "TestHelper.h"
+#include <loco.h>
+#include <plier/tf/TestHelper.h>
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+TEST(TensorFlowImport, Dummy) { moco::Importer import; }
+
+namespace
+{
+
+// clang-format off
+const char *basic_pbtxtdata = STRING_CONTENT(
+node {
+ name: "Placeholder"
+ op: "Placeholder"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "shape"
+ value {
+ shape {
+ dim {
+ size: 1
+ }
+ dim {
+ size: 2
+ }
+ dim {
+ size: 1
+ }
+ dim {
+ size: 2
+ }
+ }
+ }
+ }
+}
+node {
+ name: "output/identity"
+ op: "Identity"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, load_model_withio_tf)
+{
+ moco::ModelSignature signature;
+
+ signature.add_input(moco::TensorName("Placeholder", 0));
+ signature.add_output(moco::TensorName("output/identity", 0));
+
+ tensorflow::GraphDef graph_def;
+ EXPECT_TRUE(plier::tf::parse_graphdef(basic_pbtxtdata, graph_def));
+
+ moco::Importer importer;
+
+ std::unique_ptr<loco::Graph> graph = importer.import(signature, graph_def);
+
+ // what to test:
+ // - import reads Placeholder
+ // - import reads Identity
+ // - attribute values should match
+
+ auto tfidentity = find_first_node_bytype<moco::TFIdentity>(graph.get());
+ ASSERT_NE(tfidentity, nullptr);
+ ASSERT_NE(tfidentity->input(), nullptr);
+}
+
+namespace
+{
+
+// clang-format off
+const char *query_pbtxtdata = STRING_CONTENT(
+node {
+ name: "Placeholder"
+ op: "Placeholder"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "shape"
+ value {
+ shape {
+ dim {
+ size: 1
+ }
+ dim {
+ size: 2
+ }
+ dim {
+ size: 1
+ }
+ dim {
+ size: 2
+ }
+ }
+ }
+ }
+}
+node {
+ name: "Foo/w_min"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape { }
+ float_val: -1.0
+ }
+ }
+ }
+}
+node {
+ name: "output/identity"
+ op: "Identity"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+node {
+ name: "Foo/w_max"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape { }
+ float_val: -1.0
+ }
+ }
+ }
+}
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, find_node_by_name)
+{
+ moco::ModelSignature signature;
+
+ signature.add_input(moco::TensorName("Placeholder", 0));
+ signature.add_output(moco::TensorName("output/identity", 0));
+
+ tensorflow::GraphDef graph_def;
+ EXPECT_TRUE(plier::tf::parse_graphdef(query_pbtxtdata, graph_def));
+
+ moco::Importer importer;
+
+ std::unique_ptr<loco::Graph> graph = importer.import(signature, graph_def);
+
+ // what to test:
+ // - get name of first Identity node
+ // - find node by name `Foo/w_min`
+ // - find node by name `Foo/w_max`
+
+ auto tfidentity = find_first_node_bytype<moco::TFIdentity>(graph.get());
+ ASSERT_NE(tfidentity, nullptr);
+ ASSERT_NE(tfidentity->input(), nullptr);
+ ASSERT_STREQ(tfidentity->name().c_str(), "output/identity");
+
+ auto query_node = moco::find_node_byname<moco::TFConst>(graph.get(), "Foo/w_min");
+ ASSERT_NE(query_node, nullptr);
+ ASSERT_STREQ(query_node->name().c_str(), "Foo/w_min");
+
+ auto query_node2 = moco::find_node_byname<moco::TFConst>(graph.get(), "Foo/w_max");
+ ASSERT_NE(query_node2, nullptr);
+ ASSERT_STREQ(query_node2->name().c_str(), "Foo/w_max");
+}
diff --git a/compiler/moco/import/src/ModelSignature.cpp b/compiler/moco/import/src/ModelSignature.cpp
new file mode 100644
index 000000000..d4c7e5085
--- /dev/null
+++ b/compiler/moco/import/src/ModelSignature.cpp
@@ -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 "moco/Import/ModelSignature.h"
+
+#include <oops/UserExn.h>
+
+namespace moco
+{
+
+void ModelSignature::add_customop(const std::string &op)
+{
+ if (std::find(_customops.begin(), _customops.end(), op) == _customops.end())
+ _customops.emplace_back(op);
+ else
+ throw oops::UserExn("Duplicate custom operator", op);
+}
+
+void ModelSignature::shape(const std::string &node_name, const angkor::TensorShape &shape)
+{
+ if (_shapes.find(node_name) != _shapes.end())
+ throw oops::UserExn("Duplicate node name", node_name);
+
+ _shapes[node_name] = shape;
+}
+
+const angkor::TensorShape *ModelSignature::shape(const std::string &node_name) const
+{
+ auto res = _shapes.find(node_name);
+ if (res == _shapes.end())
+ return nullptr;
+ else
+ return &res->second;
+}
+
+void ModelSignature::dtype(const std::string &node_name, loco::DataType dtype)
+{
+ if (_dtypes.find(node_name) != _dtypes.end())
+ throw oops::UserExn("Duplicate node name", node_name);
+
+ _dtypes[node_name] = dtype;
+}
+
+loco::DataType ModelSignature::dtype(const std::string &node_name) const
+{
+ auto res = _dtypes.find(node_name);
+ if (res == _dtypes.end())
+ return loco::DataType::Unknown;
+ else
+ return res->second;
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Add.cpp b/compiler/moco/import/src/Nodes/Add.cpp
new file mode 100644
index 000000000..6981a55e1
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Add.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Add.h"
+
+#include <moco/IR/Nodes/TFAdd.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Add node
+ */
+class TFAddGraphUpdate final : public GraphUpdate
+{
+public:
+ TFAddGraphUpdate(TFAdd *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFAdd *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFAddGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool AddGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void AddGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Add node
+ auto tf_add = graph->nodes()->create<TFAdd>();
+ tf_add->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_add);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // x
+ add_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_add_update = stdex::make_unique<TFAddGraphUpdate>(tf_add, add_input_names);
+ updates->enroll(std::move(tf_add_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Add.test.cpp b/compiler/moco/import/src/Nodes/Add.test.cpp
new file mode 100644
index 000000000..ace2b0801
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Add.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Add.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *add_basic_pbtxt = STRING_CONTENT(
+ name: "ADD_01"
+ op: "Add"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_add_basic)
+{
+ TFNodeBuildTester tester;
+ moco::AddGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(add_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFAdd node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("ADD_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/AvgPool.cpp b/compiler/moco/import/src/Nodes/AvgPool.cpp
new file mode 100644
index 000000000..6d7fd36bb
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/AvgPool.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/AvgPool.h"
+
+#include <moco/IR/Nodes/TFAvgPool.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <stdexcept>
+
+using namespace plier::tf;
+
+namespace
+{
+
+using namespace moco;
+
+class TFAvgPoolGraphUpdate final : public GraphUpdate
+{
+public:
+ TFAvgPoolGraphUpdate(TFAvgPool *node, const TensorName &name)
+ : _avgpool_node(node), _value_name(name)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFAvgPool *_avgpool_node;
+ const TensorName _value_name;
+};
+
+void TFAvgPoolGraphUpdate::input(const SymbolTable *node_table) const
+{
+ loco::Node *value_node = node_table->node(_value_name);
+ _avgpool_node->value(value_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool AvgPoolGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ // note: even though "data_format" is not entered when a model is written,
+ // TF seems to generate "data_format" field into a pb file
+ if (!plier::tf::has_attrs(node, {"T", "data_format", "ksize", "padding", "strides"}))
+ return false;
+
+ auto tf_ksize = get_list_attr(node, "ksize");
+ auto ksize = as_int64_list(tf_ksize);
+ if (ksize.size() != 4)
+ {
+ // TODO support ksize length for 1 and 2
+ throw oops::UserExn("AvgPool only supports ksize length 4", node.name());
+ }
+
+ auto tf_strides = get_list_attr(node, "strides");
+ auto strides = as_int64_list(tf_strides);
+ if (strides.size() != 4)
+ {
+ // TODO support strides length for 1 and 2
+ throw oops::UserExn("AvgPool only supports strides length 4", node.name());
+ }
+
+ return true;
+}
+
+void AvgPoolGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ ::std::string avgPool2d_name = node.name();
+
+ // tensorflow data_format: one of NHWC or NCHW.
+ auto data_layout = get_string_attr(node, "data_format");
+ auto avgPool_node = graph->nodes()->create<TFAvgPool>();
+ avgPool_node->name(node.name());
+ avgPool_node->data_layout(data_layout);
+
+ // padding
+ auto padding = moco::str_toupper(get_string_attr(node, "padding"));
+ avgPool_node->padding(padding);
+
+ // ksize
+ auto tf_ksize = get_list_attr(node, "ksize");
+ auto ksize = as_int64_list(tf_ksize);
+ avgPool_node->ksize(ksize);
+
+ // strides
+ auto tf_strides = get_list_attr(node, "strides");
+ auto strides = as_int64_list(tf_strides);
+ avgPool_node->strides(strides);
+
+ // To set the input node of encode_node with avgPool2d_name
+ TensorName output_name(avgPool2d_name, 0);
+ tensor_names->enroll(output_name, avgPool_node);
+
+ // Record ifm inputs to featureEncode_node
+ auto update = stdex::make_unique<TFAvgPoolGraphUpdate>(avgPool_node, TensorName(node.input(0)));
+
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
+
+// TODO Consider a case when TF AvgPool is for 3D.
+// AvgPool works for 2D and other Dimensions, such as 3D
+// So, in future, some other GraphBuilder decide if AvgPoolGraphBuilder is used or
+// other GraphBuilder is used for TF AvgPool
diff --git a/compiler/moco/import/src/Nodes/AvgPool.test.cpp b/compiler/moco/import/src/Nodes/AvgPool.test.cpp
new file mode 100644
index 000000000..7d62f0eaa
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/AvgPool.test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/AvgPool.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *avgpool_01_pbtxtdata = STRING_CONTENT(
+ name: "avgpool"
+ op: "AvgPool"
+ input: "const/float"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "ksize"
+ value {
+ list {
+ i: 1
+ i: 2
+ i: 3
+ i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "VALID"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1
+ i: 3
+ i: 2
+ i: 1
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, AvgPool_01)
+{
+ TFNodeBuildTester tester;
+ moco::AvgPoolGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(avgpool_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFAvgPool
+ // - input should exist
+ // - attributes value should match
+
+ tester.inputs({"const/float"});
+ tester.output("avgpool");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFAvgPool *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ ASSERT_EQ(test_node->padding(), "VALID");
+ ASSERT_EQ(test_node->ksize(), std::vector<int64_t>({1, 2, 3, 1}));
+ ASSERT_EQ(test_node->strides(), std::vector<int64_t>({1, 3, 2, 1}));
+}
diff --git a/compiler/moco/import/src/Nodes/BiasAdd.cpp b/compiler/moco/import/src/Nodes/BiasAdd.cpp
new file mode 100644
index 000000000..a3eb91116
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/BiasAdd.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/BiasAdd.h"
+
+#include <moco/IR/Nodes/TFBiasAdd.h>
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <vector>
+
+namespace
+{
+using namespace moco;
+
+class TFBiasAddGraphUpdate final : public GraphUpdate
+{
+public:
+ TFBiasAddGraphUpdate(TFBiasAdd *biasadd, std::vector<TensorName> &names)
+ : _biasadd(biasadd), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFBiasAdd *_biasadd;
+ std::vector<TensorName> _names;
+};
+
+void TFBiasAddGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 2);
+
+ auto value_node = node_table->node(_names[0]);
+ auto bias_node = node_table->node(_names[1]);
+ assert(value_node != nullptr);
+ assert(bias_node != nullptr);
+
+ _biasadd->value(value_node);
+ _biasadd->bias(bias_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool BiasAddGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ // note: even though "data_format" is not entered when a model is written,
+ // TF seems to generate "data_format" field into a pb file
+ if (!plier::tf::has_attrs(node, {"T", "data_format"}))
+ return false;
+
+ // TODO add type check
+ // type of input and bias should be same (except using quantization)
+
+ // Note In case of TF.nn.bias_add,
+ // "value may have any number of dimensions." ...
+ // but "data_format: A string. 'NHWC' and 'NCHW' are supported."
+ // Not sure if value should be 4-D tensor. Let's skip this check for now.
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("BiasAdd Unsupported data_format", node.name());
+ }
+
+ return true;
+}
+
+void BiasAddGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // tensorflow data_format: one of NHWC or NCHW.
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ auto tf_bias_add = graph->nodes()->create<TFBiasAdd>();
+ tf_bias_add->name(node.name());
+ tf_bias_add->data_layout(data_layout);
+
+ // To set the input node of encode_node with biasAdd_name
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_bias_add);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0)));
+ input_names.push_back(TensorName(node.input(1)));
+
+ auto update = stdex::make_unique<TFBiasAddGraphUpdate>(tf_bias_add, input_names);
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/BiasAdd.test.cpp b/compiler/moco/import/src/Nodes/BiasAdd.test.cpp
new file mode 100644
index 000000000..626456d30
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/BiasAdd.test.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/BiasAdd.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *bias_add_01_pbtxtdata = STRING_CONTENT(
+ name: "out"
+ op: "BiasAdd"
+ input: "val"
+ input: "bias"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "data_format"
+ value { s: "NHWC" }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, bias_add_01)
+{
+ TFNodeBuildTester tester;
+ moco::BiasAddGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(bias_add_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFBiasAdd
+ // - value() should not be nullptr
+ // - bias() should not be nullptr
+ // - data_layout should match
+
+ tester.inputs({"val", "bias"});
+ tester.output("out");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFBiasAdd *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_TRUE(test_node->data_layout() == "NHWC");
+}
+
+namespace
+{
+
+// clang-format off
+const char *bias_add_NCHW_pbtxtdata = STRING_CONTENT(
+ name: "out"
+ op: "BiasAdd"
+ input: "val"
+ input: "bias"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "data_format"
+ value { s: "NCHW" }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, bias_add_NCHW_axis)
+{
+ TFNodeBuildTester tester;
+ moco::BiasAddGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(bias_add_NCHW_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFBiasAdd
+ // - value() should not be nullptr
+ // - bias() should not be nullptr
+ // - data_layout should match
+
+ tester.inputs({"val", "bias"});
+ tester.output("out");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFBiasAdd *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_TRUE(test_node->data_layout() == "NCHW");
+}
diff --git a/compiler/moco/import/src/Nodes/Concat.cpp b/compiler/moco/import/src/Nodes/Concat.cpp
new file mode 100644
index 000000000..8bf8a84b5
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Concat.cpp
@@ -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 "moco/Import/Nodes/Concat.h"
+
+#include <moco/IR/Nodes/TFConcatV2.h>
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+#include <cassert>
+
+namespace
+{
+
+using namespace moco;
+
+class TFConcatV2GraphUpdate final : public GraphUpdate
+{
+public:
+ TFConcatV2GraphUpdate(TFConcatV2 *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFConcatV2 *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFConcatV2GraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ uint32_t num_values = _names.size() - 1; // exclude axis
+ assert(num_values >= 1);
+
+ for (uint32_t i = 0; i < num_values; ++i)
+ {
+ auto input_node = tensor_names->node(_names[i]);
+ assert(input_node != nullptr);
+ _node->values(i, input_node);
+ }
+ auto axis_node = tensor_names->node(_names[num_values]);
+ assert(axis_node != nullptr);
+ _node->axis(axis_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ConcatV2GraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (!plier::tf::has_attrs(node, {"T", "N", "Tidx"}))
+ return false;
+
+ // Concat node SHOULD have 3 or more inputs, that is 2 + axis
+ const int num_inputs = node.input_size() - 1;
+ return (num_inputs >= 2) && (num_inputs == plier::tf::get_int_attr(node, "N"));
+}
+
+void ConcatV2GraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+ auto tensor_names = context->tensor_names();
+ auto updates = context->updates();
+
+ const int num_inputs = node.input_size() - 1;
+ std::vector<TensorName> input_names;
+ auto concat_node = graph->nodes()->create<TFConcatV2>(num_inputs);
+ concat_node->name(node.name());
+
+ for (int ni = 0; ni < num_inputs; ++ni)
+ {
+ input_names.push_back(TensorName(node.input(ni)));
+ }
+ // last one is the axis
+ input_names.push_back(TensorName(node.input(num_inputs)));
+
+ // register string-name to the last node as output of concat(s)
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, concat_node);
+
+ auto update = stdex::make_unique<TFConcatV2GraphUpdate>(concat_node, input_names);
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Concat.test.cpp b/compiler/moco/import/src/Nodes/Concat.test.cpp
new file mode 100644
index 000000000..c0986578b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Concat.test.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Concat.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *concat_01_pbtxtdata = STRING_CONTENT(
+ name: "Concat"
+ op: "ConcatV2"
+ input: "Input01"
+ input: "Input02"
+ input: "Axis"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tidx"
+ value {
+ type: DT_INT32
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, concat_01)
+{
+ TFNodeBuildTester tester;
+ moco::ConcatV2GraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(concat_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConcatV2
+ // - there should be two values
+ // - values(idx) should not be nullptr
+ // - axis() should not be nullptr
+
+ tester.inputs({"Input01", "Input02", "Axis"});
+ tester.output("Concat");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConcatV2 *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->num_values(), 2);
+}
+
+namespace
+{
+
+// clang-format off
+const char *concat_02_pbtxtdata = STRING_CONTENT(
+ name: "Concat"
+ op: "ConcatV2"
+ input: "Input01"
+ input: "Input02"
+ input: "Input03"
+ input: "Axis"
+ attr {
+ key: "N"
+ value {
+ i: 3
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tidx"
+ value {
+ type: DT_INT32
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, concat_02)
+{
+ TFNodeBuildTester tester;
+ moco::ConcatV2GraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(concat_02_pbtxtdata, nodedef));
+
+ // what to test: TFConcatV2 has 3 inputs
+ // - there should exist TFConcatV2
+ // - values(idx) should not be nullptr
+ // - axis() should not be nullptr
+
+ tester.inputs({"Input01", "Input02", "Input03", "Axis"});
+ tester.output("Concat");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConcatV2 *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->num_values(), 3);
+}
diff --git a/compiler/moco/import/src/Nodes/Const.cpp b/compiler/moco/import/src/Nodes/Const.cpp
new file mode 100644
index 000000000..15ea717db
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Const.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Const.h"
+
+#include <moco/Names.h>
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <stdexcept>
+#include <string>
+
+namespace
+{
+
+using namespace moco;
+
+void read_value_int8(TFConst *const_node, int num_elements,
+ const tensorflow::TensorProto &input_tensor)
+{
+ const_node->size<loco::DataType::S8>(num_elements);
+
+ int32_t input_elements = input_tensor.int_val_size();
+
+ if (input_tensor.tensor_content().size() == num_elements * sizeof(int8_t))
+ {
+ const std::string &str_content = input_tensor.tensor_content();
+ const int8_t *s8_ptr = reinterpret_cast<const int8_t *>(str_content.c_str());
+ for (int32_t i = 0; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::S8>(i) = *(s8_ptr + i);
+ }
+ }
+ else if (0 < input_elements && input_elements <= num_elements)
+ {
+ for (int32_t i = 0; i < input_elements; i++)
+ {
+ const_node->at<loco::DataType::S8>(i) = input_tensor.int_val(i);
+ }
+
+ for (int32_t i = input_elements; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::S8>(i) = input_tensor.int_val(input_elements - 1);
+ }
+ }
+ else
+ {
+ throw oops::UserExn("Invalid Const values", const_node->name());
+ }
+}
+
+void read_value_int32(TFConst *const_node, int num_elements,
+ const tensorflow::TensorProto &input_tensor)
+{
+ const_node->size<loco::DataType::S32>(num_elements);
+
+ int32_t input_elements = input_tensor.int_val_size();
+
+ if (input_tensor.tensor_content().size() == num_elements * sizeof(int32_t))
+ {
+ const std::string &str_content = input_tensor.tensor_content();
+ const int32_t *s32_ptr = reinterpret_cast<const int32_t *>(str_content.c_str());
+ for (int32_t i = 0; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::S32>(i) = *(s32_ptr + i);
+ }
+ }
+ else if (0 < input_elements && input_elements <= num_elements)
+ {
+ for (int32_t i = 0; i < input_elements; i++)
+ {
+ const_node->at<loco::DataType::S32>(i) = input_tensor.int_val(i);
+ }
+
+ for (int32_t i = input_elements; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::S32>(i) = input_tensor.int_val(input_elements - 1);
+ }
+ }
+ else
+ {
+ throw oops::UserExn("Invalid Const values", const_node->name());
+ }
+}
+
+void read_value_float32(TFConst *const_node, int num_elements,
+ const tensorflow::TensorProto &input_tensor)
+{
+ const_node->size<loco::DataType::FLOAT32>(num_elements);
+
+ int32_t input_elements = input_tensor.float_val_size();
+
+ if (input_tensor.tensor_content().size() == num_elements * sizeof(float))
+ {
+ const std::string &str_content = input_tensor.tensor_content();
+ const float *float_ptr = reinterpret_cast<const float *>(str_content.c_str());
+ for (int32_t i = 0; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::FLOAT32>(i) = *(float_ptr + i);
+ }
+ }
+ else if (0 < input_elements && input_elements <= num_elements)
+ {
+ for (int32_t i = 0; i < input_elements; i++)
+ {
+ const_node->at<loco::DataType::FLOAT32>(i) = input_tensor.float_val(i);
+ }
+
+ for (int32_t i = input_elements; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::FLOAT32>(i) = input_tensor.float_val(input_elements - 1);
+ }
+ }
+ else
+ {
+ throw oops::UserExn("Invalid Const values", const_node->name());
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ConstGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (!plier::tf::has_attrs(node, {"dtype", "value"}))
+ return false;
+
+ const auto &input_tensor = plier::tf::get_tensor_attr(node, "value");
+ const auto &input_shape = input_tensor.tensor_shape();
+ const auto &input_dims = input_shape.dim();
+
+ if (!(input_shape.dim_size() <= 6))
+ return false;
+
+ for (auto &d : input_dims)
+ {
+ if (d.size() > std::numeric_limits<int>::max())
+ throw oops::UserExn("Const Shape element overflows", node.name());
+
+ if (d.size() < 0)
+ throw oops::UserExn("Unknown dim size", node.name());
+ }
+
+ auto dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "dtype"));
+ if (!(dtype == loco::DataType::S32 || dtype == loco::DataType::FLOAT32 ||
+ dtype == loco::DataType::S8))
+ return false;
+ // TODO support other dtype
+
+ return true;
+}
+
+void ConstGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+
+ // Create a "TFConstant" node for Const
+ auto const_node = graph->nodes()->create<TFConst>();
+ const_node->name(node.name());
+
+ // set dtype
+ auto dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "dtype"));
+ const_node->dtype(dtype);
+
+ // import shape and value
+ const auto &input_tensor = plier::tf::get_tensor_attr(node, "value");
+ const auto &input_shape = input_tensor.tensor_shape();
+ const auto &input_dims = input_shape.dim();
+ assert(input_shape.dim_size() <= 6);
+ const_node->rank(input_shape.dim_size());
+ int index = 0;
+ bool zero_sized_shape = false;
+ for (auto &d : input_dims)
+ {
+ assert(d.size() <= std::numeric_limits<int>::max());
+ if (d.size() == 0)
+ zero_sized_shape = true;
+
+ assert(d.size() >= 0);
+ const_node->dim(index++) = d.size();
+ }
+
+ int num_elements = 1;
+ if (zero_sized_shape)
+ {
+ const_node->rank(0);
+ num_elements = 0;
+ }
+ else
+ {
+ for (uint32_t d = 0; d < const_node->rank(); d++)
+ {
+ num_elements *= const_node->dim(d).value();
+ }
+ }
+
+ switch (dtype)
+ {
+ case loco::DataType::S8:
+ read_value_int8(const_node, num_elements, input_tensor);
+ break;
+
+ case loco::DataType::S32:
+ read_value_int32(const_node, num_elements, input_tensor);
+ break;
+
+ case loco::DataType::FLOAT32:
+ read_value_float32(const_node, num_elements, input_tensor);
+ break;
+
+ // TODO support other types
+
+ default:
+ assert(false);
+ }
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, const_node);
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Const.test.cpp b/compiler/moco/import/src/Nodes/Const.test.cpp
new file mode 100644
index 000000000..854499fe6
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Const.test.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Const.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// Test case for "input_tensor.float_val_size() == num_elements"
+
+// clang-format off
+const char *const_float_01_pbtxtdata = STRING_CONTENT(
+ name: "const/float"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ float_val: 1.1
+ float_val: 2.2
+ float_val: 3.3
+ float_val: 4.4
+ float_val: 5.5
+ float_val: 6.6
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_float_01)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_float_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/float");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::FLOAT32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(0), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(1), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(2), 3.3f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(3), 4.4f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(4), 5.5f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(5), 6.6f);
+}
+
+namespace
+{
+// Test case for "input_tensor.float_val_size() == 1"
+
+// clang-format off
+const char *const_float_02_pbtxtdata = STRING_CONTENT(
+ name: "const/float"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ float_val: 1.1
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_float_02)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_float_02_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/float");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::FLOAT32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(0), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(1), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(2), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(3), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(4), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(5), 1.1f);
+}
+
+namespace
+{
+// Test case for "input_tensor.tensor_content().size() == num_elements * sizeof(float)"
+// Generated with tfkit tool: "cat ./test.pbtxt | ./tfkit pack"
+
+// clang-format off
+const char *const_float_03_pbtxtdata = STRING_CONTENT(
+ name: "const/float"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ tensor_content: "\315\314\214?\315\314\014@33S@\315\314\214@\000\000\260@33\323@"
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_float_03)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_float_03_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/float");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::FLOAT32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(0), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(1), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(2), 3.3f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(3), 4.4f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(4), 5.5f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(5), 6.6f);
+}
+
+namespace
+{
+// Test case for "input_tensor.float_val_size() < num_elements"
+
+// clang-format off
+const char *const_float_04_pbtxtdata = STRING_CONTENT(
+ name: "const/float"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ float_val: 1.1
+ float_val: 2.2
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_float_04)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_float_04_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/float");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::FLOAT32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(0), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(1), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(2), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(3), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(4), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(5), 2.2f);
+}
+
+namespace
+{
+// Test case for "input_tensor.int_val_size() < num_elements"
+
+// clang-format off
+const char *const_int32_04_pbtxtdata = STRING_CONTENT(
+ name: "const/int"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ int_val: 1
+ int_val: 2
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_int32_04)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_int32_04_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/int");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::S32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(0), 1);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(1), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(2), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(3), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(4), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(5), 2);
+}
+
+namespace
+{
+// Test case for "scalar"
+
+// clang-format off
+const char *const_int32_scalar_pbtxtdata = STRING_CONTENT(
+ name: "const/int"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_int32_scalar)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_int32_scalar_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - there should be one element and value should be 3
+
+ tester.inputs({});
+ tester.output("const/int");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::S32>(), 1);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(0), 3);
+}
+
+namespace
+{
+
+// clang-format off
+const char *const_int8_01_pbtxtdata = STRING_CONTENT(
+ name: "const/int8"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT8
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT8
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ int_val: 0
+ int_val: -1
+ int_val: 1
+ int_val: 2
+ int_val: 3
+ int_val: 4
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_int8_01)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_int8_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/int8");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::S8>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(0), 0);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(1), -1);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(2), 1);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(3), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(4), 3);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(5), 4);
+}
diff --git a/compiler/moco/import/src/Nodes/Conv2D.cpp b/compiler/moco/import/src/Nodes/Conv2D.cpp
new file mode 100644
index 000000000..e6b98dcd1
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Conv2D.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Conv2D.h"
+
+#include <moco/IR/Nodes/TFConv2D.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <loco.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <stdexcept>
+#include <algorithm>
+
+namespace
+{
+using namespace moco;
+
+class TFConv2DGraphUpdate final : public GraphUpdate
+{
+public:
+ TFConv2DGraphUpdate(TFConv2D *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFConv2D *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFConv2DGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 2);
+
+ auto input_node = node_table->node(_names[0]);
+ auto filter_node = node_table->node(_names[1]);
+ assert(input_node != nullptr);
+ assert(filter_node != nullptr);
+
+ _node->input(input_node);
+ _node->filter(filter_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool Conv2DGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ // note: even though "data_format" is not entered when a model is written,
+ // TF seems to generate "data_format" field into a pb file
+ if (!plier::tf::has_attrs(node, {"T", "data_format", "padding", "strides"}))
+ return false;
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("Conv2D Unsupported data_format", node.name());
+ }
+
+ // dilation attribute is not fully supported
+ if (plier::tf::has_attr(node, "dilations"))
+ {
+ // TODO Support non-default dilations
+ auto dilation = plier::tf::get_list_attr(node, "dilations").i();
+ if (!std::all_of(dilation.begin(), dilation.end(), [](std::int64_t dil) { return dil == 1; }))
+ return false;
+ }
+ // Else, dilations are automatically set to default [1,1,1,1] which we assumes now
+
+ return true;
+}
+
+void Conv2DGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ std::string conv2d_name = node.name();
+
+ auto conv2d = graph->nodes()->create<TFConv2D>();
+ conv2d->name(node.name());
+
+ // read attributes
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ assert(data_layout == "NHWC" || data_layout == "NCHW");
+ conv2d->data_layout(data_layout);
+
+ auto tf_strides = plier::tf::get_list_attr(node, "strides");
+ auto strides = plier::tf::as_int64_list(tf_strides);
+ conv2d->strides(strides);
+
+ auto padding = moco::str_toupper(plier::tf::get_string_attr(node, "padding"));
+ assert(padding == "VALID" || padding == "SAME");
+ conv2d->padding(padding);
+
+ // save the name for graph link updates
+ TensorName output_name(conv2d_name, 0);
+ tensor_names->enroll(output_name, conv2d);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // input
+ input_names.push_back(TensorName(node.input(1))); // kernel
+
+ // Record ifm inputs to featureEncode_node
+ auto tfconv2d_update = stdex::make_unique<TFConv2DGraphUpdate>(conv2d, input_names);
+
+ updates->enroll(std::move(tfconv2d_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Conv2D.test.cpp b/compiler/moco/import/src/Nodes/Conv2D.test.cpp
new file mode 100644
index 000000000..ba006f489
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Conv2D.test.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Conv2D.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *conv2d_01_pbtxtdata = STRING_CONTENT(
+ name: "conv2d"
+ op: "Conv2D"
+ input: "ifm"
+ input: "ker"
+ attr { key: "T" value { type: DT_FLOAT } }
+ attr { key: "data_format" value { s: "NHWC" } }
+ attr { key: "dilations" value { list { i: 1 i: 1 i: 1 i: 1 } } }
+ attr { key: "padding" value { s: "VALID" } }
+ attr { key: "strides" value { list { i: 1 i: 2 i: 3 i: 1 } } }
+);
+// clang-format on
+} // namespace
+
+TEST(TensorFlowImport, Conv2D_01)
+{
+ TFNodeBuildTester tester;
+ moco::Conv2DGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(conv2d_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - Conv2D node should exist
+ // - ifm() should not be nullptr
+ // - ker() should not be nullptr
+ // - attribute values should match
+
+ tester.inputs({"ifm", "ker"});
+ tester.output("conv2d");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConv2D *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->padding(), "VALID");
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ auto strides = test_node->strides();
+ ASSERT_EQ(strides.size(), 4);
+ // TODO add verify dilation
+}
+
+namespace
+{
+// clang-format off
+const char *conv2d_inception_pbtxtdata = STRING_CONTENT(
+ name: "InceptionV3/InceptionV3/Conv2d_1a_3x3/Conv2D"
+ op: "Conv2D"
+ input: "input:0"
+ input: "InceptionV3/Conv2d_1a_3x3/weights/read/_3__cf__3"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "data_format"
+ value { s: "NHWC" }
+ }
+ attr {
+ key: "dilations"
+ value {
+ list { i: 1 i: 1 i: 1 i: 1 }
+ }
+ }
+ attr {
+ key: "padding"
+ value { s: "VALID" }
+ }
+ attr {
+ key: "strides"
+ value {
+ list { i: 1 i: 2 i: 2 i: 1 }
+ }
+ }
+);
+} // namespace
+
+TEST(TensorFlowImport, Conv2D_inception_indexed_tensor_name)
+{
+ TFNodeBuildTester tester;
+ moco::Conv2DGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(conv2d_inception_pbtxtdata, nodedef));
+
+ // what to test: name with ':0' should be treated correctly
+ // - Conv2D node should exist
+ // - ifm() should not be nullptr
+ // - ker() should not be nullptr
+
+ tester.inputs({"input", "InceptionV3/Conv2d_1a_3x3/weights/read/_3__cf__3"});
+ tester.output("InceptionV3/InceptionV3/Conv2d_1a_3x3/Conv2D");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Conv2DBackpropInput.cpp b/compiler/moco/import/src/Nodes/Conv2DBackpropInput.cpp
new file mode 100644
index 000000000..74c6605ab
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Conv2DBackpropInput.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Conv2DBackpropInput.h"
+
+#include <moco/IR/Nodes/TFConv2DBackpropInput.h>
+
+#include "Convert.h"
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+namespace
+{
+using namespace moco;
+
+/// @brief GraphUpdate for Conv2DBackpropInput node
+class Conv2DBackpropInputGraphUpdate final : public GraphUpdate
+{
+public:
+ Conv2DBackpropInputGraphUpdate(TFConv2DBackpropInput *node, std::vector<TensorName> names)
+ : _node(node), _input_names(names)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFConv2DBackpropInput *_node;
+ std::vector<TensorName> _input_names;
+};
+
+void Conv2DBackpropInputGraphUpdate::input(const SymbolTable *table) const
+{
+ assert(_input_names.size() == 3);
+
+ auto input_sizes_node = table->node(_input_names[0]);
+ auto filter_node = table->node(_input_names[1]);
+ auto out_backprop_node = table->node(_input_names[2]);
+
+ assert(input_sizes_node != nullptr);
+ assert(filter_node != nullptr);
+ assert(out_backprop_node != nullptr);
+
+ _node->input_sizes(input_sizes_node);
+ _node->filter(filter_node);
+ _node->out_backprop(out_backprop_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool Conv2DBackpropInputGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 3)
+ return false;
+
+ if (!plier::tf::has_attrs(node, {"T", "data_format", "padding", "strides"}))
+ return false;
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("Conv2DBackprop Unsupported data_format", node.name());
+ }
+
+ // dilation attribute is not fully supported
+ if (plier::tf::has_attr(node, "dilations"))
+ {
+ // TODO Support non-default dilations
+ auto dilation = plier::tf::get_list_attr(node, "dilations").i();
+ if (!std::all_of(dilation.begin(), dilation.end(), [](std::int64_t dil) { return dil == 1; }))
+ return false;
+ }
+ // Else, dilations are automatically set to default [1,1,1,1] which we assumes now
+
+ return true;
+}
+
+void Conv2DBackpropInputGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ std::string conv2d_backprop_name = node.name();
+
+ auto conv2d_backprop = graph->nodes()->create<TFConv2DBackpropInput>();
+ conv2d_backprop->name(node.name());
+
+ // read attributes
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ assert(data_layout == "NHWC" || data_layout == "NCHW");
+ conv2d_backprop->data_layout(data_layout);
+
+ auto tf_strides = plier::tf::get_list_attr(node, "strides");
+ auto strides = plier::tf::as_int64_list(tf_strides);
+ conv2d_backprop->strides(strides);
+
+ auto padding = moco::str_toupper(plier::tf::get_string_attr(node, "padding"));
+ assert(padding == "VALID" || padding == "SAME");
+ conv2d_backprop->padding(padding);
+
+ // save the name for graph link updates
+ TensorName output_name(conv2d_backprop_name, 0);
+ tensor_names->enroll(output_name, conv2d_backprop);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // input_sizes
+ input_names.push_back(TensorName(node.input(1))); // filter
+ input_names.push_back(TensorName(node.input(2))); // out_backprop
+
+ // update
+ auto conv2d_backprop_update =
+ stdex::make_unique<Conv2DBackpropInputGraphUpdate>(conv2d_backprop, input_names);
+
+ updates->enroll(std::move(conv2d_backprop_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Conv2DBackpropInput.test.cpp b/compiler/moco/import/src/Nodes/Conv2DBackpropInput.test.cpp
new file mode 100644
index 000000000..8c462bc3b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Conv2DBackpropInput.test.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Conv2DBackpropInput.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *conv2d_backprop_input_01_pbtxtdata = STRING_CONTENT(
+ name: "ofm"
+ op: "Conv2DBackpropInput"
+ input: "outshape"
+ input: "weights"
+ input: "ifm"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "dilations"
+ value {
+ list {
+ i: 1
+ i: 1
+ i: 1
+ i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "SAME"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1
+ i: 2
+ i: 2
+ i: 1
+ }
+ }
+ }
+);
+// clang-format on
+} // namespace
+
+TEST(TensorFlowImport, conv2d_backprop_input_01)
+{
+ TFNodeBuildTester tester;
+ moco::Conv2DBackpropInputGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(conv2d_backprop_input_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - All node inputs are valid
+ // - All attributes are as expected
+
+ tester.inputs({"outshape", "weights", "ifm"});
+ tester.output("ofm");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConv2DBackpropInput *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->padding(), "SAME");
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ ASSERT_EQ(test_node->strides().size(), 4);
+}
diff --git a/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.cpp b/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.cpp
new file mode 100644
index 000000000..3991a4d51
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/DepthwiseConv2dNative.h"
+
+#include <moco/IR/Nodes/TFDepthwiseConv2dNative.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <plier/tf/Convert.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+
+using namespace plier::tf;
+
+namespace
+{
+using namespace moco;
+
+class TFDepthwiseConv2dNativeGraphUpdate final : public GraphUpdate
+{
+public:
+ TFDepthwiseConv2dNativeGraphUpdate(TFDepthwiseConv2dNative *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFDepthwiseConv2dNative *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFDepthwiseConv2dNativeGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 2);
+
+ auto input_node = node_table->node(_names[0]);
+ auto filter_node = node_table->node(_names[1]);
+ assert(input_node != nullptr);
+ assert(filter_node != nullptr);
+
+ _node->input(input_node);
+ _node->filter(filter_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool DepthwiseConv2dNativeGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ // note: even though "data_format" and "dilations" are not entered when a model is written,
+ // TF seems to generate those field into a pb file.
+ if (!has_attrs(node, {"T", "data_format", "dilations", "padding", "strides"}))
+ return false;
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("DepthwiseConv2dNative Unsupported data_format", node.name());
+ }
+
+ auto padding = moco::str_toupper(get_string_attr(node, "padding"));
+ if (!(padding == "VALID" || padding == "SAME"))
+ return false;
+
+ auto tf_strides = get_list_attr(node, "strides");
+ auto strides = as_int64_list(tf_strides);
+ if (!(strides.size() == 4))
+ {
+ throw oops::UserExn("DepthwiseConv2dNative strides requires rank 4", node.name());
+ }
+ auto stride_n = strides.at(0);
+ auto stride_h = strides.at(1);
+ auto stride_w = strides.at(2);
+ auto stride_c = strides.at(3);
+ if (!(stride_n == 1 && stride_c == 1) || !(stride_h == stride_w))
+ {
+ // TODO this message may need to be refined
+ throw oops::UserExn("DepthwiseConv2dNative strides requires N=C=1, H=W", node.name());
+ }
+
+ return true;
+}
+
+void DepthwiseConv2dNativeGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ auto depthwiseconv2d_native_node = graph->nodes()->create<TFDepthwiseConv2dNative>();
+ depthwiseconv2d_native_node->name(node.name());
+
+ // read attributes
+ auto data_layout = get_string_attr(node, "data_format");
+ depthwiseconv2d_native_node->data_layout(data_layout);
+
+ auto tf_strides = get_list_attr(node, "strides");
+ auto strides = as_int64_list(tf_strides);
+ depthwiseconv2d_native_node->strides(strides);
+
+ auto padding = moco::str_toupper(get_string_attr(node, "padding"));
+ depthwiseconv2d_native_node->padding(padding);
+
+ // save the name for graph link updates
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, depthwiseconv2d_native_node);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // input
+ input_names.push_back(TensorName(node.input(1))); // kernel
+
+ // Record ifm inputs to featureEncode_node
+ auto tfdepthwiseconv2dnative_update = stdex::make_unique<TFDepthwiseConv2dNativeGraphUpdate>(
+ depthwiseconv2d_native_node, input_names);
+
+ updates->enroll(std::move(tfdepthwiseconv2dnative_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.test.cpp b/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.test.cpp
new file mode 100644
index 000000000..c65283c1b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.test.cpp
@@ -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.
+ */
+
+#include "moco/Import/Nodes/DepthwiseConv2dNative.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *depthwise_conv2d_native_01_pbtxtdata = STRING_CONTENT(
+ name: "depthwise"
+ op: "DepthwiseConv2dNative"
+ input: "input"
+ input: "filter"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "dilations"
+ value {
+ list {
+ i: 1
+ i: 1
+ i: 1
+ i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "VALID"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1
+ i: 1
+ i: 1
+ i: 1
+ }
+ }
+ }
+);
+// clang-format on
+} // namespace
+
+TEST(TensorFlowImport, Depthwise_conv2d_native)
+{
+ TFNodeBuildTester tester;
+ moco::DepthwiseConv2dNativeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(depthwise_conv2d_native_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - All node inputs are valid
+ // - All attributes are as expected
+
+ tester.inputs({"input", "filter"});
+ tester.output("depthwise");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFDepthwiseConv2dNative *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->padding(), "VALID");
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ ASSERT_EQ(test_node->strides().size(), 4);
+}
diff --git a/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.cpp b/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.cpp
new file mode 100644
index 000000000..d2fa3d1eb
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/FakeQuantWithMinMaxVars.h"
+
+#include <moco/IR/Nodes/TFFakeQuantWithMinMaxVars.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <plier/tf/Convert.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+
+#include <cassert>
+
+using namespace plier::tf;
+
+namespace
+{
+using namespace moco;
+
+class TFFakeQuantWithMinMaxVarsGraphUpdate final : public GraphUpdate
+{
+public:
+ TFFakeQuantWithMinMaxVarsGraphUpdate(TFFakeQuantWithMinMaxVars *node,
+ std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFFakeQuantWithMinMaxVars *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFFakeQuantWithMinMaxVarsGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 3);
+
+ auto inputs_node = node_table->node(_names[0]);
+ auto min_node = node_table->node(_names[1]);
+ auto max_node = node_table->node(_names[2]);
+ assert(inputs_node != nullptr);
+ assert(min_node != nullptr);
+ assert(max_node != nullptr);
+
+ _node->inputs(inputs_node);
+ _node->min(min_node);
+ _node->max(max_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool FakeQuantWithMinMaxVarsGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 3)
+ return false;
+
+ // attrs "narrow_range", "num_bits" are optional
+ return true;
+}
+
+void FakeQuantWithMinMaxVarsGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ auto fakequant_node = graph->nodes()->create<TFFakeQuantWithMinMaxVars>();
+ fakequant_node->name(node.name());
+
+ // read optional attributes
+ if (has_attr(node, "num_bits"))
+ {
+ auto num_bits = get_int_attr(node, "num_bits");
+ fakequant_node->num_bits(num_bits);
+ }
+ if (has_attr(node, "narrow_range"))
+ {
+ auto narrow_range = get_bool_attr(node, "narrow_range");
+ fakequant_node->narrow_range(narrow_range);
+ }
+
+ // save the name for graph link updates
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, fakequant_node);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // inputs
+ input_names.push_back(TensorName(node.input(1))); // min
+ input_names.push_back(TensorName(node.input(2))); // max
+
+ // Record ifm inputs to featureEncode_node
+ auto tffakequant_update =
+ stdex::make_unique<TFFakeQuantWithMinMaxVarsGraphUpdate>(fakequant_node, input_names);
+
+ updates->enroll(std::move(tffakequant_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.test.cpp b/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.test.cpp
new file mode 100644
index 000000000..40c494bb0
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.test.cpp
@@ -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 "moco/Import/Nodes/FakeQuantWithMinMaxVars.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *fakequant_01_pbtxtdata = STRING_CONTENT(
+ name: "FakeQuant"
+ op: "FakeQuantWithMinMaxVars"
+ input: "Input"
+ input: "FakeMin"
+ input: "FakeMax"
+ attr {
+ key: "narrow_range"
+ value { b: true }
+ }
+ attr {
+ key: "num_bits"
+ value { i: 16 }
+ }
+);
+// clang-format on
+} // namespace
+
+TEST(TensorFlowImport, FakeQuantWithMinMaxVars)
+{
+ TFNodeBuildTester tester;
+ moco::FakeQuantWithMinMaxVarsGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(fakequant_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - All node inputs are valid
+ // - All attributes are as expected
+
+ tester.inputs({"Input", "FakeMin", "FakeMax"});
+ tester.output("FakeQuant");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFFakeQuantWithMinMaxVars *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->narrow_range(), true);
+ ASSERT_EQ(test_node->num_bits(), 16);
+}
diff --git a/compiler/moco/import/src/Nodes/FusedBatchNorm.cpp b/compiler/moco/import/src/Nodes/FusedBatchNorm.cpp
new file mode 100644
index 000000000..59f98017c
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/FusedBatchNorm.cpp
@@ -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 "moco/Import/Nodes/FusedBatchNorm.h"
+
+#include <moco/IR/Nodes/TFFusedBatchNorm.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for FusedBatchNorm node
+ */
+class FusedBatchNormGraphUpdate final : public GraphUpdate
+{
+public:
+ FusedBatchNormGraphUpdate(TFFusedBatchNorm *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFFusedBatchNorm *_node;
+ std::vector<TensorName> _names;
+};
+
+void FusedBatchNormGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 5);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->scale(tensor_names->node(_names[1]));
+ _node->offset(tensor_names->node(_names[2]));
+ _node->mean(tensor_names->node(_names[3]));
+ _node->variance(tensor_names->node(_names[4]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool FusedBatchNormGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 5)
+ return false;
+
+ return plier::tf::has_attrs(node, {"epsilon"});
+}
+
+void FusedBatchNormGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ float epsilon = plier::tf::get_float_attr(node, "epsilon");
+
+ // creating TF dialect FusedBatchNorm node
+ auto tf_fbn = graph->nodes()->create<TFFusedBatchNorm>();
+ tf_fbn->name(node.name());
+ tf_fbn->epsilon(epsilon);
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_fbn);
+
+ std::vector<TensorName> fbn_input_names;
+ fbn_input_names.push_back(TensorName(node.input(0))); // input
+ fbn_input_names.push_back(TensorName(node.input(1))); // scale
+ fbn_input_names.push_back(TensorName(node.input(2))); // offset
+ fbn_input_names.push_back(TensorName(node.input(3))); // mean
+ fbn_input_names.push_back(TensorName(node.input(4))); // variance
+
+ auto tf_fbn_update = stdex::make_unique<FusedBatchNormGraphUpdate>(tf_fbn, fbn_input_names);
+ updates->enroll(std::move(tf_fbn_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/FusedBatchNorm.test.cpp b/compiler/moco/import/src/Nodes/FusedBatchNorm.test.cpp
new file mode 100644
index 000000000..0f2e037b8
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/FusedBatchNorm.test.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/FusedBatchNorm.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *fbn_basic_pbtxt = STRING_CONTENT(
+ name: "FBN_01"
+ op: "FusedBatchNorm"
+ input: "input"
+ input: "gamma"
+ input: "beta"
+ input: "FBN_01/mean"
+ input: "FBN_01/variance"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "epsilon"
+ value {
+ f: 0.001
+ }
+ }
+ attr {
+ key: "is_training"
+ value {
+ b: false
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_fbn_basic)
+{
+ TFNodeBuildTester tester;
+ moco::FusedBatchNormGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(fbn_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - there should exist a TFFusedBatchNorm
+ // - input() should not be nullptr
+ // - gamma() should not be nullptr
+ // - beta() should not be nullptr
+ // - mean() should not be nullptr
+ // - variance() should not be nullptr
+ // - epsilon() value should match
+
+ tester.inputs({"input", "gamma", "beta", "FBN_01/mean", "FBN_01/variance"});
+ tester.output("FBN_01");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFFusedBatchNorm *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->epsilon(), 0.001f);
+}
diff --git a/compiler/moco/import/src/Nodes/Identity.cpp b/compiler/moco/import/src/Nodes/Identity.cpp
new file mode 100644
index 000000000..8ca0e2d01
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Identity.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Identity.h"
+
+#include <moco/IR/Nodes/TFIdentity.h>
+
+#include <moco/Names.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <vector>
+
+namespace
+{
+
+using namespace moco;
+
+class TFIdentityGraphUpdate final : public GraphUpdate
+{
+public:
+ TFIdentityGraphUpdate(TFIdentity *node, const std::vector<TensorName> &names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFIdentity *_node;
+ const std::vector<TensorName> _names;
+};
+
+void TFIdentityGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ for (auto &name : _names)
+ {
+ loco::Node *target = tensor_names->node(name);
+ _node->input(target);
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool IdentityGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() < 1) // from TensorFlow lite toco
+ return false;
+
+ return true;
+}
+
+void IdentityGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // Create a Identity node
+ auto identity_node = graph->nodes()->create<TFIdentity>();
+ identity_node->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, identity_node);
+
+ // Queue node input update
+ // TODO: Check if we really need multiple input handlings
+ std::vector<TensorName> names;
+ for (int i = 0; i < node.input_size(); ++i)
+ {
+ names.emplace_back(TensorName(node.input(i)));
+ }
+ auto update = stdex::make_unique<TFIdentityGraphUpdate>(identity_node, names);
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/MaxPool.cpp b/compiler/moco/import/src/Nodes/MaxPool.cpp
new file mode 100644
index 000000000..63275a3b8
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/MaxPool.cpp
@@ -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 "moco/Import/Nodes/MaxPool.h"
+
+#include <moco/IR/Nodes/TFMaxPool.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <loco.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+
+using namespace moco;
+
+class TFMaxPoolGraphUpdate final : public GraphUpdate
+{
+public:
+ TFMaxPoolGraphUpdate(TFMaxPool *node, const TensorName &name)
+ : _maxpool_node(node), _input_name(name)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFMaxPool *_maxpool_node;
+ const TensorName _input_name;
+};
+
+void TFMaxPoolGraphUpdate::input(const SymbolTable *node_table) const
+{
+ loco::Node *input_node = node_table->node(_input_name);
+ _maxpool_node->input(input_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool MaxPoolGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // note: even though "data_format" is not entered when a model is written,
+ // TF seems to generate "data_format" field into a pb file
+ if (!plier::tf::has_attrs(node, {"T", "data_format", "ksize", "padding", "strides"}))
+ return false;
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("MaxPool Unsupported data_format", node.name());
+ }
+
+ auto tf_ksize = plier::tf::get_list_attr(node, "ksize");
+ auto ksize = plier::tf::as_int64_list(tf_ksize);
+ if (ksize.size() != 4)
+ {
+ // TODO support ksize length for 1 and 2
+ throw oops::UserExn("MaxPool ksize requires rank 4", node.name());
+ }
+
+ auto tf_strides = plier::tf::get_list_attr(node, "strides");
+ auto strides = plier::tf::as_int64_list(tf_strides);
+ if (strides.size() != 4)
+ {
+ // TODO support strides length for 1 and 2
+ throw oops::UserExn("MaxPool strides requires rank 4", node.name());
+ }
+
+ return true;
+}
+
+void MaxPoolGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ ::std::string node_name = node.name();
+
+ // tensorflow data_format: one of NHWC or NCHW.
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ auto maxPool_node = graph->nodes()->create<TFMaxPool>();
+ maxPool_node->name(node.name());
+ maxPool_node->data_layout(data_layout);
+
+ // padding
+ auto padding = moco::str_toupper(plier::tf::get_string_attr(node, "padding"));
+ maxPool_node->padding(padding);
+
+ // ksize
+ auto tf_ksize = plier::tf::get_list_attr(node, "ksize");
+ auto ksize = plier::tf::as_int64_list(tf_ksize);
+ assert(ksize.size() == 4);
+ maxPool_node->ksize(ksize);
+
+ // strides
+ auto tf_strides = plier::tf::get_list_attr(node, "strides");
+ auto strides = plier::tf::as_int64_list(tf_strides);
+ assert(strides.size() == 4);
+ maxPool_node->strides(strides);
+
+ // To set the input node of encode_node with node_name
+ TensorName output_name(node_name, 0);
+ tensor_names->enroll(output_name, maxPool_node);
+
+ // Record ifm inputs to featureEncode_node
+ auto update = stdex::make_unique<TFMaxPoolGraphUpdate>(maxPool_node, TensorName(node.input(0)));
+
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
+
+// TODO Consider a case when TF MaxPool is for 3D.
+// MaxPool works for 2D and other Dimensions, such as 3D
+// So, in future, some other GraphBuilder decide if MaxPoolGraphBuilder is used or
+// other GraphBuilder is used for TF MaxPool
diff --git a/compiler/moco/import/src/Nodes/MaxPool.test.cpp b/compiler/moco/import/src/Nodes/MaxPool.test.cpp
new file mode 100644
index 000000000..a85e2027b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/MaxPool.test.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/MaxPool.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *maxpool_01_pbtxtdata = STRING_CONTENT(
+ name: "maxpool"
+ op: "MaxPool"
+ input: "const/float"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "ksize"
+ value {
+ list {
+ i: 1
+ i: 2
+ i: 3
+ i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "VALID"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1
+ i: 3
+ i: 2
+ i: 1
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, MaxPool_01)
+{
+ TFNodeBuildTester tester;
+ moco::MaxPoolGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(maxpool_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFMaxPool
+ // - attributes value should match
+
+ tester.inputs({"const/float"});
+ tester.output("maxpool");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFMaxPool *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ ASSERT_EQ(test_node->padding(), "VALID");
+ ASSERT_EQ(test_node->ksize(), std::vector<int64_t>({1, 2, 3, 1}));
+ ASSERT_EQ(test_node->strides(), std::vector<int64_t>({1, 3, 2, 1}));
+}
diff --git a/compiler/moco/import/src/Nodes/Maximum.cpp b/compiler/moco/import/src/Nodes/Maximum.cpp
new file mode 100644
index 000000000..43bbbabe6
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Maximum.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Maximum.h"
+
+#include <moco/IR/Nodes/TFMaximum.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Maximum node
+ */
+class TFMaximumGraphUpdate final : public GraphUpdate
+{
+public:
+ TFMaximumGraphUpdate(TFMaximum *node, std::vector<TensorName> names) : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFMaximum *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFMaximumGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool MaximumGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void MaximumGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Maximum node
+ auto tf_maximum = graph->nodes()->create<TFMaximum>();
+ tf_maximum->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_maximum);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // x
+ add_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_maximum_update = stdex::make_unique<TFMaximumGraphUpdate>(tf_maximum, add_input_names);
+ updates->enroll(std::move(tf_maximum_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Maximum.test.cpp b/compiler/moco/import/src/Nodes/Maximum.test.cpp
new file mode 100644
index 000000000..2a8b63622
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Maximum.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Maximum.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *maximum_basic_pbtxt = STRING_CONTENT(
+ name: "MAXIMUM_01"
+ op: "Maximum"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_maximum_basic)
+{
+ TFNodeBuildTester tester;
+ moco::MaximumGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(maximum_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFMaximum node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("MAXIMUM_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Mean.cpp b/compiler/moco/import/src/Nodes/Mean.cpp
new file mode 100644
index 000000000..30fb0f1f7
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Mean.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Mean.h"
+
+#include <moco/IR/Nodes/TFMean.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for Mean node
+ */
+class MeanGraphUpdate final : public GraphUpdate
+{
+public:
+ MeanGraphUpdate(TFMean *node, const TensorName &&input_name,
+ const TensorName &&reduction_indices_name)
+ : _node(node), _input_name(input_name), _reduction_indices_name(reduction_indices_name)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFMean *_node;
+ const TensorName _input_name;
+ const TensorName _reduction_indices_name;
+};
+
+void MeanGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *input_node = table->node(_input_name);
+ loco::Node *reduction_indices_node = table->node(_reduction_indices_name);
+ _node->input(input_node);
+ _node->reduction_indices(reduction_indices_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool MeanGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ if (!plier::tf::has_attrs(node, {"T", "Tidx", "keep_dims"}))
+ return false;
+
+ auto dtype = plier::tf::get_datatype_attr(node, "Tidx");
+ if (dtype != tensorflow::DataType::DT_INT32 && dtype != tensorflow::DataType::DT_INT64)
+ return false;
+
+ return true;
+}
+
+void MeanGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Mean node
+ auto tf_mean = graph->nodes()->create<TFMean>();
+ tf_mean->name(node.name());
+ tf_mean->keep_dims(plier::tf::get_bool_attr(node, "keep_dims"));
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_mean);
+
+ auto update = stdex::make_unique<MeanGraphUpdate>(tf_mean, TensorName(node.input(0)),
+ TensorName(node.input(1)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Mean.test.cpp b/compiler/moco/import/src/Nodes/Mean.test.cpp
new file mode 100644
index 000000000..6321fad16
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Mean.test.cpp
@@ -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.
+ */
+
+#include "moco/Import/Nodes/Mean.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *mean_true_pbtxtdata = STRING_CONTENT(
+ name: "Mean"
+ op: "Mean"
+ input: "Placeholder"
+ input: "Const"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "Tidx"
+ value { type: DT_INT32 }
+ }
+ attr {
+ key: "keep_dims"
+ value { b: true }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, mean_true)
+{
+ TFNodeBuildTester tester;
+ moco::MeanGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(mean_true_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFMean
+ // - input node should not be nullptr
+ // - reduction_indeces node should not be nullptr
+ // - keep_dims attribute is set same as pbtxt
+
+ tester.inputs({"Placeholder", "Const"});
+ tester.output("Mean");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFMean *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->keep_dims(), true);
+}
+
+namespace
+{
+
+// clang-format off
+const char *mean_false_pbtxtdata = STRING_CONTENT(
+ name: "Mean"
+ op: "Mean"
+ input: "Placeholder"
+ input: "Const"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "Tidx"
+ value { type: DT_INT32 }
+ }
+ attr {
+ key: "keep_dims"
+ value { b: false }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, mean_false)
+{
+ TFNodeBuildTester tester;
+ moco::MeanGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(mean_false_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFMean
+ // - input node should not be nullptr
+ // - reduction_indeces node should not be nullptr
+ // - keep_dims attribute is set same as pbtxt
+
+ tester.inputs({"Placeholder", "Const"});
+ tester.output("Mean");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFMean *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->keep_dims(), false);
+}
diff --git a/compiler/moco/import/src/Nodes/Mul.cpp b/compiler/moco/import/src/Nodes/Mul.cpp
new file mode 100644
index 000000000..ab926b59e
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Mul.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Mul.h"
+
+#include <moco/IR/Nodes/TFMul.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Mul node
+ */
+class TFMulGraphUpdate final : public GraphUpdate
+{
+public:
+ TFMulGraphUpdate(TFMul *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFMul *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFMulGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool MulGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void MulGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Mul node
+ auto tf_mul = graph->nodes()->create<TFMul>();
+ tf_mul->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_mul);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // x
+ add_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_mul_update = stdex::make_unique<TFMulGraphUpdate>(tf_mul, add_input_names);
+ updates->enroll(std::move(tf_mul_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Mul.test.cpp b/compiler/moco/import/src/Nodes/Mul.test.cpp
new file mode 100644
index 000000000..92730b377
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Mul.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Mul.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *mul_basic_pbtxt = STRING_CONTENT(
+ name: "MUL_01"
+ op: "Mul"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_mul_basic)
+{
+ TFNodeBuildTester tester;
+ moco::MulGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(mul_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFMul node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("MUL_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Pack.cpp b/compiler/moco/import/src/Nodes/Pack.cpp
new file mode 100644
index 000000000..45815a30e
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Pack.cpp
@@ -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 "moco/Import/Nodes/Pack.h"
+
+#include <moco/IR/Nodes/TFPack.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <loco/IR/NodeShape.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+#include <cassert>
+
+namespace
+{
+
+using namespace moco;
+
+class TFPackGraphUpdate final : public GraphUpdate
+{
+public:
+ TFPackGraphUpdate(TFPack *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFPack *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFPackGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ uint32_t num_values = _names.size();
+ assert(num_values >= 1);
+
+ for (uint32_t i = 0; i < num_values; ++i)
+ {
+ auto input_node = tensor_names->node(_names[i]);
+ assert(input_node != nullptr);
+ _node->values(i, input_node);
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool PackGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (!plier::tf::has_attrs(node, {"T", "N", "axis"}))
+ return false;
+
+ const int num_inputs = node.input_size();
+ return (num_inputs >= 1) && (num_inputs == plier::tf::get_int_attr(node, "N"));
+}
+
+void PackGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+ auto tensor_names = context->tensor_names();
+ auto updates = context->updates();
+
+ const int num_inputs = node.input_size();
+ std::vector<TensorName> input_names;
+ auto pack_node = graph->nodes()->create<TFPack>(num_inputs);
+ pack_node->name(node.name());
+
+ for (int ni = 0; ni < num_inputs; ++ni)
+ {
+ input_names.push_back(TensorName(node.input(ni)));
+ }
+
+ pack_node->axis(plier::tf::get_int_attr(node, "axis"));
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, pack_node);
+
+ auto update = stdex::make_unique<TFPackGraphUpdate>(pack_node, input_names);
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Pack.test.cpp b/compiler/moco/import/src/Nodes/Pack.test.cpp
new file mode 100644
index 000000000..01774a906
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Pack.test.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Pack.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *pack_01_pbtxtdata = STRING_CONTENT(
+ name: "Pack"
+ op: "Pack"
+ input: "input_1"
+ input: "input_2"
+ input: "input_3"
+ input: "input_4"
+ attr {
+ key: "N"
+ value {
+ i: 4
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_pack_basic)
+{
+ TFNodeBuildTester tester;
+ moco::PackGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(pack_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFPack
+ // - there should be four values
+ // - values(idx) should not be nullptr
+ // - axis() should be 0
+
+ tester.inputs({"input_1", "input_2", "input_3", "input_4"});
+ tester.output("Pack");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFPack *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->N(), 4);
+ ASSERT_NE(test_node->values(0), nullptr);
+ ASSERT_NE(test_node->values(1), nullptr);
+ ASSERT_NE(test_node->values(2), nullptr);
+ ASSERT_NE(test_node->values(3), nullptr);
+ ASSERT_EQ(test_node->axis(), 0);
+}
diff --git a/compiler/moco/import/src/Nodes/Pad.cpp b/compiler/moco/import/src/Nodes/Pad.cpp
new file mode 100644
index 000000000..262a68fa0
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Pad.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Pad.h"
+
+#include <moco/IR/Nodes/TFPad.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Pad node
+ */
+class TFPadGraphUpdate final : public GraphUpdate
+{
+public:
+ TFPadGraphUpdate(TFPad *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFPad *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFPadGraphUpdate::input(const SymbolTable *table) const
+{
+ assert(_names.size() == 2);
+
+ _node->input(table->node(_names[0]));
+ _node->paddings(table->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool PadGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ return plier::tf::has_attrs(node, {"T", "Tpaddings"});
+}
+
+void PadGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Pad node
+ auto tf_pad = graph->nodes()->create<TFPad>();
+ tf_pad->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_pad);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // input
+ add_input_names.push_back(TensorName(node.input(1))); // paddings
+
+ // Queue node input update
+ auto tf_pad_update = stdex::make_unique<TFPadGraphUpdate>(tf_pad, add_input_names);
+ updates->enroll(std::move(tf_pad_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Pad.test.cpp b/compiler/moco/import/src/Nodes/Pad.test.cpp
new file mode 100644
index 000000000..19769cf6b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Pad.test.cpp
@@ -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 "moco/Import/Nodes/Pad.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *pad_basic_pbtxt = STRING_CONTENT(
+ name: "Pad"
+ op: "Pad"
+ input: "input"
+ input: "paddings"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tpaddings"
+ value {
+ type: DT_INT32
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_pad_basic)
+{
+ TFNodeBuildTester tester;
+ moco::PadGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(pad_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFPad node should exist
+ // - input input() should not be null
+ // - input paddings() should not be null
+
+ tester.inputs({"input", "paddings"});
+ tester.output("Pad");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Placeholder.cpp b/compiler/moco/import/src/Nodes/Placeholder.cpp
new file mode 100644
index 000000000..0033f664b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Placeholder.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Placeholder.h"
+
+#include <moco/IR/Nodes/TFPlaceholder.h>
+
+#include <moco/Names.h>
+#include <plier/tf/Convert.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace moco
+{
+
+bool PlaceholderGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (!plier::tf::has_attrs(node, {"dtype", "shape"}))
+ return false;
+
+ loco::DataType dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "dtype"));
+ if (dtype != loco::DataType::FLOAT32)
+ return false;
+ // TODO support other types
+
+ return true;
+}
+
+void PlaceholderGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+
+ loco::DataType dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "dtype"));
+ const auto &shape = plier::tf::get_shape_attr(node, "shape");
+ // TODO handle for unknown rank
+ assert(!shape.unknown_rank());
+ int64_t num_dims = shape.dim_size();
+
+ // TODO support other types
+ assert(dtype == loco::DataType::FLOAT32);
+
+ // Create a "Placeholder" node as an input
+ auto placeholder_node = graph->nodes()->create<moco::TFPlaceholder>();
+ placeholder_node->name(node.name());
+ placeholder_node->dtype(dtype);
+
+ // Setting shape info.
+ placeholder_node->rank(num_dims);
+ for (int64_t d = 0; d < num_dims; d++)
+ {
+ assert(shape.dim(d).size() < std::numeric_limits<uint32_t>::max());
+ int64_t dim_value = shape.dim(d).size();
+ if (dim_value >= 0)
+ {
+ uint32_t dim_value32 = static_cast<uint32_t>(dim_value);
+ placeholder_node->dim(d) = dim_value32;
+ }
+ else
+ {
+ placeholder_node->dim(d).unset();
+ // TODO Remove assert() and do implement
+ // NOTE Current implementation assumes dim is all know
+ assert(false);
+ }
+ }
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, placeholder_node);
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Placeholder.test.cpp b/compiler/moco/import/src/Nodes/Placeholder.test.cpp
new file mode 100644
index 000000000..80488ce39
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Placeholder.test.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Placeholder.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *known_batch_pbtxt = STRING_CONTENT(
+ name: "placeholder"
+ op: "Placeholder"
+ attr {
+ key: "dtype" value { type: DT_FLOAT }
+ }
+ attr {
+ key: "shape"
+ value {
+ shape {
+ dim { size: 1024 }
+ dim { size: 2 }
+ dim { size: 3 }
+ dim { size: 4 }
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, placeholder_knwon_batch)
+{
+ TFNodeBuildTester tester;
+ moco::PlaceholderGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(known_batch_pbtxt, nodedef));
+
+ // what to test:
+ // - TFPlaceholder node should exist
+ // - shape attribute should match
+
+ tester.inputs({});
+ tester.output("placeholder");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFPlaceholder *>(tester.output());
+ assert(test_node != nullptr);
+ ASSERT_TRUE(test_node->dim(0).known() && test_node->dim(0).value() == 1024);
+ ASSERT_TRUE(test_node->dim(1).known() && test_node->dim(1).value() == 2);
+ ASSERT_TRUE(test_node->dim(2).known() && test_node->dim(2).value() == 3);
+ ASSERT_TRUE(test_node->dim(3).known() && test_node->dim(3).value() == 4);
+}
diff --git a/compiler/moco/import/src/Nodes/RealDiv.cpp b/compiler/moco/import/src/Nodes/RealDiv.cpp
new file mode 100644
index 000000000..de3d57673
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/RealDiv.cpp
@@ -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 "moco/Import/Nodes/RealDiv.h"
+
+#include <moco/IR/Nodes/TFRealDiv.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF RealDiv node
+ */
+class TFRealDivGraphUpdate final : public GraphUpdate
+{
+public:
+ TFRealDivGraphUpdate(TFRealDiv *node, std::vector<TensorName> names) : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFRealDiv *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFRealDivGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+bool RealDivGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void RealDivGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect RealDiv node
+ auto tf_div = graph->nodes()->create<TFRealDiv>();
+ tf_div->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_div);
+
+ std::vector<TensorName> div_input_names;
+ div_input_names.push_back(TensorName(node.input(0))); // x
+ div_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_div_update = stdex::make_unique<TFRealDivGraphUpdate>(tf_div, div_input_names);
+ updates->enroll(std::move(tf_div_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/RealDiv.test.cpp b/compiler/moco/import/src/Nodes/RealDiv.test.cpp
new file mode 100644
index 000000000..cda2d3738
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/RealDiv.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/RealDiv.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *div_basic_pbtxt = STRING_CONTENT(
+ name: "DIV_01"
+ op: "RealDiv"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_div_basic)
+{
+ TFNodeBuildTester tester;
+ moco::RealDivGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(div_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFRealDiv node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("DIV_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Relu.cpp b/compiler/moco/import/src/Nodes/Relu.cpp
new file mode 100644
index 000000000..eedc8155d
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Relu.cpp
@@ -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 "moco/Import/Nodes/Relu.h"
+
+#include <moco/IR/Nodes/TFRelu.h>
+
+#include <moco/Names.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+
+using namespace moco;
+
+class TFReluGraphUpdate final : public GraphUpdate
+{
+public:
+ TFReluGraphUpdate(TFRelu *node, const TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFRelu *_node;
+ const TensorName _name;
+};
+
+void TFReluGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->features(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ReluGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // ReLU node SHOULD have only one input
+ if (node.input_size() != 1)
+ return false;
+
+ return true;
+}
+
+void ReluGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // Create a "TFRelu" node for Relu
+ auto relu_node = graph->nodes()->create<TFRelu>();
+ relu_node->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, relu_node);
+
+ // Queue node input update
+ auto update = stdex::make_unique<TFReluGraphUpdate>(relu_node, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Relu.test.cpp b/compiler/moco/import/src/Nodes/Relu.test.cpp
new file mode 100644
index 000000000..a20ee081d
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Relu.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Relu.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *relu_01_pbtxtdata = STRING_CONTENT(
+ name: "ReLU"
+ op: "Relu"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, relu_01)
+{
+ TFNodeBuildTester tester;
+ moco::ReluGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(relu_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFRelu
+ // - features node should not be nullptr
+
+ tester.inputs({"Placeholder"});
+ tester.output("ReLU");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Relu6.cpp b/compiler/moco/import/src/Nodes/Relu6.cpp
new file mode 100644
index 000000000..4700ba408
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Relu6.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Relu6.h"
+
+#include <moco/IR/Nodes/TFRelu6.h>
+
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+class TFRelu6GraphUpdate final : public GraphUpdate
+{
+public:
+ TFRelu6GraphUpdate(TFRelu6 *node, const TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFRelu6 *_node;
+ const TensorName _name;
+};
+
+void TFRelu6GraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->features(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool Relu6GraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // ReLU6 node SHOULD have only one input
+ if (node.input_size() != 1)
+ return false;
+ return true;
+}
+
+void Relu6GraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // Create a "TFRelu6" node for Relu
+ auto relu_node = graph->nodes()->create<TFRelu6>();
+ relu_node->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, relu_node);
+
+ // Queue node input update
+ auto update = stdex::make_unique<TFRelu6GraphUpdate>(relu_node, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Relu6.test.cpp b/compiler/moco/import/src/Nodes/Relu6.test.cpp
new file mode 100644
index 000000000..26beb6c17
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Relu6.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Relu6.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *relu6_01_pbtxtdata = STRING_CONTENT(
+ name: "ReLU6"
+ op: "Relu6"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, relu6_01)
+{
+ TFNodeBuildTester tester;
+ moco::Relu6GraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(relu6_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFRelu6
+ // - features node should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("ReLU6");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Reshape.cpp b/compiler/moco/import/src/Nodes/Reshape.cpp
new file mode 100644
index 000000000..26e22513f
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Reshape.cpp
@@ -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 "moco/Import/Nodes/Reshape.h"
+
+#include <moco/IR/Nodes/TFReshape.h>
+
+#include <moco/Names.h>
+#include <plier/tf/Convert.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+using namespace moco;
+
+class ReshapeGraphUpdate final : public GraphUpdate
+{
+public:
+ ReshapeGraphUpdate(TFReshape *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFReshape *_node;
+ std::vector<TensorName> _names;
+};
+
+void ReshapeGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 2);
+
+ auto tensor_node = node_table->node(_names[0]);
+ auto shape_node = node_table->node(_names[1]);
+
+ assert(tensor_node != nullptr);
+ assert(shape_node != nullptr);
+
+ _node->tensor(tensor_node);
+ _node->shape(shape_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ReshapeGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // Tensorflow Reshape has 2 inputs: tensor & shape
+ if (node.input_size() != 2)
+ return false;
+
+ // TODO Assert Tshape value is DT_INT32?
+ return plier::tf::has_attrs(node, {"T", "Tshape"});
+}
+
+void ReshapeGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ std::string reshape_name = node.name();
+
+ auto reshape = graph->nodes()->create<TFReshape>();
+ reshape->name(node.name());
+
+ // save the name for graph link updates
+ TensorName output_name(reshape_name, 0);
+ tensor_names->enroll(output_name, reshape);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // tensor
+ input_names.push_back(TensorName(node.input(1))); // shape
+
+ // Queue node input update
+ auto update = stdex::make_unique<ReshapeGraphUpdate>(reshape, input_names);
+
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Reshape.test.cpp b/compiler/moco/import/src/Nodes/Reshape.test.cpp
new file mode 100644
index 000000000..c406bf47b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Reshape.test.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Reshape.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *reshape_01_pbtxtdata = STRING_CONTENT(
+ name: "reshape"
+ op: "Reshape"
+ input: "placeholder"
+ input: "shape"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "Tshape"
+ value { type: DT_INT32 }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, reshape_01)
+{
+ TFNodeBuildTester tester;
+ moco::ReshapeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(reshape_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFReshape
+ // - input nodes should not be null
+
+ tester.inputs({"placeholder", "shape"});
+ tester.output("reshape");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Rsqrt.cpp b/compiler/moco/import/src/Nodes/Rsqrt.cpp
new file mode 100644
index 000000000..979ac90c9
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Rsqrt.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Rsqrt.h"
+
+#include <moco/IR/Nodes/TFRsqrt.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Rsqrt node
+ */
+class TFRsqrtGraphUpdate final : public GraphUpdate
+{
+public:
+ TFRsqrtGraphUpdate(TFRsqrt *node, TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFRsqrt *_node;
+ TensorName _name;
+};
+
+void TFRsqrtGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->x(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool RsqrtGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 1;
+}
+
+void RsqrtGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Rsqrt node
+ auto tf_rsqrt = graph->nodes()->create<TFRsqrt>();
+ tf_rsqrt->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_rsqrt);
+
+ // Queue node input update
+ auto tf_rsqrt_update =
+ stdex::make_unique<TFRsqrtGraphUpdate>(tf_rsqrt, TensorName(node.input(0)));
+ updates->enroll(std::move(tf_rsqrt_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Rsqrt.test.cpp b/compiler/moco/import/src/Nodes/Rsqrt.test.cpp
new file mode 100644
index 000000000..2750725bc
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Rsqrt.test.cpp
@@ -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.
+ */
+
+#include "moco/Import/Nodes/Rsqrt.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *rsqrt_basic_pbtxt = STRING_CONTENT(
+ name: "RSQRT_01"
+ op: "Rsqrt"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_rsqrt_basic)
+{
+ TFNodeBuildTester tester;
+ moco::RsqrtGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(rsqrt_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFRsqrt node should exist
+ // - input x() should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("RSQRT_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Shape.cpp b/compiler/moco/import/src/Nodes/Shape.cpp
new file mode 100644
index 000000000..1e112ebb0
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Shape.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Shape.h"
+
+#include <moco/IR/Nodes/TFShape.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for Shape node
+ */
+class ShapeGraphUpdate final : public GraphUpdate
+{
+public:
+ ShapeGraphUpdate(TFShape *node, const TensorName &&input_name)
+ : _node(node), _input_name(input_name)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFShape *_node;
+ const TensorName _input_name;
+};
+
+void ShapeGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *input_node = table->node(_input_name);
+ _node->input(input_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ShapeGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ return plier::tf::has_attrs(node, {"T"});
+}
+
+void ShapeGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // create TF dialect Shape node
+ auto tf_shape = graph->nodes()->create<TFShape>();
+ tf_shape->name(node.name());
+
+ if (plier::tf::has_attrs(node, {"out_type"}))
+ {
+ auto dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "out_type"));
+ // TODO Support other dtype like S64
+ assert(dtype == loco::DataType::S32);
+
+ tf_shape->dtype(dtype);
+ }
+ else
+ {
+ // Set to S32, TF-documented default value for 'out_type'
+ tf_shape->dtype(loco::DataType::S32);
+ }
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_shape);
+
+ auto update = stdex::make_unique<ShapeGraphUpdate>(tf_shape, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Shape.test.cpp b/compiler/moco/import/src/Nodes/Shape.test.cpp
new file mode 100644
index 000000000..4aaf66c6f
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Shape.test.cpp
@@ -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 "moco/Import/Nodes/Shape.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *shape_000_pbtxtdata = STRING_CONTENT(
+ name: "Shape"
+ op: "Shape"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "out_type"
+ value { type: DT_INT32 }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, shape_000)
+{
+ TFNodeBuildTester tester;
+ moco::ShapeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(shape_000_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFShape
+ // - input node should not be null
+ // - dtype attribute is set same as out_type attribute of pbtxt
+
+ tester.inputs({"Placeholder"});
+ tester.output("Shape");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFShape *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->dtype(), loco::DataType::S32);
+}
diff --git a/compiler/moco/import/src/Nodes/Softmax.cpp b/compiler/moco/import/src/Nodes/Softmax.cpp
new file mode 100644
index 000000000..6f2c609ff
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Softmax.cpp
@@ -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 "moco/Import/Nodes/Softmax.h"
+
+#include <moco/IR/Nodes/TFSoftmax.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+using namespace moco;
+
+/**
+* @brief GraphUpdate for Softmax node
+*/
+class SoftmaxGraphUpdate final : public GraphUpdate
+{
+public:
+ SoftmaxGraphUpdate(TFSoftmax *node, const TensorName &&input_name)
+ : _node(node), _input_name(input_name)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSoftmax *_node;
+ const TensorName _input_name;
+};
+
+void SoftmaxGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *input_node = table->node(_input_name);
+ _node->logits(input_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SoftmaxGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ return plier::tf::has_attrs(node, {"T"});
+}
+
+void SoftmaxGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Softmax node
+ auto tf_softmax = graph->nodes()->create<TFSoftmax>();
+ tf_softmax->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_softmax);
+
+ auto update = stdex::make_unique<SoftmaxGraphUpdate>(tf_softmax, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Softmax.test.cpp b/compiler/moco/import/src/Nodes/Softmax.test.cpp
new file mode 100644
index 000000000..b7c0797bb
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Softmax.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Softmax.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *softmax_2d_pbtxtdata = STRING_CONTENT(
+ name: "Softmax"
+ op: "Softmax"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, softmax_2d)
+{
+ TFNodeBuildTester tester;
+ moco::SoftmaxGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(softmax_2d_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFSoftmax
+ // - logits node should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("Softmax");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Sqrt.cpp b/compiler/moco/import/src/Nodes/Sqrt.cpp
new file mode 100644
index 000000000..f891e48f6
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Sqrt.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Sqrt.h"
+
+#include <moco/IR/Nodes/TFSqrt.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Sqrt node
+ */
+class TFSqrtGraphUpdate final : public GraphUpdate
+{
+public:
+ TFSqrtGraphUpdate(TFSqrt *node, TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSqrt *_node;
+ TensorName _name;
+};
+
+void TFSqrtGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->x(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SqrtGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 1;
+}
+
+void SqrtGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Sqrt node
+ auto tf_sqrt = graph->nodes()->create<TFSqrt>();
+ tf_sqrt->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_sqrt);
+
+ // Queue node input update
+ auto tf_sqrt_update = stdex::make_unique<TFSqrtGraphUpdate>(tf_sqrt, TensorName(node.input(0)));
+ updates->enroll(std::move(tf_sqrt_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Sqrt.test.cpp b/compiler/moco/import/src/Nodes/Sqrt.test.cpp
new file mode 100644
index 000000000..427d4df0f
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Sqrt.test.cpp
@@ -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.
+ */
+
+#include "moco/Import/Nodes/Sqrt.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *sqrt_basic_pbtxt = STRING_CONTENT(
+ name: "SQRT_01"
+ op: "Sqrt"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_sqrt_basic)
+{
+ TFNodeBuildTester tester;
+ moco::SqrtGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(sqrt_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFSqrt node should exist
+ // - input x() should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("SQRT_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/SquaredDifference.cpp b/compiler/moco/import/src/Nodes/SquaredDifference.cpp
new file mode 100644
index 000000000..17a1fe93d
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/SquaredDifference.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/SquaredDifference.h"
+
+#include <moco/IR/Nodes/TFSquaredDifference.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF SquaredDifference node
+ */
+class TFSquaredDifferenceGraphUpdate final : public GraphUpdate
+{
+public:
+ TFSquaredDifferenceGraphUpdate(TFSquaredDifference *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSquaredDifference *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFSquaredDifferenceGraphUpdate::input(const SymbolTable *table) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(table->node(_names[0]));
+ _node->y(table->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SquaredDifferenceGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void SquaredDifferenceGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect SquaredDifference node
+ auto tf_sqdiff = graph->nodes()->create<TFSquaredDifference>();
+ tf_sqdiff->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_sqdiff);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // x
+ add_input_names.push_back(TensorName(node.input(1))); // y
+
+ // Queue node input update
+ auto tf_sqrt_update =
+ stdex::make_unique<TFSquaredDifferenceGraphUpdate>(tf_sqdiff, add_input_names);
+ updates->enroll(std::move(tf_sqrt_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/SquaredDifference.test.cpp b/compiler/moco/import/src/Nodes/SquaredDifference.test.cpp
new file mode 100644
index 000000000..336ab1358
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/SquaredDifference.test.cpp
@@ -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 "moco/Import/Nodes/SquaredDifference.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *sqdiff_basic_pbtxt = STRING_CONTENT(
+ name: "squared_difference"
+ op: "SquaredDifference"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_squdiff_basic)
+{
+ TFNodeBuildTester tester;
+ moco::SquaredDifferenceGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(sqdiff_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFSquaredDifference node should exist
+ // - input x() should not be null
+ // - input y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("squared_difference");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Squeeze.cpp b/compiler/moco/import/src/Nodes/Squeeze.cpp
new file mode 100644
index 000000000..1b4ebae6f
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Squeeze.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Squeeze.h"
+
+#include <moco/IR/Nodes/TFSqueeze.h>
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+namespace
+{
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for Squeeze node
+ */
+class SqueezeGraphUpdate final : public GraphUpdate
+{
+public:
+ SqueezeGraphUpdate(TFSqueeze *node, const TensorName &&input_name)
+ : _node(node), _input_name(input_name)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSqueeze *_node;
+ const TensorName _input_name;
+};
+
+void SqueezeGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *input_node = table->node(_input_name);
+ _node->input(input_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SqueezeGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ if (!plier::tf::has_attrs(node, {"T"}))
+ return false;
+
+ if (plier::tf::has_attrs(node, {"axis"}))
+ {
+ // TODO support 'axis' attribute
+ oops::UserExn("Squeeze: Unsupported 'axis' attribute", node.name());
+ }
+
+ return true;
+}
+
+void SqueezeGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // TODO support 'axis' attribute
+ assert(!plier::tf::has_attrs(node, {"axis"}));
+
+ std::vector<int64_t> squeeze_dims;
+ if (plier::tf::has_attrs(node, {"squeeze_dims"}))
+ {
+ auto squeeze_dim_list = plier::tf::get_list_attr(node, {"squeeze_dims"});
+ // TODO assert squeeze_dims are mutually different?
+ squeeze_dims = plier::tf::as_int64_list(squeeze_dim_list);
+ }
+ // Note that it is possible that NodeDef does not have squeeze_dims attribute.
+ // In that case, TFSqueeze also has empty squeeze_dims,
+
+ // creating TF dialect Squeeze node
+ auto tf_squeeze = graph->nodes()->create<TFSqueeze>();
+ tf_squeeze->name(node.name());
+ tf_squeeze->squeeze_dims(squeeze_dims);
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_squeeze);
+
+ auto update = stdex::make_unique<SqueezeGraphUpdate>(tf_squeeze, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Squeeze.test.cpp b/compiler/moco/import/src/Nodes/Squeeze.test.cpp
new file mode 100644
index 000000000..e8188f98b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Squeeze.test.cpp
@@ -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 "moco/Import/Nodes/Squeeze.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *squeeze_all_pbtxtdata = STRING_CONTENT(
+ name: "Squeeze"
+ op: "Squeeze"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, squeeze_all)
+{
+ TFNodeBuildTester tester;
+ moco::SqueezeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(squeeze_all_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFSqueeze
+ // - input node should not be null
+ // - squeeze_dims attribute is set same as pbtxt
+
+ tester.inputs({"Placeholder"});
+ tester.output("Squeeze");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFSqueeze *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->squeeze_dims().size(), 0);
+}
+
+namespace
+{
+
+// clang-format off
+const char *squeeze_some_pbtxtdata = STRING_CONTENT(
+ name: "Squeeze"
+ op: "Squeeze"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "squeeze_dims"
+ value {
+ list { i: 1 }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, squeeze_some)
+{
+ TFNodeBuildTester tester;
+ moco::SqueezeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(squeeze_some_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFSqueeze
+ // - input node should not be null
+ // - squeeze_dims attribute is set same as pbtxt
+
+ tester.inputs({"Placeholder"});
+ tester.output("Squeeze");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFSqueeze *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->squeeze_dims().size(), 1);
+ ASSERT_EQ(test_node->squeeze_dims().at(0), 1);
+}
+
+// TODO Add test case for negative squeeze dim
diff --git a/compiler/moco/import/src/Nodes/StopGradient.cpp b/compiler/moco/import/src/Nodes/StopGradient.cpp
new file mode 100644
index 000000000..9caec6943
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/StopGradient.cpp
@@ -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 "moco/Import/Nodes/StopGradient.h"
+
+#include <moco/IR/Nodes/TFStopGradient.h>
+
+#include <loco.h>
+#include <plier/tf/Convert.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF StopGradient node
+ */
+class TFStopGradientGraphUpdate final : public GraphUpdate
+{
+public:
+ TFStopGradientGraphUpdate(TFStopGradient *node, TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFStopGradient *_node;
+ TensorName _name;
+};
+
+void TFStopGradientGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->input(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool StopGradientGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ return plier::tf::has_attrs(node, {"T"});
+}
+
+void StopGradientGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect StopGradient node
+ auto tf_stopgradient = graph->nodes()->create<TFStopGradient>();
+ tf_stopgradient->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_stopgradient);
+
+ // Queue node input update
+ auto tf_stopgradient_update =
+ stdex::make_unique<TFStopGradientGraphUpdate>(tf_stopgradient, TensorName(node.input(0)));
+ updates->enroll(std::move(tf_stopgradient_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/StopGradient.test.cpp b/compiler/moco/import/src/Nodes/StopGradient.test.cpp
new file mode 100644
index 000000000..0bf70ebcc
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/StopGradient.test.cpp
@@ -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.
+ */
+
+#include "moco/Import/Nodes/StopGradient.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *stopgradient_basic_pbtxt = STRING_CONTENT(
+ name: "StopGradient_01"
+ op: "StopGradient"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_stopgradient_basic)
+{
+ TFNodeBuildTester tester;
+ moco::StopGradientGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(stopgradient_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFStopGradient node should exist
+ // - input() should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("StopGradient_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/StridedSlice.cpp b/compiler/moco/import/src/Nodes/StridedSlice.cpp
new file mode 100644
index 000000000..06d388be0
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/StridedSlice.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/StridedSlice.h"
+
+#include <moco/IR/Nodes/TFStridedSlice.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+namespace
+{
+using namespace moco;
+
+class TFStridedSliceGraphUpdate final : public GraphUpdate
+{
+public:
+ TFStridedSliceGraphUpdate(TFStridedSlice *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFStridedSlice *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFStridedSliceGraphUpdate::input(const SymbolTable *node_table) const
+{
+ // TODO support size 3 where strides is None
+ assert(_names.size() == 4);
+
+ auto input_node = node_table->node(_names[0]);
+ auto begin_node = node_table->node(_names[1]);
+ auto end_node = node_table->node(_names[2]);
+ auto strides_node = node_table->node(_names[3]);
+ assert(input_node != nullptr);
+ assert(begin_node != nullptr);
+ assert(end_node != nullptr);
+ assert(strides_node != nullptr);
+
+ _node->input(input_node);
+ _node->begin(begin_node);
+ _node->end(end_node);
+ _node->strides(strides_node);
+
+ // TODO move validation codes to some suitable place
+ // Run basic validation
+
+ // TODO support full mask features
+ if (_node->begin_mask() != 0 || _node->end_mask() != 0 || _node->ellipsis_mask() != 0 ||
+ _node->new_axis_mask() != 0 || _node->shrink_axis_mask() != 1)
+ {
+ throw oops::UserExn("Mask attributes are not supported for now: ", _node->name());
+ }
+
+ // Only Const are supported for now
+ auto const_input = dynamic_cast<moco::TFConst *>(_node->input());
+ auto const_begin = dynamic_cast<moco::TFConst *>(_node->begin());
+ auto const_end = dynamic_cast<moco::TFConst *>(_node->end());
+ auto const_strides = dynamic_cast<moco::TFConst *>(_node->strides());
+ if (const_input == nullptr || const_begin == nullptr || const_end == nullptr ||
+ const_strides == nullptr)
+ {
+ throw oops::UserExn("Only Const inputs are supported for now: ", _node->name());
+ }
+
+ // TODO support S64
+ if (const_begin->dtype() != loco::DataType::S32 || const_end->dtype() != loco::DataType::S32 ||
+ const_strides->dtype() != loco::DataType::S32)
+ {
+ throw oops::UserExn("Only Const types of INT32 are supported for begin/end/strides for now: ",
+ _node->name());
+ }
+
+ // Input Rank should match number of elements of the begin/end/strides
+ auto rin = const_input->rank();
+ if (rin != const_begin->size<loco::DataType::S32>() ||
+ rin != const_end->size<loco::DataType::S32>() ||
+ rin != const_strides->size<loco::DataType::S32>())
+ {
+ throw oops::UserExn("Ranks for inputs should be same: ", _node->name());
+ }
+
+ // TODO support strides type of S64
+ // TODO support other strides value
+ // Only support stride 1 for now
+ uint32_t elements = const_strides->size<loco::DataType::S32>();
+ for (uint32_t e = 0; e < elements; ++e)
+ {
+ if (const_strides->at<loco::DataType::S32>(e) != 1)
+ {
+ throw oops::UserExn("Only stride 1 is supported for now: ", _node->name());
+ }
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool StridedSliceGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // TODO support node.input_size() == 3 where strides is None
+ if (node.input_size() != 4)
+ return false;
+
+ if (!plier::tf::has_attrs(node, {"T", "Index", "begin_mask", "end_mask", "ellipsis_mask",
+ "new_axis_mask", "shrink_axis_mask"}))
+ return false;
+
+ return true;
+}
+
+void StridedSliceGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ std::string node_name = node.name();
+
+ auto stridedslice = graph->nodes()->create<TFStridedSlice>();
+ stridedslice->name(node_name);
+
+ // read attributes
+ auto begin_mask = plier::tf::get_int_attr(node, "begin_mask");
+ auto end_mask = plier::tf::get_int_attr(node, "end_mask");
+ auto ellipsis_mask = plier::tf::get_int_attr(node, "ellipsis_mask");
+ auto new_axis_mask = plier::tf::get_int_attr(node, "new_axis_mask");
+ auto shrink_axis_mask = plier::tf::get_int_attr(node, "shrink_axis_mask");
+
+ stridedslice->begin_mask(begin_mask);
+ stridedslice->end_mask(end_mask);
+ stridedslice->ellipsis_mask(ellipsis_mask);
+ stridedslice->new_axis_mask(new_axis_mask);
+ stridedslice->shrink_axis_mask(shrink_axis_mask);
+
+ // TODO support general mask values: we support only this limited case for now
+ assert(begin_mask == 0);
+ assert(end_mask == 0);
+ assert(ellipsis_mask == 0);
+ assert(new_axis_mask == 0);
+ assert(shrink_axis_mask == 1);
+
+ // save the name for graph link updates
+ TensorName output_name(node_name, 0);
+ tensor_names->enroll(output_name, stridedslice);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // input
+ input_names.push_back(TensorName(node.input(1))); // begin
+ input_names.push_back(TensorName(node.input(2))); // end
+ input_names.push_back(TensorName(node.input(3))); // strides
+
+ auto tfconv2d_update = stdex::make_unique<TFStridedSliceGraphUpdate>(stridedslice, input_names);
+
+ updates->enroll(std::move(tfconv2d_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/StridedSlice.test.cpp b/compiler/moco/import/src/Nodes/StridedSlice.test.cpp
new file mode 100644
index 000000000..b6959d7ab
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/StridedSlice.test.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/StridedSlice.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *stridedslice_basic_pbtxt = STRING_CONTENT(
+ name: "StridedSlice"
+ op: "StridedSlice"
+ input: "input"
+ input: "begin"
+ input: "end"
+ input: "strides"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_stridedslice_basic)
+{
+ TFNodeBuildTester tester;
+ moco::StridedSliceGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(stridedslice_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFStridedSlice node should exist
+ // - inputs should not be nullptr
+ // - attributes should match the values
+
+ tester.inputs({"input", "begin", "end", "strides"}, loco::DataType::S32);
+ tester.output("StridedSlice");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFStridedSlice *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->begin_mask(), 0);
+ ASSERT_EQ(test_node->end_mask(), 0);
+ ASSERT_EQ(test_node->ellipsis_mask(), 0);
+ ASSERT_EQ(test_node->new_axis_mask(), 0);
+ ASSERT_EQ(test_node->shrink_axis_mask(), 1);
+}
+
+// TODO add test where strides is None
diff --git a/compiler/moco/import/src/Nodes/Sub.cpp b/compiler/moco/import/src/Nodes/Sub.cpp
new file mode 100644
index 000000000..bdad81d67
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Sub.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Sub.h"
+
+#include <moco/IR/Nodes/TFSub.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Sub node
+ */
+class TFSubGraphUpdate final : public GraphUpdate
+{
+public:
+ TFSubGraphUpdate(TFSub *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSub *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFSubGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SubGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void SubGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Sub node
+ auto tf_sub = graph->nodes()->create<TFSub>();
+ tf_sub->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_sub);
+
+ std::vector<TensorName> sub_input_names;
+ sub_input_names.push_back(TensorName(node.input(0))); // x
+ sub_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_sub_update = stdex::make_unique<TFSubGraphUpdate>(tf_sub, sub_input_names);
+ updates->enroll(std::move(tf_sub_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Sub.test.cpp b/compiler/moco/import/src/Nodes/Sub.test.cpp
new file mode 100644
index 000000000..05f1fb0d6
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Sub.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Sub.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *sub_basic_pbtxt = STRING_CONTENT(
+ name: "SUB_01"
+ op: "Sub"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_sub_basic)
+{
+ TFNodeBuildTester tester;
+ moco::SubGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(sub_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFSub node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("SUB_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Tanh.cpp b/compiler/moco/import/src/Nodes/Tanh.cpp
new file mode 100644
index 000000000..c89fa862a
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Tanh.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Import/Nodes/Tanh.h"
+
+#include <moco/IR/Nodes/TFTanh.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Tanh node
+ */
+class TFTanhGraphUpdate final : public GraphUpdate
+{
+public:
+ TFTanhGraphUpdate(TFTanh *node, TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFTanh *_node;
+ TensorName _name;
+};
+
+void TFTanhGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->x(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool TanhGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 1;
+}
+
+void TanhGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Tanh node
+ auto tf_tanh = graph->nodes()->create<TFTanh>();
+ tf_tanh->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_tanh);
+
+ // Queue node input update
+ auto tf_tanh_update = stdex::make_unique<TFTanhGraphUpdate>(tf_tanh, TensorName(node.input(0)));
+ updates->enroll(std::move(tf_tanh_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Tanh.test.cpp b/compiler/moco/import/src/Nodes/Tanh.test.cpp
new file mode 100644
index 000000000..20ebd15b2
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Tanh.test.cpp
@@ -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.
+ */
+
+#include "moco/Import/Nodes/Tanh.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *tanh_basic_pbtxt = STRING_CONTENT(
+ name: "output/tanh"
+ op: "Tanh"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_tanh_basic)
+{
+ TFNodeBuildTester tester;
+ moco::TanhGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(tanh_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFTanh node should exist
+ // - input x() should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("output/tanh");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/TestHelper.h b/compiler/moco/import/src/TestHelper.h
new file mode 100644
index 000000000..54ca45b4a
--- /dev/null
+++ b/compiler/moco/import/src/TestHelper.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 __TEST_HELPER_H__
+#define __TEST_HELPER_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+#include <moco/IR/TFNode.h>
+#include <loco.h>
+#include <plier/tf/TestHelper.h>
+
+#include <tensorflow/core/framework/graph.pb.h>
+
+#define STRING_CONTENT(content) #content
+
+namespace moco
+{
+namespace test
+{
+
+template <typename T> T *find_first_node_bytype(loco::Graph *g)
+{
+ T *first_node = nullptr;
+ loco::Graph::NodeContext *nodes = g->nodes();
+ uint32_t count = nodes->size();
+
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ first_node = dynamic_cast<T *>(nodes->at(i));
+ if (first_node != nullptr)
+ break;
+ }
+
+ return first_node;
+}
+
+} // namespace test
+} // namespace moco
+
+namespace moco
+{
+namespace test
+{
+
+class TFNodeBuildTester
+{
+public:
+ TFNodeBuildTester();
+
+public:
+ void inputs(const std::vector<std::string> &names);
+ void inputs(const std::vector<std::string> &names, const loco::DataType dtype);
+ void output(const char *name);
+ moco::TFNode *output(void);
+
+ void run(tensorflow::NodeDef &node_def, moco::GraphBuilder &graph_builder);
+
+private:
+ std::unique_ptr<moco::SymbolTable> _tensor_names;
+ std::unique_ptr<loco::Graph> _graph;
+
+ std::vector<moco::TFNode *> _inputs;
+ const char *_output{nullptr};
+};
+
+} // namespace test
+} // namespace moco
+
+#endif // __TEST_HELPER_H__
diff --git a/compiler/moco/import/src/TestHelper.test.cpp b/compiler/moco/import/src/TestHelper.test.cpp
new file mode 100644
index 000000000..06c3dd372
--- /dev/null
+++ b/compiler/moco/import/src/TestHelper.test.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestHelper.h"
+
+#include <moco/IR/Nodes/TFConst.h>
+#include <stdex/Memory.h>
+
+#include <gtest/gtest.h>
+
+namespace moco
+{
+namespace test
+{
+
+TFNodeBuildTester::TFNodeBuildTester()
+{
+ _graph = loco::make_graph();
+ _tensor_names = stdex::make_unique<moco::SymbolTable>();
+}
+
+void TFNodeBuildTester::inputs(const std::vector<std::string> &names)
+{
+ for (auto name : names)
+ {
+ auto input = _graph->nodes()->create<moco::TFConst>();
+ moco::TensorName name_01(name, 0);
+ _tensor_names->enroll(name_01, input);
+
+ _inputs.push_back(input);
+ }
+}
+
+void TFNodeBuildTester::inputs(const std::vector<std::string> &names, const loco::DataType dtype)
+{
+ for (auto name : names)
+ {
+ auto input = _graph->nodes()->create<moco::TFConst>();
+ input->dtype(dtype);
+ moco::TensorName name_01(name, 0);
+ _tensor_names->enroll(name_01, input);
+
+ _inputs.push_back(input);
+ }
+}
+
+void TFNodeBuildTester::output(const char *name) { _output = name; }
+
+moco::TFNode *TFNodeBuildTester::output(void)
+{
+ assert(_output != nullptr);
+
+ moco::TensorName tname(_output, 0);
+ return static_cast<moco::TFNode *>(_tensor_names->node(tname));
+}
+
+void TFNodeBuildTester::run(tensorflow::NodeDef &nodedef, moco::GraphBuilder &graphbuilder)
+{
+ assert(_output != nullptr);
+
+ auto node_defs = stdex::make_unique<moco::NodeDefTable>();
+ auto updates = stdex::make_unique<moco::UpdateQueue>();
+
+ moco::GraphBuilderContext gb_context(_graph.get(), node_defs.get(), _tensor_names.get(),
+ updates.get());
+
+ EXPECT_TRUE(graphbuilder.validate(nodedef));
+ graphbuilder.build(nodedef, &gb_context);
+
+ for (auto &update : updates->queue())
+ {
+ update->input(_tensor_names.get());
+ }
+
+ auto tfnode = output();
+ ASSERT_NE(tfnode, nullptr);
+ ASSERT_STREQ(tfnode->name().c_str(), _output);
+
+ int idx = 0;
+ ASSERT_EQ(tfnode->arity(), _inputs.size());
+ for (auto input : _inputs)
+ {
+ ASSERT_EQ(tfnode->arg(idx++), input);
+ }
+}
+
+} // namespace test
+} // namespace moco
diff --git a/compiler/moco/lang/CMakeLists.txt b/compiler/moco/lang/CMakeLists.txt
new file mode 100644
index 000000000..a64fdf92a
--- /dev/null
+++ b/compiler/moco/lang/CMakeLists.txt
@@ -0,0 +1,21 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(moco_lang SHARED ${SOURCES})
+target_include_directories(moco_lang PRIVATE src)
+target_include_directories(moco_lang PUBLIC include)
+target_link_libraries(moco_lang PUBLIC loco)
+target_link_libraries(moco_lang PRIVATE nncc_common)
+target_link_libraries(moco_lang PRIVATE stdex)
+install(TARGETS moco_lang DESTINATION lib) # moco_tf_frontend requires moco_lang
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
+
+GTest_AddTest(moco_lang_test ${TESTS})
+target_include_directories(moco_lang_test PRIVATE src)
+target_link_libraries(moco_lang_test moco_lang)
diff --git a/compiler/moco/lang/README.md b/compiler/moco/lang/README.md
new file mode 100644
index 000000000..6ee3fc660
--- /dev/null
+++ b/compiler/moco/lang/README.md
@@ -0,0 +1,3 @@
+# lang
+
+`lang` provides TensorFlow Dialect IR
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFAdd.h b/compiler/moco/lang/include/moco/IR/Nodes/TFAdd.h
new file mode 100644
index 000000000..13b064fba
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFAdd.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 __MOCO_IR_TFADD_H__
+#define __MOCO_IR_TFADD_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFAdd corresponds to the following GraphDef
+/*
+node {
+ name: "add"
+ op: "Add"
+ input: "x"
+ input: "y"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFAdd final : public FixedArityNode<2, TFNodeImpl<TFOpcode::Add>>
+{
+public:
+ TFAdd() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+
+ Node *y(void) const { return at(1)->node(); }
+ void y(Node *node) { at(1)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFADD_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFAvgPool.h b/compiler/moco/lang/include/moco/IR/Nodes/TFAvgPool.h
new file mode 100644
index 000000000..74c91b5fb
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFAvgPool.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFAVGPOOL_H__
+#define __MOCO_IR_TFAVGPOOL_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <vector>
+
+namespace moco
+{
+
+/// @note TFAvgPool corresponds to the following GraphDef
+/*
+node {
+ name: "avgpool"
+ op: "AvgPool"
+ input: "placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "ksize"
+ value {
+ list {
+ i: 1 i: 3 i: 3 i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "SAME"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1 i: 1 i: 1 i: 1
+ }
+ }
+ }
+}
+*/
+
+class TFAvgPool final : public FixedArityNode<1, TFNodeImpl<TFOpcode::AvgPool>>
+{
+public:
+ TFAvgPool() = default;
+
+public:
+ Node *value(void) const { return at(0)->node(); }
+ void value(Node *node) { return at(0)->node(node); }
+
+public:
+ const TFDataLayout &data_layout(void) const { return _data_layout; }
+ void data_layout(const TFDataLayout &data_layout) { _data_layout = data_layout; }
+
+ const TFPadding &padding(void) const { return _padding; }
+ void padding(const TFPadding &padding) { _padding = padding; }
+
+ const std::vector<int64_t> &ksize(void) const { return _ksize; }
+ void ksize(const std::vector<int64_t> &ksize) { _ksize = ksize; }
+
+ const std::vector<int64_t> &strides(void) const { return _strides; }
+ void strides(const std::vector<int64_t> &strides) { _strides = strides; }
+
+private:
+ TFDataLayout _data_layout;
+ TFPadding _padding;
+ std::vector<int64_t> _ksize;
+ std::vector<int64_t> _strides;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFAVGPOOL_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFBiasAdd.h b/compiler/moco/lang/include/moco/IR/Nodes/TFBiasAdd.h
new file mode 100644
index 000000000..11e309caa
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFBiasAdd.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 __MOCO_IR_TFBIASADD_H__
+#define __MOCO_IR_TFBIASADD_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFBiasAdd corresponds to the following GraphDef
+/*
+node {
+ name: "bias_add_01"
+ op: "BiasAdd"
+ input: "input_01"
+ input: "bias_add_01/bias"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+}
+*/
+
+class TFBiasAdd final : public FixedArityNode<2, TFNodeImpl<TFOpcode::BiasAdd>>
+{
+public:
+ TFBiasAdd() = default;
+
+public:
+ Node *value(void) const { return at(0)->node(); }
+ void value(Node *node) { return at(0)->node(node); }
+
+ Node *bias(void) const { return at(1)->node(); }
+ void bias(Node *node) { return at(1)->node(node); }
+
+ const TFDataLayout data_layout(void) const { return _data_layout; }
+ void data_layout(const TFDataLayout &data_layout) { _data_layout = data_layout; }
+
+private:
+ TFDataLayout _data_layout;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFBIASADD_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFConcatV2.h b/compiler/moco/lang/include/moco/IR/Nodes/TFConcatV2.h
new file mode 100644
index 000000000..7f0d32697
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFConcatV2.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFCONCATV2_H__
+#define __MOCO_IR_TFCONCATV2_H__
+
+#include "moco/IR/TFNodeDecl.h"
+#include "moco/IR/VariadicArityNode.h"
+
+namespace moco
+{
+
+/// @note TFConcatV2 corresponds to the following GraphDef
+/*
+node {
+ name: "Concat"
+ op: "ConcatV2"
+ input: "Input01"
+ input: "Input02"
+ input: "Axis"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tidx"
+ value {
+ type: DT_INT32
+ }
+ }
+}
+*/
+
+class TFConcatV2 final : public VariadicArityNode<TFNodeImpl<TFOpcode::ConcatV2>>
+{
+public:
+ TFConcatV2(uint32_t arity) : VariadicArityNode<TFNodeImpl<TFOpcode::ConcatV2>>(arity + 1)
+ {
+ // we add +1 for axis of VariadicArityNode ctor
+ // at least one value is required
+ assert(arity >= 1);
+ }
+
+public:
+ uint32_t num_values(void) const
+ {
+ // last one is for axis
+ return arity() - 1;
+ }
+
+public:
+ Node *values(uint32_t index) const
+ {
+ assert(index < num_values());
+ return at(index)->node();
+ }
+ void values(uint32_t index, Node *node)
+ {
+ assert(index < num_values());
+ at(index)->node(node);
+ }
+
+ Node *axis(void) const { return at(num_values())->node(); }
+ void axis(Node *node) { at(num_values())->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFCONCATV2_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFConst.h b/compiler/moco/lang/include/moco/IR/Nodes/TFConst.h
new file mode 100644
index 000000000..7c2595fcb
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFConst.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.
+ */
+
+#ifndef __MOCO_IR_TFCONSTANT_H__
+#define __MOCO_IR_TFCONSTANT_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <loco/IR/DataTypeTraits.h>
+#include <loco/IR/NodeMixins.h>
+#include <loco/IR/TensorShape.h>
+
+#include <vector>
+
+namespace moco
+{
+
+/// @note TFConst corresponds to the following GraphDef
+/*
+node {
+ name: "val"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim { size: 1 }
+ dim { size: 3 }
+ dim { size: 4 }
+ dim { size: 4 }
+ }
+ float_val: 2.1
+ }
+ }
+ }
+}
+*/
+
+/**
+ * @brief IR for tf.constant
+ *
+ * @note Implementation for this class came from Canonical ConstGen
+ * Read comments in loco::ConstGen for details
+ */
+class TFConst final : public FixedArityNode<0, TFNodeImpl<TFOpcode::Const>>,
+ public loco::NodeMixin<loco::NodeTrait::DataType>,
+ public loco::NodeMixin<loco::NodeTrait::TensorShape>
+{
+public:
+ TFConst() = default;
+
+public:
+ template <loco::DataType DT> uint32_t size(void) const;
+ template <loco::DataType DT> void size(uint32_t size);
+
+ template <loco::DataType DT> const typename loco::DataTypeImpl<DT>::Type &at(uint32_t n) const;
+ template <loco::DataType DT> typename loco::DataTypeImpl<DT>::Type &at(uint32_t n);
+
+private:
+ std::vector<uint8_t> _data;
+};
+
+} // namespace moco
+
+namespace moco
+{
+
+loco::TensorShape tensor_shape(const TFConst *node);
+
+uint32_t num_elements(const TFConst *tfconst);
+bool same_shape(const TFConst *lhs, const TFConst *rhs);
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFCONSTANT_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFConv2D.h b/compiler/moco/lang/include/moco/IR/Nodes/TFConv2D.h
new file mode 100644
index 000000000..0d5a17879
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFConv2D.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 __MOCO_IR_TFCONV2D_H__
+#define __MOCO_IR_TFCONV2D_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <vector>
+
+namespace moco
+{
+
+class TFConv2D final : public FixedArityNode<2, TFNodeImpl<TFOpcode::Conv2D>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+ loco::Node *filter(void) const { return at(1)->node(); }
+ void filter(Node *node) { at(1)->node(node); }
+
+public:
+ const TFPadding &padding(void) const { return _padding; }
+ void padding(const TFPadding &padding) { _padding = padding; }
+
+ const TFDataLayout &data_layout(void) const { return _data_layout; }
+ void data_layout(const TFDataLayout &data_layout) { _data_layout = data_layout; }
+
+ const std::vector<int64_t> &strides(void) const { return _strides; }
+ void strides(const std::vector<int64_t> &strides) { _strides = strides; }
+
+private:
+ TFPadding _padding;
+ TFDataLayout _data_layout;
+ std::vector<int64_t> _strides;
+ // TODO Support "Dilation"
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFCONV2D_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFConv2DBackpropInput.h b/compiler/moco/lang/include/moco/IR/Nodes/TFConv2DBackpropInput.h
new file mode 100644
index 000000000..43e620d24
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFConv2DBackpropInput.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFCONV2DBACKPROPINPUT_H__
+#define __MOCO_IR_TFCONV2DBACKPROPINPUT_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <vector>
+
+namespace moco
+{
+
+/// @note TFConv2DBackpropInput corresponds to the following GraphDef
+/*
+node {
+ name: "conv2d_backprop_input"
+ op: "Conv2DBackpropInput"
+ input: "input_sizes"
+ input: "filter"
+ input: "out_backprop"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "data_format"
+ value { s: "NHWC" }
+ }
+ attr {
+ key: "dilations"
+ value {
+ list { i: 1 i: 1 i: 1 i: 1 }
+ }
+ }
+ attr {
+ key: "padding"
+ value { s: "SAME" }
+ }
+ attr {
+ key: "strides"
+ value {
+ list { i: 1 i: 2 i: 2 i: 1 }
+ }
+ }
+}
+*/
+
+/**
+ * @note For Tensorflow Conv2DBackpropInput, 'input' refers actual output of the
+ * node, and 'input' refers actual input. The reasone of this is, as name
+ * suggests, because it is inspired from backpropagation of convolution.
+ * For example, 'out_backprop' of Conv2DBackpropInput is its actual input
+ * feature map, and 'input_sizes' means desired output node's size.
+ * Note that this convention is against loco canonical's convention.
+ */
+class TFConv2DBackpropInput final
+ : public FixedArityNode<3, TFNodeImpl<TFOpcode::Conv2DBackpropInput>>
+{
+public:
+ loco::Node *input_sizes(void) const { return at(0)->node(); }
+ void input_sizes(Node *node) { at(0)->node(node); }
+
+ loco::Node *filter(void) const { return at(1)->node(); }
+ void filter(Node *node) { at(1)->node(node); }
+
+ loco::Node *out_backprop(void) const { return at(2)->node(); }
+ void out_backprop(Node *node) { at(2)->node(node); }
+
+public:
+ const TFPadding &padding(void) const { return _padding; }
+ void padding(const TFPadding &padding) { _padding = padding; }
+
+ const TFDataLayout &data_layout(void) const { return _data_layout; }
+ void data_layout(const TFDataLayout &data_layout) { _data_layout = data_layout; }
+
+ const std::vector<int64_t> &strides(void) const { return _strides; }
+ void strides(const std::vector<int64_t> &strides) { _strides = strides; }
+
+private:
+ TFPadding _padding;
+ TFDataLayout _data_layout;
+ std::vector<int64_t> _strides;
+ // TODO Support "Dilation"
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFCONV2DBACKPROPINPUT_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFDepthwiseConv2dNative.h b/compiler/moco/lang/include/moco/IR/Nodes/TFDepthwiseConv2dNative.h
new file mode 100644
index 000000000..aefc0b5d9
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFDepthwiseConv2dNative.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 __MOCO_IR_TFDEPTHWISECONV2DNATIVE_H__
+#define __MOCO_IR_TFDEPTHWISECONV2DNATIVE_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <vector>
+
+namespace moco
+{
+
+class TFDepthwiseConv2dNative final
+ : public FixedArityNode<2, TFNodeImpl<TFOpcode::DepthwiseConv2dNative>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+ loco::Node *filter(void) const { return at(1)->node(); }
+ void filter(Node *node) { at(1)->node(node); }
+
+public:
+ const TFPadding &padding(void) const { return _padding; }
+ void padding(const TFPadding &padding) { _padding = padding; }
+
+ const TFDataLayout &data_layout(void) const { return _data_layout; }
+ void data_layout(const TFDataLayout &data_layout) { _data_layout = data_layout; }
+
+ const std::vector<int64_t> &strides(void) const { return _strides; }
+ void strides(const std::vector<int64_t> &strides) { _strides = strides; }
+
+private:
+ TFPadding _padding;
+ TFDataLayout _data_layout;
+ std::vector<int64_t> _strides;
+ // TODO Support "Dilation"
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFDEPTHWISECONV2DNATIVE_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFFakeQuantWithMinMaxVars.h b/compiler/moco/lang/include/moco/IR/Nodes/TFFakeQuantWithMinMaxVars.h
new file mode 100644
index 000000000..ec54da596
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFFakeQuantWithMinMaxVars.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 __MOCO_IR_TFFAKEQUANTWITHMINMAXVARS_H__
+#define __MOCO_IR_TFFAKEQUANTWITHMINMAXVARS_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <vector>
+
+namespace moco
+{
+
+class TFFakeQuantWithMinMaxVars final
+ : public FixedArityNode<3, TFNodeImpl<TFOpcode::FakeQuantWithMinMaxVars>>
+{
+public:
+ loco::Node *inputs(void) const { return at(0)->node(); }
+ void inputs(Node *node) { at(0)->node(node); }
+
+ loco::Node *min(void) const { return at(1)->node(); }
+ void min(Node *node) { at(1)->node(node); }
+
+ loco::Node *max(void) const { return at(2)->node(); }
+ void max(Node *node) { at(2)->node(node); }
+
+public:
+ const int64_t &num_bits(void) const { return _num_bits; }
+ void num_bits(const int64_t &num_bits) { _num_bits = num_bits; }
+
+ const bool &narrow_range(void) const { return _narrow_range; }
+ void narrow_range(const bool &narrow_range) { _narrow_range = narrow_range; }
+
+private:
+ int64_t _num_bits{8};
+ bool _narrow_range{false};
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFFAKEQUANTWITHMINMAXVARS_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFFusedBatchNorm.h b/compiler/moco/lang/include/moco/IR/Nodes/TFFusedBatchNorm.h
new file mode 100644
index 000000000..5b980e3b2
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFFusedBatchNorm.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 __MOCO_IR_TFFUSEDBATCHNORM_H__
+#define __MOCO_IR_TFFUSEDBATCHNORM_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+class TFFusedBatchNorm final : public FixedArityNode<5, TFNodeImpl<TFOpcode::FusedBatchNorm>>
+{
+public:
+ TFFusedBatchNorm() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+
+ Node *scale(void) const { return at(1)->node(); } // gamma
+ void scale(Node *node) { at(1)->node(node); }
+
+ Node *offset(void) const { return at(2)->node(); } // beta
+ void offset(Node *node) { at(2)->node(node); }
+
+ Node *mean(void) const { return at(3)->node(); }
+ void mean(Node *node) { at(3)->node(node); }
+
+ Node *variance(void) const { return at(4)->node(); }
+ void variance(Node *node) { at(4)->node(node); }
+
+ float epsilon(void) const { return _epsilon; }
+ void epsilon(float epsilon) { _epsilon = epsilon; }
+
+private:
+ float _epsilon = 0.001f;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFFUSEDBATCHNORM_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFIdentity.h b/compiler/moco/lang/include/moco/IR/Nodes/TFIdentity.h
new file mode 100644
index 000000000..26a1a36bf
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFIdentity.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 __MOCO_IR_TFIDENTITY_H__
+#define __MOCO_IR_TFIDENTITY_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFIdentity corresponds to the following GraphDef
+/*
+node {
+ name: "identity"
+ op: "Identity"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFIdentity final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Identity>>
+{
+public:
+ TFIdentity() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFIDENTITY_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFMaxPool.h b/compiler/moco/lang/include/moco/IR/Nodes/TFMaxPool.h
new file mode 100644
index 000000000..a66b4044e
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFMaxPool.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFMAXPOOL_H__
+#define __MOCO_IR_TFMAXPOOL_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <vector>
+
+namespace moco
+{
+
+/// @note TFMaxPool corresponds to the following GraphDef
+/*
+node {
+ name: "maxpool2d"
+ op: "MaxPool"
+ input: "placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "ksize"
+ value {
+ list {
+ i: 1 i: 2 i: 2 i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "VALID"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1 i: 1 i: 1 i: 1
+ }
+ }
+ }
+}
+*/
+
+class TFMaxPool final : public FixedArityNode<1, TFNodeImpl<TFOpcode::MaxPool>>
+{
+public:
+ TFMaxPool() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { return at(0)->node(node); }
+
+public:
+ const TFDataLayout &data_layout(void) const { return _data_layout; }
+ void data_layout(const TFDataLayout &data_layout) { _data_layout = data_layout; }
+
+ const TFPadding &padding(void) const { return _padding; }
+ void padding(const TFPadding &padding) { _padding = padding; }
+
+ const std::vector<int64_t> &ksize(void) const { return _ksize; }
+ void ksize(const std::vector<int64_t> &ksize) { _ksize = ksize; }
+
+ const std::vector<int64_t> &strides(void) const { return _strides; }
+ void strides(const std::vector<int64_t> &strides) { _strides = strides; }
+
+private:
+ TFDataLayout _data_layout;
+ TFPadding _padding;
+ std::vector<int64_t> _ksize;
+ std::vector<int64_t> _strides;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFMAXPOOL_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFMaximum.h b/compiler/moco/lang/include/moco/IR/Nodes/TFMaximum.h
new file mode 100644
index 000000000..346dbebe8
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFMaximum.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFMAXIMUM_H__
+#define __MOCO_IR_TFMAXIMUM_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFMaximum corresponds to the following GraphDef
+/*
+node {
+ name: "maximum"
+ op: "Maximum"
+ input: "x"
+ input: "y"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFMaximum final : public FixedArityNode<2, TFNodeImpl<TFOpcode::Maximum>>
+{
+public:
+ TFMaximum() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+
+ Node *y(void) const { return at(1)->node(); }
+ void y(Node *node) { at(1)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFMAXIMUM_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFMean.h b/compiler/moco/lang/include/moco/IR/Nodes/TFMean.h
new file mode 100644
index 000000000..abcd21c49
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFMean.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFMEAN_H__
+#define __MOCO_IR_TFMEAN_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <vector>
+
+namespace moco
+{
+
+/// @note TFMean corresponds to the following GraphDef
+/*
+node {
+ name: "Mean"
+ op: "Mean"
+ input: "Placeholder"
+ input: "Mean/reduction_indices"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "Tidx"
+ value { type: DT_INT32 }
+ }
+ attr {
+ key: "keep_dims"
+ value { b: true }
+ }
+}
+*/
+
+class TFMean final : public FixedArityNode<2, TFNodeImpl<TFOpcode::Mean>>
+{
+public:
+ TFMean() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+ Node *reduction_indices(void) const { return at(1)->node(); }
+ void reduction_indices(Node *node) { at(1)->node(node); }
+
+public:
+ bool keep_dims(void) const { return _keep_dims; }
+ void keep_dims(bool keep_dims) { _keep_dims = keep_dims; }
+
+private:
+ bool _keep_dims = false;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFMEAN_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFMul.h b/compiler/moco/lang/include/moco/IR/Nodes/TFMul.h
new file mode 100644
index 000000000..4692838cb
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFMul.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 __MOCO_IR_TFMUL_H__
+#define __MOCO_IR_TFMUL_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFMul corresponds to the following GraphDef
+/*
+node {
+ name: "mul"
+ op: "Mul"
+ input: "x"
+ input: "y"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFMul final : public FixedArityNode<2, TFNodeImpl<TFOpcode::Mul>>
+{
+public:
+ TFMul() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+
+ Node *y(void) const { return at(1)->node(); }
+ void y(Node *node) { at(1)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFMUL_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFPack.h b/compiler/moco/lang/include/moco/IR/Nodes/TFPack.h
new file mode 100644
index 000000000..1046a18ed
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFPack.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFPACK_H__
+#define __MOCO_IR_TFPACK_H__
+
+#include "moco/IR/TFNodeDecl.h"
+#include "moco/IR/VariadicArityNode.h"
+
+namespace moco
+{
+/// @note TFPack corresponds to the following GraphDef
+/*
+node {
+ name: "Pack"
+ op: "Pack"
+ input: "input_1"
+ input: "input_2"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+}
+*/
+
+class TFPack final : public VariadicArityNode<TFNodeImpl<TFOpcode::Pack>>
+{
+public:
+ TFPack(uint32_t arity) : VariadicArityNode<TFNodeImpl<TFOpcode::Pack>>(arity)
+ {
+ // at least one item should exist
+ assert(arity >= 1);
+ }
+
+public:
+ Node *values(uint32_t index) const
+ {
+ assert(index < arity());
+ return at(index)->node();
+ }
+ void values(uint32_t index, Node *node)
+ {
+ assert(index < arity());
+ at(index)->node(node);
+ }
+
+public:
+ uint32_t N(void) const { return arity(); }
+
+ int32_t axis(void) const { return _axis; }
+ void axis(int32_t axis) { _axis = axis; }
+
+private:
+ int32_t _axis{0};
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFPACK_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFPad.h b/compiler/moco/lang/include/moco/IR/Nodes/TFPad.h
new file mode 100644
index 000000000..dae4741d6
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFPad.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFPAD_H__
+#define __MOCO_IR_TFPAD_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+/// @note TFPad corresponds to the following GraphDef
+/*
+node {
+ name: "Pad"
+ op: "Pad"
+ input: "Const_tensor"
+ input: "Const_paddings"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "Tpaddings"
+ value {
+ type: DT_INT32
+ }
+ }
+}
+*/
+
+class TFPad final : public FixedArityNode<2, TFNodeImpl<TFOpcode::Pad>>
+{
+public:
+ TFPad() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+ Node *paddings(void) const { return at(1)->node(); }
+ void paddings(Node *node) { at(1)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFPAD_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFPlaceholder.h b/compiler/moco/lang/include/moco/IR/Nodes/TFPlaceholder.h
new file mode 100644
index 000000000..65a78e665
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFPlaceholder.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFPLACEHOLDER_H__
+#define __MOCO_IR_TFPLACEHOLDER_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <loco/IR/DataTypeTraits.h>
+#include <loco/IR/NodeMixins.h>
+#include <loco/IR/GraphInputIndex.h>
+#include <loco/IR/TensorShape.h>
+
+namespace moco
+{
+
+/// @note TFPlaceholder corresponds to the following GraphDef
+/*
+node {
+ name: "placeholder"
+ op: "Placeholder"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "shape"
+ value {
+ shape {
+ dim {
+ size: 1
+ }
+ dim {
+ size: 3
+ }
+ dim {
+ size: 3
+ }
+ dim {
+ size: 1
+ }
+ }
+ }
+ }
+}
+*/
+
+/**
+ * @brief IR for tf.placeholder
+ */
+class TFPlaceholder final : public FixedArityNode<0, TFNodeImpl<TFOpcode::Placeholder>>,
+ public loco::NodeMixin<loco::NodeTrait::DataType>,
+ public loco::NodeMixin<loco::NodeTrait::TensorShape>
+{
+public:
+ TFPlaceholder() = default;
+
+ // TODO Update unkown shape information. tensorflow::NodeDef may not have "shape" attr.
+};
+
+} // namespace moco
+
+namespace moco
+{
+
+bool indexed(const TFPlaceholder *node);
+loco::GraphInputIndex index(const TFPlaceholder *node);
+void index(TFPlaceholder *node, const loco::GraphInputIndex index);
+loco::TensorShape tensor_shape(const TFPlaceholder *node);
+
+TFPlaceholder *placeholder_node(loco::Graph *g, const loco::GraphInputIndex &idx);
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFPLACEHOLDER_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFPush.h b/compiler/moco/lang/include/moco/IR/Nodes/TFPush.h
new file mode 100644
index 000000000..e45804252
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFPush.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFPUSH_H__
+#define __MOCO_IR_TFPUSH_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Make a value visible to user
+ *
+ * @note TFPush is a virtual node that does not corresponds to real TensorFlow node
+ * Why this node is introduced:
+ * - Any TensorFlow Nodes can be an output.
+ * - So let any TFNode type can provide OutputIndex using Annotation.
+ * - Problem comes when in transformation, output node can be replaced.
+ * - This causes that OutputIndex Annotation should be copied to new node.
+ * - This makes every transformation in any Dialect code change.
+ * - And even worse, this makes every new transformation follow this rule.
+ * - Which is not good.
+ * - Thus, like loco Canonical does, follow loco::Push.
+ */
+class TFPush /* to user */ final : public FixedArityNode<1, TFNodeImpl<TFOpcode::TFPush>>
+{
+public:
+ TFPush() = default;
+
+public:
+ loco::Node *from(void) const { return at(0)->node(); }
+ void from(loco::Node *node) { at(0)->node(node); }
+
+public:
+ void index(const loco::GraphOutputIndex &index);
+
+ /**
+ * @brief Get associated output index
+ *
+ * The behavior of this method is undefined when "index" is not set before.
+ *
+ * NOTE This method intentionally returns "GraphOutputIndex" instead of "const GraphOutputIndex &"
+ * not to expose the internal implementation details.
+ */
+ loco::GraphOutputIndex index(void) const;
+
+ /**
+ * @brief Check whether index is initialized
+ *
+ * NOTE "indexed" method does not validate whether index is in a valid range
+ */
+ bool indexed(void) const { return _index != -1; }
+
+ /**
+ * @brief Reset output index
+ */
+ void index_reset(void) { _index = -1; }
+
+private:
+ int64_t _index = -1; // Uninitialized
+};
+
+/// @brief Find a TFPush node with a given output index
+TFPush *push_node(loco::Graph *g, const loco::GraphOutputIndex &index);
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFPUSH_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFRealDiv.h b/compiler/moco/lang/include/moco/IR/Nodes/TFRealDiv.h
new file mode 100644
index 000000000..8d61b3d13
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFRealDiv.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 __MOCO_IR_TFREALDIV_H__
+#define __MOCO_IR_TFREALDIV_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFRealDiv corresponds to the following GraphDef
+/*
+node {
+ name: "div"
+ op: "RealDiv"
+ input: "x"
+ input: "y"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFRealDiv final : public FixedArityNode<2, TFNodeImpl<TFOpcode::RealDiv>>
+{
+public:
+ TFRealDiv() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+
+ Node *y(void) const { return at(1)->node(); }
+ void y(Node *node) { at(1)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFREALDIV_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFRelu.h b/compiler/moco/lang/include/moco/IR/Nodes/TFRelu.h
new file mode 100644
index 000000000..90e121e5e
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFRelu.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 __MOCO_IR_TFRELU_H__
+#define __MOCO_IR_TFRELU_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFRelu corresponds to the following GraphDef
+/*
+node {
+ name: "output/relu"
+ op: "Relu"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFRelu final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Relu>>
+{
+public:
+ TFRelu() = default;
+
+public:
+ Node *features(void) const { return at(0)->node(); }
+ void features(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFRELU_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFRelu6.h b/compiler/moco/lang/include/moco/IR/Nodes/TFRelu6.h
new file mode 100644
index 000000000..bb705b782
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFRelu6.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 __MOCO_IR_TFRELU6_H__
+#define __MOCO_IR_TFRELU6_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFRelu6 corresponds to the following GraphDef
+/*
+node {
+ name: "Relu6"
+ op: "Relu6"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+}
+*/
+
+class TFRelu6 final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Relu6>>
+{
+public:
+ TFRelu6() = default;
+
+public:
+ Node *features(void) const { return at(0)->node(); }
+ void features(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFRELU6_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFReshape.h b/compiler/moco/lang/include/moco/IR/Nodes/TFReshape.h
new file mode 100644
index 000000000..1f743565d
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFReshape.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 __MOCO_IR_TFRESHAPE_H__
+#define __MOCO_IR_TFRESHAPE_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFReshape corresponds to the following GraphDef
+/*
+node {
+ name: "reshape"
+ op: "Reshape"
+ input: "tensor"
+ input: "shape"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+}
+*/
+
+class TFReshape final : public FixedArityNode<2, TFNodeImpl<TFOpcode::Reshape>>
+{
+public:
+ TFReshape() = default;
+
+public:
+ Node *tensor(void) const { return at(0)->node(); }
+ void tensor(Node *node) { at(0)->node(node); }
+
+ Node *shape(void) const { return at(1)->node(); }
+ void shape(Node *node) { at(1)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFRESHAPE_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFRsqrt.h b/compiler/moco/lang/include/moco/IR/Nodes/TFRsqrt.h
new file mode 100644
index 000000000..c71a5b98c
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFRsqrt.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 __MOCO_IR_TFRSQRT_H__
+#define __MOCO_IR_TFRSQRT_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFRsqrt corresponds to the following GraphDef
+/*
+node {
+ name: "Rsqrt"
+ op: "Rsqrt"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFRsqrt final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Rsqrt>>
+{
+public:
+ TFRsqrt() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFRSQRT_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFShape.h b/compiler/moco/lang/include/moco/IR/Nodes/TFShape.h
new file mode 100644
index 000000000..36f0f1e69
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFShape.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 __MOCO_IR_TFSHAPE_H__
+#define __MOCO_IR_TFSHAPE_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <loco/IR/NodeMixins.h>
+
+#include <vector>
+
+namespace moco
+{
+
+/// @note TFShape corresponds to the following GraphDef
+/*
+node {
+ name: "Shape"
+ op: "Shape"
+ input: "some_input"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "out_type"
+ value { type: DT_INT32 }
+ }
+}
+*/
+
+/// @note Mixed in dtype() is for 'out_type' attribute
+class TFShape final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Shape>>,
+ public loco::NodeMixin<loco::NodeTrait::DataType>
+{
+public:
+ TFShape() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFSHAPE_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFSoftmax.h b/compiler/moco/lang/include/moco/IR/Nodes/TFSoftmax.h
new file mode 100644
index 000000000..c98df1d82
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFSoftmax.h
@@ -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.
+ */
+
+#ifndef __MOCO_IR_TFSOFTMAX_H__
+#define __MOCO_IR_TFSOFTMAX_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+class TFSoftmax final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Softmax>>
+{
+public:
+ TFSoftmax() = default;
+
+public:
+ Node *logits(void) const { return at(0)->node(); }
+ void logits(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFSOFTMAX_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFSqrt.h b/compiler/moco/lang/include/moco/IR/Nodes/TFSqrt.h
new file mode 100644
index 000000000..273b5d49b
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFSqrt.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 __MOCO_IR_TFSQRT_H__
+#define __MOCO_IR_TFSQRT_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFSqrt corresponds to the following GraphDef
+/*
+node {
+ name: "Sqrt"
+ op: "Sqrt"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFSqrt final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Sqrt>>
+{
+public:
+ TFSqrt() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFSQRT_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFSquaredDifference.h b/compiler/moco/lang/include/moco/IR/Nodes/TFSquaredDifference.h
new file mode 100644
index 000000000..4e0a929d3
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFSquaredDifference.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 __MOCO_IR_TFSQUAREDDIFFERENCE_H__
+#define __MOCO_IR_TFSQUAREDDIFFERENCE_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFSquaredDifference corresponds to the following GraphDef
+/*
+node {
+ name: "SquaredDifference"
+ op: "SquaredDifference"
+ input: "input_x"
+ input: "input_y"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFSquaredDifference final : public FixedArityNode<2, TFNodeImpl<TFOpcode::SquaredDifference>>
+{
+public:
+ TFSquaredDifference() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+
+ Node *y(void) const { return at(1)->node(); }
+ void y(Node *node) { at(1)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFSQUAREDDIFFERENCE_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFSqueeze.h b/compiler/moco/lang/include/moco/IR/Nodes/TFSqueeze.h
new file mode 100644
index 000000000..612497ee7
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFSqueeze.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFSQUEEZE_H__
+#define __MOCO_IR_TFSQUEEZE_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+#include <vector>
+
+namespace moco
+{
+
+/// @note TFSqueeze corresponds to the following GraphDef
+/*
+node {
+ name: "squeeze"
+ op: "Squeeze"
+ input: "x"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "squeeze_dims"
+ value {
+ list {
+ i: a
+ i: b
+ ..
+ }
+ }
+ }
+}
+*/
+
+class TFSqueeze final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Squeeze>>
+{
+public:
+ TFSqueeze() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+public:
+ const std::vector<int64_t> &squeeze_dims(void) const { return _squeeze_dims; }
+ void squeeze_dims(const std::vector<int64_t> &squeeze_dims) { _squeeze_dims = squeeze_dims; }
+
+private:
+ std::vector<int64_t> _squeeze_dims;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFSQUEEZE_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFStopGradient.h b/compiler/moco/lang/include/moco/IR/Nodes/TFStopGradient.h
new file mode 100644
index 000000000..cfebd92a9
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFStopGradient.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 __MOCO_IR_TFSTOPGRADIENT_H__
+#define __MOCO_IR_TFSTOPGRADIENT_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFStopGradient corresponds to the following GraphDef
+/*
+node {
+ name: "StopGradient"
+ op: "StopGradient"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFStopGradient final : public FixedArityNode<1, TFNodeImpl<TFOpcode::StopGradient>>
+{
+public:
+ TFStopGradient() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFSTOPGRADIENT_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFStridedSlice.h b/compiler/moco/lang/include/moco/IR/Nodes/TFStridedSlice.h
new file mode 100644
index 000000000..75012b219
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFStridedSlice.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFSTRIDEDSLICE_H__
+#define __MOCO_IR_TFSTRIDEDSLICE_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFStridedSlice corresponds to the following GraphDef
+/*
+node {
+ name: "StridedSlice"
+ op: "StridedSlice"
+ input: "input"
+ input: "begin"
+ input: "end"
+ input: "stride"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 0
+ }
+ }
+}
+*/
+
+class TFStridedSlice final : public FixedArityNode<4, TFNodeImpl<TFOpcode::StridedSlice>>
+{
+public:
+ TFStridedSlice() = default;
+
+public:
+ Node *input(void) const { return at(0)->node(); }
+ void input(Node *node) { at(0)->node(node); }
+
+ Node *begin(void) const { return at(1)->node(); }
+ void begin(Node *node) { at(1)->node(node); }
+
+ Node *end(void) const { return at(2)->node(); }
+ void end(Node *node) { at(2)->node(node); }
+
+ Node *strides(void) const { return at(3)->node(); }
+ void strides(Node *node) { at(3)->node(node); }
+
+public:
+ int32_t begin_mask(void) const { return _begin_mask; }
+ void begin_mask(int32_t begin_mask) { _begin_mask = begin_mask; }
+
+ int32_t end_mask(void) const { return _end_mask; }
+ void end_mask(int32_t end_mask) { _end_mask = end_mask; }
+
+ int32_t ellipsis_mask(void) const { return _ellipsis_mask; }
+ void ellipsis_mask(int32_t ellipsis_mask) { _ellipsis_mask = ellipsis_mask; }
+
+ int32_t new_axis_mask(void) const { return _new_axis_mask; }
+ void new_axis_mask(int32_t new_axis_mask) { _new_axis_mask = new_axis_mask; }
+
+ int32_t shrink_axis_mask(void) const { return _shrink_axis_mask; }
+ void shrink_axis_mask(int32_t shrink_axis_mask) { _shrink_axis_mask = shrink_axis_mask; }
+
+private:
+ int32_t _begin_mask{0};
+ int32_t _end_mask{0};
+ int32_t _ellipsis_mask{0};
+ int32_t _new_axis_mask{0};
+ int32_t _shrink_axis_mask{0};
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFSTRIDEDSLICE_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFSub.h b/compiler/moco/lang/include/moco/IR/Nodes/TFSub.h
new file mode 100644
index 000000000..27905cbdb
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFSub.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 __MOCO_IR_TFSUB_H__
+#define __MOCO_IR_TFSUB_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+/// @note TFSub corresponds to the following GraphDef
+/*
+node {
+ name: "sub"
+ op: "Sub"
+ input: "x"
+ input: "y"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+*/
+
+class TFSub final : public FixedArityNode<2, TFNodeImpl<TFOpcode::Sub>>
+{
+public:
+ TFSub() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+
+ Node *y(void) const { return at(1)->node(); }
+ void y(Node *node) { at(1)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFSUB_H__
diff --git a/compiler/moco/lang/include/moco/IR/Nodes/TFTanh.h b/compiler/moco/lang/include/moco/IR/Nodes/TFTanh.h
new file mode 100644
index 000000000..4543c62f3
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/Nodes/TFTanh.h
@@ -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.
+ */
+
+#ifndef __MOCO_IR_TFTANH_H__
+#define __MOCO_IR_TFTANH_H__
+
+#include "moco/IR/TFNodeDecl.h"
+
+namespace moco
+{
+
+class TFTanh final : public FixedArityNode<1, TFNodeImpl<TFOpcode::Tanh>>
+{
+public:
+ TFTanh() = default;
+
+public:
+ Node *x(void) const { return at(0)->node(); }
+ void x(Node *node) { at(0)->node(node); }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFTANH_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFDataLayout.h b/compiler/moco/lang/include/moco/IR/TFDataLayout.h
new file mode 100644
index 000000000..f0edfacd5
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFDataLayout.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFDATALAYOUT_H__
+#define __MOCO_IR_TFDATALAYOUT_H__
+
+#include <string>
+
+namespace moco
+{
+
+using TFDataLayout = std::string;
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFDATALAYOUT_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFDialect.h b/compiler/moco/lang/include/moco/IR/TFDialect.h
new file mode 100644
index 000000000..847bc527f
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFDialect.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFDIALECT_H__
+#define __MOCO_IR_TFDIALECT_H__
+
+#include <loco/IR/Dialect.h>
+
+namespace moco
+{
+
+/**
+ * @brief A singleton for TensorFlow Dialect
+ */
+class TFDialect final : public loco::Dialect
+{
+private:
+ TFDialect();
+
+public:
+ TFDialect(const TFDialect &) = delete;
+ TFDialect(TFDialect &&) = delete;
+
+public:
+ static loco::Dialect *get(void);
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFDIALECT_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFNode.h b/compiler/moco/lang/include/moco/IR/TFNode.h
new file mode 100644
index 000000000..e3d900ba3
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFNode.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFNODE_H__
+#define __MOCO_IR_TFNODE_H__
+
+#include "moco/IR/TFNodeDecl.h"
+#include "moco/IR/TFNodeImpl.h"
+
+#endif // __MOCO_IR_TFNODE_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFNodeDecl.h b/compiler/moco/lang/include/moco/IR/TFNodeDecl.h
new file mode 100644
index 000000000..68d7161b6
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFNodeDecl.h
@@ -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.
+ */
+
+#ifndef __MOCO_IR_TFNODE_DECL_H__
+#define __MOCO_IR_TFNODE_DECL_H__
+
+#include <loco/IR/Node.h>
+#include <loco/IR/Dialect.h>
+
+#include "moco/IR/TFOpcode.h"
+#include "moco/IR/TFNodeVisitor.forward.h"
+
+#include "moco/IR/TFDataLayout.h"
+#include "moco/IR/TFPadding.h"
+
+#include <array>
+#include <string>
+
+namespace moco
+{
+
+/**
+ * @note NodeName is string name of the Node without ':#' prefix like ':0' or ':1'
+ */
+using NodeName = std::string;
+
+struct TFNode : public loco::Node
+{
+ virtual ~TFNode() = default;
+
+ const loco::Dialect *dialect(void) const final;
+ virtual TFOpcode opcode(void) const = 0;
+
+ template <typename T> T accept(TFNodeVisitorBase<T> *) const;
+ template <typename T> T accept(TFNodeMutableVisitorBase<T> *);
+
+ NodeName name(void) const { return _name; }
+ void name(const NodeName &name) { _name = name; }
+
+private:
+ NodeName _name;
+};
+
+template <TFOpcode Code> struct TFNodeImpl : public TFNode
+{
+ virtual ~TFNodeImpl() = default;
+
+ uint32_t opnum(void) const final { return static_cast<uint32_t>(Code); }
+ TFOpcode opcode(void) const final { return Code; }
+};
+
+/**
+ * @brief Nodes with the fixed number of inputs
+ */
+template <unsigned N, typename Base> class FixedArityNode : public Base
+{
+public:
+ FixedArityNode()
+ {
+ for (uint32_t n = 0; n < N; ++n)
+ {
+ _args[n] = std::unique_ptr<loco::Use>{new loco::Use{this}};
+ }
+ }
+
+ virtual ~FixedArityNode() = default;
+
+public:
+ unsigned arity(void) const final { return N; }
+
+ loco::Node *arg(uint32_t n) const final { return _args.at(n)->node(); }
+
+ void drop(void) final
+ {
+ for (uint32_t n = 0; n < N; ++n)
+ {
+ _args.at(n)->node(nullptr);
+ }
+ }
+
+protected:
+ // This API allows inherited classes to access "_args" field.
+ loco::Use *at(unsigned n) const { return _args.at(n).get(); }
+
+private:
+ std::array<std::unique_ptr<loco::Use>, N> _args{};
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFNODE_DECL_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFNodeImpl.h b/compiler/moco/lang/include/moco/IR/TFNodeImpl.h
new file mode 100644
index 000000000..afc306031
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFNodeImpl.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 __MOCO_IR_TFNODE_IMPL_H__
+#define __MOCO_IR_TFNODE_IMPL_H__
+
+#include "moco/IR/TFNodes.h"
+#include "moco/IR/TFNodeVisitor.h"
+
+#include <stdexcept>
+
+namespace moco
+{
+
+template <typename T> T TFNode::accept(TFNodeVisitorBase<T> *v) const
+{
+ switch (this->opcode())
+ {
+#define TENSORFLOW_NODE(OPCODE, CLASS) \
+ case TFOpcode::OPCODE: \
+ return v->visit(dynamic_cast<const CLASS *>(this));
+
+#include "TFNodes.lst"
+#undef TENSORFLOW_NODE
+ default:
+ break;
+ }
+
+ // TODO including oops will make oops dependent to modules that include this
+ // postpone decision to this or not
+ throw std::runtime_error{"Unsupported Node"};
+}
+
+template <typename T> T TFNode::accept(TFNodeMutableVisitorBase<T> *v)
+{
+ switch (this->opcode())
+ {
+#define TENSORFLOW_NODE(OPCODE, CLASS) \
+ case TFOpcode::OPCODE: \
+ return v->visit(dynamic_cast<CLASS *>(this));
+
+#include "TFNodes.lst"
+#undef TENSORFLOW_NODE
+ default:
+ break;
+ }
+
+ // TODO including oops will make oops dependent to modules that include this
+ // postpone decision to this or not
+ throw std::runtime_error{"Unsupported Node"};
+}
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFNODE_IMPL_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFNodeVisitor.forward.h b/compiler/moco/lang/include/moco/IR/TFNodeVisitor.forward.h
new file mode 100644
index 000000000..1eb86871c
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFNodeVisitor.forward.h
@@ -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.
+ */
+
+#ifndef __MOCO_IR_TFNODE_VISITOR_FORWARD_H__
+#define __MOCO_IR_TFNODE_VISITOR_FORWARD_H__
+
+namespace moco
+{
+
+// NOTE These forward declarations SHOULD BE aligned with Node delcarations in
+// "TFNodeVisitor.h"
+template <typename T> struct TFNodeVisitorBase;
+template <typename T> struct TFNodeMutableVisitorBase;
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFNODE_VISITOR_FORWARD_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFNodeVisitor.h b/compiler/moco/lang/include/moco/IR/TFNodeVisitor.h
new file mode 100644
index 000000000..8d23e447d
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFNodeVisitor.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 __MOCO_IR_TFNODE_VISITOR_H__
+#define __MOCO_IR_TFNODE_VISITOR_H__
+
+#include "moco/IR/TFNodes.h"
+
+#include <stdexcept>
+
+namespace moco
+{
+
+/**
+ * DO NOT use this class. Use TFNodeVisitor instead.
+ */
+template <typename T> struct TFNodeVisitorBase
+{
+ virtual ~TFNodeVisitorBase() = default;
+
+#define TENSORFLOW_NODE(OPCODE, CLASS) virtual T visit(const CLASS *) = 0;
+#include "TFNodes.lst"
+#undef TENSORFLOW_NODE
+};
+
+template <typename T> struct TFNodeVisitor : public TFNodeVisitorBase<T>
+{
+ virtual ~TFNodeVisitor() = default;
+
+#define TENSORFLOW_NODE(OPCODE, CLASS) \
+ virtual T visit(const CLASS *node) { return visit(static_cast<const TFNode *>(node)); }
+#include "TFNodes.lst"
+#undef TENSORFLOW_NODE
+
+ // TODO including oops will make oops dependent to modules that include this
+ // postpone decision to this or not
+ /// @brief Default fallback
+ virtual T visit(const TFNode *) { throw std::runtime_error{"Unsupported Node"}; }
+};
+
+/**
+ * DO NOT use this class. Use TFNodeMutableVisitor instead.
+ */
+template <typename T> struct TFNodeMutableVisitorBase
+{
+ virtual ~TFNodeMutableVisitorBase() = default;
+
+#define TENSORFLOW_NODE(OPCODE, CLASS) virtual T visit(CLASS *) = 0;
+#include "TFNodes.lst"
+#undef TENSORFLOW_NODE
+};
+
+template <typename T> struct TFNodeMutableVisitor : public TFNodeMutableVisitorBase<T>
+{
+ virtual ~TFNodeMutableVisitor() = default;
+
+#define TENSORFLOW_NODE(OPCODE, CLASS) \
+ virtual T visit(CLASS *node) { return visit(static_cast<TFNode *>(node)); }
+#include "TFNodes.lst"
+#undef TENSORFLOW_NODE
+
+ // TODO including oops will make oops dependent to modules that include this
+ // postpone decision to this or not
+ /// @brief Default fallback
+ virtual T visit(TFNode *) { throw std::runtime_error{"Unsupported Node"}; }
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFNODE_VISITOR_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFNodes.h b/compiler/moco/lang/include/moco/IR/TFNodes.h
new file mode 100644
index 000000000..ad54dfdf3
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFNodes.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 __MOCO_IR_TFNODES_H__
+#define __MOCO_IR_TFNODES_H__
+
+#include "moco/IR/Nodes/TFAdd.h"
+#include "moco/IR/Nodes/TFAvgPool.h"
+#include "moco/IR/Nodes/TFBiasAdd.h"
+#include "moco/IR/Nodes/TFConcatV2.h"
+#include "moco/IR/Nodes/TFConst.h"
+#include "moco/IR/Nodes/TFConv2D.h"
+#include "moco/IR/Nodes/TFConv2DBackpropInput.h"
+#include "moco/IR/Nodes/TFDepthwiseConv2dNative.h"
+#include "moco/IR/Nodes/TFFakeQuantWithMinMaxVars.h"
+#include "moco/IR/Nodes/TFFusedBatchNorm.h"
+#include "moco/IR/Nodes/TFIdentity.h"
+#include "moco/IR/Nodes/TFMaximum.h"
+#include "moco/IR/Nodes/TFMaxPool.h"
+#include "moco/IR/Nodes/TFMean.h"
+#include "moco/IR/Nodes/TFMul.h"
+#include "moco/IR/Nodes/TFPack.h"
+#include "moco/IR/Nodes/TFPad.h"
+#include "moco/IR/Nodes/TFPlaceholder.h"
+#include "moco/IR/Nodes/TFRealDiv.h"
+#include "moco/IR/Nodes/TFRelu.h"
+#include "moco/IR/Nodes/TFRelu6.h"
+#include "moco/IR/Nodes/TFReshape.h"
+#include "moco/IR/Nodes/TFRsqrt.h"
+#include "moco/IR/Nodes/TFShape.h"
+#include "moco/IR/Nodes/TFSoftmax.h"
+#include "moco/IR/Nodes/TFSqrt.h"
+#include "moco/IR/Nodes/TFSquaredDifference.h"
+#include "moco/IR/Nodes/TFSqueeze.h"
+#include "moco/IR/Nodes/TFStopGradient.h"
+#include "moco/IR/Nodes/TFStridedSlice.h"
+#include "moco/IR/Nodes/TFSub.h"
+#include "moco/IR/Nodes/TFTanh.h"
+// For virtual node(s)
+#include "moco/IR/Nodes/TFPush.h"
+
+#endif // __MOCO_IR_TFNODES_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFNodes.lst b/compiler/moco/lang/include/moco/IR/TFNodes.lst
new file mode 100644
index 000000000..8373d2b8d
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFNodes.lst
@@ -0,0 +1,48 @@
+#ifndef TENSORFLOW_NODE
+#error "Define TENSORFLOW_NODE"
+#endif // TENSORFLOW_NODE
+
+//
+// PLEASE SORT NODE DECLS IN ALPHABETICAL ORDER
+//
+// Naming rule: Follow names in TensorFlow C++ source
+// ex) for AvgPool, tensorflow/core/ops/nn_ops.cc
+// REGISTER_OP("AvgPool") <-- OPCODE: AvgPool. Prefix `TF` for CLASS name
+// .Input("value: T") <-- Input name is 'value'
+//
+
+// TENSORFLOW_NODE(OPCODE, CLASS)
+TENSORFLOW_NODE(Add, TFAdd)
+TENSORFLOW_NODE(AvgPool, TFAvgPool)
+TENSORFLOW_NODE(BiasAdd, TFBiasAdd)
+TENSORFLOW_NODE(ConcatV2, TFConcatV2)
+TENSORFLOW_NODE(Const, TFConst)
+TENSORFLOW_NODE(Conv2D, TFConv2D)
+TENSORFLOW_NODE(Conv2DBackpropInput, TFConv2DBackpropInput)
+TENSORFLOW_NODE(DepthwiseConv2dNative, TFDepthwiseConv2dNative)
+TENSORFLOW_NODE(FakeQuantWithMinMaxVars, TFFakeQuantWithMinMaxVars)
+TENSORFLOW_NODE(FusedBatchNorm, TFFusedBatchNorm)
+TENSORFLOW_NODE(Identity, TFIdentity)
+TENSORFLOW_NODE(Maximum, TFMaximum)
+TENSORFLOW_NODE(MaxPool, TFMaxPool)
+TENSORFLOW_NODE(Mean, TFMean)
+TENSORFLOW_NODE(Mul, TFMul)
+TENSORFLOW_NODE(Pack, TFPack)
+TENSORFLOW_NODE(Pad, TFPad)
+TENSORFLOW_NODE(Placeholder, TFPlaceholder)
+TENSORFLOW_NODE(RealDiv, TFRealDiv)
+TENSORFLOW_NODE(Relu, TFRelu)
+TENSORFLOW_NODE(Relu6, TFRelu6)
+TENSORFLOW_NODE(Reshape, TFReshape)
+TENSORFLOW_NODE(Rsqrt, TFRsqrt)
+TENSORFLOW_NODE(Shape, TFShape)
+TENSORFLOW_NODE(Softmax, TFSoftmax)
+TENSORFLOW_NODE(Sqrt, TFSqrt)
+TENSORFLOW_NODE(SquaredDifference, TFSquaredDifference)
+TENSORFLOW_NODE(Squeeze, TFSqueeze)
+TENSORFLOW_NODE(StopGradient, TFStopGradient)
+TENSORFLOW_NODE(StridedSlice, TFStridedSlice)
+TENSORFLOW_NODE(Sub, TFSub)
+TENSORFLOW_NODE(Tanh, TFTanh)
+// For virtual node(s)
+TENSORFLOW_NODE(TFPush, TFPush)
diff --git a/compiler/moco/lang/include/moco/IR/TFOpcode.h b/compiler/moco/lang/include/moco/IR/TFOpcode.h
new file mode 100644
index 000000000..7524dcce4
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFOpcode.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFOPCODE_H__
+#define __MOCO_IR_TFOPCODE_H__
+
+namespace moco
+{
+
+/**
+ * @brief TensorFlow Node Opcode
+ */
+enum class TFOpcode
+{
+#define TENSORFLOW_NODE(OPCODE, CLASS) OPCODE,
+#include "TFNodes.lst"
+#undef TENSORFLOW_NODE
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFOPCODE_H__
diff --git a/compiler/moco/lang/include/moco/IR/TFPadding.h b/compiler/moco/lang/include/moco/IR/TFPadding.h
new file mode 100644
index 000000000..c75b3f2ce
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/TFPadding.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_TFPADDING_H__
+#define __MOCO_IR_TFPADDING_H__
+
+#include <string>
+
+namespace moco
+{
+
+using TFPadding = std::string;
+
+} // namespace moco
+
+#endif // __MOCO_IR_TFPADDING_H__
diff --git a/compiler/moco/lang/include/moco/IR/VariadicArityNode.h b/compiler/moco/lang/include/moco/IR/VariadicArityNode.h
new file mode 100644
index 000000000..7df0f7dec
--- /dev/null
+++ b/compiler/moco/lang/include/moco/IR/VariadicArityNode.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_IR_VARIADIC_ARITY_NODE_H__
+#define __MOCO_IR_VARIADIC_ARITY_NODE_H__
+
+#include <loco/IR/Node.h>
+#include <loco/IR/Use.h>
+
+#include <vector>
+#include <memory>
+#include <cassert>
+
+namespace moco
+{
+
+/**
+ * @brief Nodes with the variadic inputs
+ */
+template <typename Base> class VariadicArityNode : public Base
+{
+public:
+ VariadicArityNode(uint32_t arity)
+ {
+ for (uint32_t n = 0; n < arity; ++n)
+ {
+ _args.emplace_back(std::move(std::unique_ptr<loco::Use>{new loco::Use{this}}));
+ }
+ };
+
+ virtual ~VariadicArityNode() = default;
+
+public:
+ uint32_t arity(void) const final { return _args.size(); }
+
+ loco::Node *arg(uint32_t n) const final
+ {
+ assert(n < _args.size());
+ return _args.at(n)->node();
+ }
+
+ void drop(void) final
+ {
+ for (uint32_t n = 0; n < _args.size(); ++n)
+ {
+ _args.at(n)->node(nullptr);
+ }
+ }
+
+protected:
+ // This API allows inherited classes to access "_args" field.
+ loco::Use *at(uint32_t n) const
+ {
+ assert(n < _args.size());
+ return _args.at(n).get();
+ }
+
+private:
+ std::vector<std::unique_ptr<loco::Use>> _args;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IR_VARIADIC_ARITY_NODE_H__
diff --git a/compiler/moco/lang/include/moco/Names.h b/compiler/moco/lang/include/moco/Names.h
new file mode 100644
index 000000000..1addc812b
--- /dev/null
+++ b/compiler/moco/lang/include/moco/Names.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 __MOCO_NAMES_H__
+#define __MOCO_NAMES_H__
+
+#include <string>
+#include <stdexcept>
+
+namespace moco
+{
+
+struct TensorName final
+{
+public:
+ /**
+ * @brief Constructor
+ *
+ * @note If tensor_name does not have ":index", this constructor adds ":0" by default
+ */
+ explicit TensorName(const std::string &tensor_name)
+ {
+ if (tensor_name.find(":") != std::string::npos) // tensor_name is a form of letter:0
+ {
+ _name.assign(tensor_name);
+ }
+ else
+ {
+ _name.assign(tensor_name + ":0"); // if it does not have ":index", adds ":0" by default
+ }
+ }
+
+ explicit TensorName(const std::string &node_name, const int tensor_index)
+ {
+ if (node_name.find(":") != std::string::npos) // tensor_name is already a form of name:0
+ {
+ // TODO including oops will make oops dependent to modules that include this
+ // postpone decision to this or not
+ throw std::runtime_error("Error: Node name has already tensor index:" + node_name);
+ }
+ else
+ {
+ _name.assign(node_name + ":" + std::to_string(tensor_index));
+ }
+ }
+
+ const std::string &name() const { return _name; }
+
+ /**
+ * @brief Returns node name from tensor name by removing, e.g., ":0"
+ */
+ const std::string nodeName() const
+ {
+ auto index = _name.find(":");
+
+ if (index != std::string::npos)
+ return _name.substr(0, index);
+ else
+ {
+ // TODO including oops will make oops dependent to modules that include this
+ // postpone decision to this or not
+ throw std::runtime_error{"Error: Tensor name should be a 'name:number' format: " + _name};
+ }
+ };
+
+private:
+ std::string _name;
+};
+
+/**
+ * @brief To use TensorName as a key in std::map, this struct defines how to compare two TensorNames
+ */
+struct TensorNameCompare
+{
+ bool operator()(const TensorName &lhs, const TensorName &rhs) const
+ {
+ return lhs.name() < rhs.name();
+ }
+};
+
+} // namespace moco
+
+#endif // __MOCO_NAMES_H__
diff --git a/compiler/moco/lang/src/IR/Nodes/TFAdd.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFAdd.test.cpp
new file mode 100644
index 000000000..d2cfb6ac4
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFAdd.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFAdd.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFAddTest, constructor)
+{
+ moco::TFAdd add_node;
+
+ ASSERT_EQ(add_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(add_node.opcode(), moco::TFOpcode::Add);
+
+ ASSERT_EQ(add_node.x(), nullptr);
+ ASSERT_EQ(add_node.y(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFAvgPool.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFAvgPool.test.cpp
new file mode 100644
index 000000000..32a27ffa0
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFAvgPool.test.cpp
@@ -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.
+ */
+
+#include "moco/IR/Nodes/TFAvgPool.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFAvgPoolTest, constructor)
+{
+ moco::TFAvgPool avgpool;
+
+ ASSERT_EQ(avgpool.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(avgpool.opcode(), moco::TFOpcode::AvgPool);
+
+ ASSERT_EQ(avgpool.value(), nullptr);
+ ASSERT_EQ(avgpool.data_layout(), "");
+ ASSERT_EQ(avgpool.padding(), "");
+ ASSERT_EQ(avgpool.ksize(), std::vector<int64_t>({}));
+ ASSERT_EQ(avgpool.strides(), std::vector<int64_t>({}));
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFBiasAdd.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFBiasAdd.test.cpp
new file mode 100644
index 000000000..4a15a4981
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFBiasAdd.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFBiasAdd.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFBiasAddTest, constructor)
+{
+ moco::TFBiasAdd bias_add;
+
+ ASSERT_EQ(bias_add.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(bias_add.opcode(), moco::TFOpcode::BiasAdd);
+
+ ASSERT_EQ(bias_add.value(), nullptr);
+ ASSERT_EQ(bias_add.bias(), nullptr);
+ ASSERT_EQ(bias_add.data_layout(), "");
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFConcatV2.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFConcatV2.test.cpp
new file mode 100644
index 000000000..8f7df92d0
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFConcatV2.test.cpp
@@ -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.
+ */
+
+#include "moco/IR/Nodes/TFConcatV2.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFConcatV2Test, constructor)
+{
+ moco::TFConcatV2 concatv2_node(3); // num of values
+
+ ASSERT_EQ(concatv2_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(concatv2_node.opcode(), moco::TFOpcode::ConcatV2);
+
+ ASSERT_EQ(concatv2_node.num_values(), 3);
+ ASSERT_EQ(concatv2_node.values(0), nullptr);
+ ASSERT_EQ(concatv2_node.values(1), nullptr);
+ ASSERT_EQ(concatv2_node.values(2), nullptr);
+ ASSERT_EQ(concatv2_node.axis(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFConst.cpp b/compiler/moco/lang/src/IR/Nodes/TFConst.cpp
new file mode 100644
index 000000000..5c8c08ec0
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFConst.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFConst.h"
+
+#include <cassert>
+
+namespace moco
+{
+
+template <loco::DataType DT> uint32_t TFConst::size(void) const
+{
+ assert(dtype() == DT);
+ assert(_data.size() % sizeof(typename loco::DataTypeImpl<DT>::Type) == 0);
+ return _data.size() / sizeof(typename loco::DataTypeImpl<DT>::Type);
+}
+
+template <loco::DataType DT> void TFConst::size(uint32_t l)
+{
+ assert(dtype() == DT);
+ _data.resize(l * sizeof(typename loco::DataTypeImpl<DT>::Type));
+}
+
+template <loco::DataType DT>
+const typename loco::DataTypeImpl<DT>::Type &TFConst::at(uint32_t n) const
+{
+ assert(dtype() == DT);
+ assert(n < size<DT>());
+ return *(reinterpret_cast<const typename loco::DataTypeImpl<DT>::Type *>(_data.data()) + n);
+}
+
+template <loco::DataType DT> typename loco::DataTypeImpl<DT>::Type &TFConst::at(uint32_t n)
+{
+ assert(dtype() == DT);
+ assert(n < size<DT>());
+ return *(reinterpret_cast<typename loco::DataTypeImpl<DT>::Type *>(_data.data()) + n);
+}
+
+#define INSTANTIATE(DT) \
+ template uint32_t TFConst::size<DT>(void) const; \
+ template void TFConst::size<DT>(uint32_t); \
+ template const typename loco::DataTypeImpl<DT>::Type &TFConst::at<DT>(uint32_t) const; \
+ template typename loco::DataTypeImpl<DT>::Type &TFConst::at<DT>(uint32_t);
+
+INSTANTIATE(loco::DataType::S8);
+INSTANTIATE(loco::DataType::S32);
+INSTANTIATE(loco::DataType::FLOAT32);
+
+#undef INSTANTIATE
+
+loco::TensorShape tensor_shape(const TFConst *node)
+{
+ assert(node != nullptr);
+
+ loco::TensorShape shape;
+
+ uint32_t rank = node->rank();
+ shape.rank(rank);
+ for (uint32_t index = 0; index < rank; ++index)
+ {
+ assert(node->dim(index).known());
+ shape.dim(index) = node->dim(index).value();
+ }
+
+ return shape;
+}
+
+uint32_t num_elements(const TFConst *tfconst)
+{
+ assert(tfconst != nullptr);
+
+ uint32_t num_elements = 1;
+ for (uint32_t index = 0; index < tfconst->rank(); ++index)
+ {
+ assert(tfconst->dim(index).known());
+ uint32_t dim = tfconst->dim(index).value();
+ num_elements = num_elements * dim;
+ }
+ return num_elements;
+}
+
+bool same_shape(const TFConst *lhs, const TFConst *rhs)
+{
+ assert(lhs != nullptr);
+ assert(rhs != nullptr);
+
+ if (lhs->rank() != rhs->rank())
+ return false;
+
+ for (uint32_t index = 0; index < lhs->rank(); ++index)
+ {
+ assert(lhs->dim(index).known());
+ assert(rhs->dim(index).known());
+ if (lhs->dim(index).value() != rhs->dim(index).value())
+ return false;
+ }
+ return true;
+}
+
+} // namespace moco
diff --git a/compiler/moco/lang/src/IR/Nodes/TFConst.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFConst.test.cpp
new file mode 100644
index 000000000..259966e33
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFConst.test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFConst.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFConstantTest, constructor)
+{
+ moco::TFConst constant;
+
+ ASSERT_EQ(constant.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(constant.opcode(), moco::TFOpcode::Const);
+
+ ASSERT_EQ(constant.dtype(), loco::DataType::Unknown);
+ ASSERT_EQ(constant.rank(), 0);
+
+ constant.dtype(loco::DataType::FLOAT32);
+ ASSERT_EQ(constant.dtype(), loco::DataType::FLOAT32);
+
+ constant.rank(2);
+ ASSERT_EQ(constant.rank(), 2);
+
+ constant.dim(0) = 2;
+ constant.dim(1) = 3;
+
+ ASSERT_TRUE(constant.dim(0).known());
+ ASSERT_TRUE(constant.dim(1).known());
+
+ ASSERT_EQ(constant.dim(0), 2);
+ ASSERT_EQ(constant.dim(1), 3);
+
+ constant.size<loco::DataType::FLOAT32>(6);
+
+ ASSERT_EQ(constant.size<loco::DataType::FLOAT32>(), 6);
+
+ constant.at<loco::DataType::FLOAT32>(0) = 0.0f; // Set 0,0
+ constant.at<loco::DataType::FLOAT32>(1) = 1.0f; // Set 0,1
+ constant.at<loco::DataType::FLOAT32>(2) = 2.0f; // Set 0,2
+ constant.at<loco::DataType::FLOAT32>(3) = 3.0f; // Set 1,0
+ constant.at<loco::DataType::FLOAT32>(4) = 4.0f; // Set 1,1
+ constant.at<loco::DataType::FLOAT32>(5) = 5.0f; // Set 1,2
+
+ ASSERT_EQ(constant.at<loco::DataType::FLOAT32>(0), 0.0f);
+ ASSERT_EQ(constant.at<loco::DataType::FLOAT32>(1), 1.0f);
+ ASSERT_EQ(constant.at<loco::DataType::FLOAT32>(2), 2.0f);
+ ASSERT_EQ(constant.at<loco::DataType::FLOAT32>(3), 3.0f);
+ ASSERT_EQ(constant.at<loco::DataType::FLOAT32>(4), 4.0f);
+ ASSERT_EQ(constant.at<loco::DataType::FLOAT32>(5), 5.0f);
+}
+
+TEST(TFConstantTest, datatype_s8)
+{
+ moco::TFConst constant;
+
+ ASSERT_EQ(constant.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(constant.opcode(), moco::TFOpcode::Const);
+
+ ASSERT_EQ(constant.dtype(), loco::DataType::Unknown);
+ ASSERT_EQ(constant.rank(), 0);
+
+ constant.dtype(loco::DataType::S8);
+ ASSERT_EQ(constant.dtype(), loco::DataType::S8);
+
+ constant.rank(1);
+ ASSERT_EQ(constant.rank(), 1);
+
+ constant.dim(0) = 3;
+ ASSERT_TRUE(constant.dim(0).known());
+ ASSERT_EQ(constant.dim(0), 3);
+ constant.size<loco::DataType::S8>(3);
+ ASSERT_EQ(constant.size<loco::DataType::S8>(), 3);
+
+ constant.at<loco::DataType::S8>(0) = -1;
+ constant.at<loco::DataType::S8>(1) = 1;
+ constant.at<loco::DataType::S8>(2) = 0;
+
+ ASSERT_EQ(constant.at<loco::DataType::S8>(0), -1);
+ ASSERT_EQ(constant.at<loco::DataType::S8>(1), 1);
+ ASSERT_EQ(constant.at<loco::DataType::S8>(2), 0);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFConv2D.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFConv2D.test.cpp
new file mode 100644
index 000000000..3e3453db0
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFConv2D.test.cpp
@@ -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.
+ */
+
+#include "moco/IR/Nodes/TFConv2D.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFConv2DTest, constructor)
+{
+ moco::TFConv2D conv2d_node;
+
+ ASSERT_EQ(conv2d_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(conv2d_node.opcode(), moco::TFOpcode::Conv2D);
+
+ ASSERT_EQ(conv2d_node.input(), nullptr);
+ ASSERT_EQ(conv2d_node.filter(), nullptr);
+ ASSERT_EQ(conv2d_node.padding(), "");
+ ASSERT_EQ(conv2d_node.data_layout(), "");
+ ASSERT_EQ(conv2d_node.strides().size(), 0);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFConv2DBackpropInput.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFConv2DBackpropInput.test.cpp
new file mode 100644
index 000000000..f7ad4ce67
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFConv2DBackpropInput.test.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFConv2DBackpropInput.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFConv2DBackpropInputTest, constructor)
+{
+ moco::TFConv2DBackpropInput conv2dbi_node;
+
+ ASSERT_EQ(conv2dbi_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(conv2dbi_node.opcode(), moco::TFOpcode::Conv2DBackpropInput);
+
+ ASSERT_EQ(conv2dbi_node.input_sizes(), nullptr);
+ ASSERT_EQ(conv2dbi_node.filter(), nullptr);
+ ASSERT_EQ(conv2dbi_node.out_backprop(), nullptr);
+ ASSERT_EQ(conv2dbi_node.padding(), "");
+ ASSERT_EQ(conv2dbi_node.data_layout(), "");
+ ASSERT_EQ(conv2dbi_node.strides().size(), 0);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFDepthwiseConv2dNative.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFDepthwiseConv2dNative.test.cpp
new file mode 100644
index 000000000..2562997c2
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFDepthwiseConv2dNative.test.cpp
@@ -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.
+ */
+
+#include "moco/IR/Nodes/TFDepthwiseConv2dNative.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFDepthwiseConv2dNativeTest, constructor)
+{
+ moco::TFDepthwiseConv2dNative depthwiseConv2dnative_node;
+
+ ASSERT_EQ(depthwiseConv2dnative_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(depthwiseConv2dnative_node.opcode(), moco::TFOpcode::DepthwiseConv2dNative);
+
+ ASSERT_EQ(depthwiseConv2dnative_node.input(), nullptr);
+ ASSERT_EQ(depthwiseConv2dnative_node.filter(), nullptr);
+ ASSERT_EQ(depthwiseConv2dnative_node.padding(), "");
+ ASSERT_EQ(depthwiseConv2dnative_node.data_layout(), "");
+ ASSERT_EQ(depthwiseConv2dnative_node.strides().size(), 0);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFFakeQuantWithMinMaxVars.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFFakeQuantWithMinMaxVars.test.cpp
new file mode 100644
index 000000000..be8fc3a70
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFFakeQuantWithMinMaxVars.test.cpp
@@ -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.
+ */
+
+#include "moco/IR/Nodes/TFFakeQuantWithMinMaxVars.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFFakeQuantWithMinMaxVarsTest, constructor)
+{
+ moco::TFFakeQuantWithMinMaxVars fakequant_node;
+
+ ASSERT_EQ(fakequant_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(fakequant_node.opcode(), moco::TFOpcode::FakeQuantWithMinMaxVars);
+
+ ASSERT_EQ(fakequant_node.inputs(), nullptr);
+ ASSERT_EQ(fakequant_node.min(), nullptr);
+ ASSERT_EQ(fakequant_node.max(), nullptr);
+ ASSERT_EQ(fakequant_node.num_bits(), 8);
+ ASSERT_EQ(fakequant_node.narrow_range(), false);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFFusedBatchNorm.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFFusedBatchNorm.test.cpp
new file mode 100644
index 000000000..265f8f9a4
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFFusedBatchNorm.test.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFFusedBatchNorm.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFFusedBatchNormTest, constructor)
+{
+ moco::TFFusedBatchNorm fbn_node;
+
+ ASSERT_EQ(fbn_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(fbn_node.opcode(), moco::TFOpcode::FusedBatchNorm);
+
+ ASSERT_EQ(fbn_node.x(), nullptr);
+ ASSERT_EQ(fbn_node.scale(), nullptr);
+ ASSERT_EQ(fbn_node.offset(), nullptr);
+ ASSERT_EQ(fbn_node.mean(), nullptr);
+ ASSERT_EQ(fbn_node.variance(), nullptr);
+ ASSERT_NE(fbn_node.epsilon(), 0.0f);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFIdentity.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFIdentity.test.cpp
new file mode 100644
index 000000000..deb17d502
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFIdentity.test.cpp
@@ -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 "moco/IR/Nodes/TFIdentity.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFIdentituTest, constructor)
+{
+ moco::TFIdentity identity_node;
+
+ ASSERT_EQ(identity_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(identity_node.opcode(), moco::TFOpcode::Identity);
+
+ ASSERT_EQ(identity_node.input(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFMaxPool.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFMaxPool.test.cpp
new file mode 100644
index 000000000..482ad889d
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFMaxPool.test.cpp
@@ -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.
+ */
+
+#include "moco/IR/Nodes/TFMaxPool.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFMaxPoolTest, constructor)
+{
+ moco::TFMaxPool maxpool;
+
+ ASSERT_EQ(maxpool.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(maxpool.opcode(), moco::TFOpcode::MaxPool);
+
+ ASSERT_EQ(maxpool.input(), nullptr);
+ ASSERT_EQ(maxpool.data_layout(), "");
+ ASSERT_EQ(maxpool.padding(), "");
+ ASSERT_EQ(maxpool.ksize(), std::vector<int64_t>({}));
+ ASSERT_EQ(maxpool.strides(), std::vector<int64_t>({}));
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFMaximum.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFMaximum.test.cpp
new file mode 100644
index 000000000..568bd7038
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFMaximum.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFMaximum.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFMaximumTest, constructor)
+{
+ moco::TFMaximum max_node;
+
+ ASSERT_EQ(max_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(max_node.opcode(), moco::TFOpcode::Maximum);
+
+ ASSERT_EQ(max_node.x(), nullptr);
+ ASSERT_EQ(max_node.y(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFMean.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFMean.test.cpp
new file mode 100644
index 000000000..126b31783
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFMean.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFMean.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFMeanTest, constructor)
+{
+ moco::TFMean mean_node;
+
+ ASSERT_EQ(mean_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(mean_node.opcode(), moco::TFOpcode::Mean);
+
+ ASSERT_EQ(mean_node.input(), nullptr);
+ ASSERT_EQ(mean_node.reduction_indices(), nullptr);
+ ASSERT_EQ(mean_node.keep_dims(), false);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFMul.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFMul.test.cpp
new file mode 100644
index 000000000..a4a1ecfd7
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFMul.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFMul.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFMulTest, constructor)
+{
+ moco::TFMul mul_node;
+
+ ASSERT_EQ(mul_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(mul_node.opcode(), moco::TFOpcode::Mul);
+
+ ASSERT_EQ(mul_node.x(), nullptr);
+ ASSERT_EQ(mul_node.y(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFPack.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFPack.test.cpp
new file mode 100644
index 000000000..a62b39f3d
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFPack.test.cpp
@@ -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.
+ */
+
+#include "moco/IR/Nodes/TFPack.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFPackTest, constructor)
+{
+ moco::TFPack pack_node(3); // num of values
+
+ ASSERT_EQ(pack_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(pack_node.opcode(), moco::TFOpcode::Pack);
+
+ ASSERT_EQ(pack_node.N(), 3);
+ ASSERT_EQ(pack_node.values(0), nullptr);
+ ASSERT_EQ(pack_node.values(1), nullptr);
+ ASSERT_EQ(pack_node.values(2), nullptr);
+ ASSERT_EQ(pack_node.axis(), 0);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFPad.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFPad.test.cpp
new file mode 100644
index 000000000..f3f3dcc8c
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFPad.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFPad.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFPadTest, constructor)
+{
+ moco::TFPad pad;
+
+ ASSERT_EQ(pad.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(pad.opcode(), moco::TFOpcode::Pad);
+
+ ASSERT_EQ(pad.input(), nullptr);
+ ASSERT_EQ(pad.paddings(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFPlaceholder.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFPlaceholder.test.cpp
new file mode 100644
index 000000000..e082f0c3e
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFPlaceholder.test.cpp
@@ -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 "moco/IR/Nodes/TFPlaceholder.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFPlaceholderTest, constructor)
+{
+ moco::TFPlaceholder placeholder;
+
+ ASSERT_EQ(placeholder.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(placeholder.opcode(), moco::TFOpcode::Placeholder);
+
+ ASSERT_EQ(placeholder.dtype(), loco::DataType::Unknown);
+ ASSERT_EQ(placeholder.rank(), 0);
+
+ placeholder.dtype(loco::DataType::FLOAT32);
+ ASSERT_EQ(placeholder.dtype(), loco::DataType::FLOAT32);
+
+ placeholder.rank(2);
+ ASSERT_EQ(placeholder.rank(), 2);
+
+ placeholder.dim(0) = 2;
+ placeholder.dim(1) = 3;
+
+ ASSERT_TRUE(placeholder.dim(0).known());
+ ASSERT_TRUE(placeholder.dim(1).known());
+
+ ASSERT_EQ(placeholder.dim(0), 2);
+ ASSERT_EQ(placeholder.dim(1), 3);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFRealDiv.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFRealDiv.test.cpp
new file mode 100644
index 000000000..bfb8154a6
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFRealDiv.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFRealDiv.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFRealDivTest, constructor)
+{
+ moco::TFRealDiv div_node;
+
+ ASSERT_EQ(div_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(div_node.opcode(), moco::TFOpcode::RealDiv);
+
+ ASSERT_EQ(div_node.x(), nullptr);
+ ASSERT_EQ(div_node.y(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFRelu.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFRelu.test.cpp
new file mode 100644
index 000000000..650e2550d
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFRelu.test.cpp
@@ -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 "moco/IR/Nodes/TFRelu.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFReluTest, constructor)
+{
+ moco::TFRelu relu_node;
+
+ ASSERT_EQ(relu_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(relu_node.opcode(), moco::TFOpcode::Relu);
+
+ ASSERT_EQ(relu_node.features(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFRelu6.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFRelu6.test.cpp
new file mode 100644
index 000000000..9cce83df3
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFRelu6.test.cpp
@@ -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 "moco/IR/Nodes/TFRelu6.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFRelu6Test, constructor)
+{
+ moco::TFRelu6 relu6_node;
+
+ ASSERT_EQ(relu6_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(relu6_node.opcode(), moco::TFOpcode::Relu6);
+
+ ASSERT_EQ(relu6_node.features(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFReshape.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFReshape.test.cpp
new file mode 100644
index 000000000..514c691e9
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFReshape.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFReshape.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFReshapeTest, constructor)
+{
+ moco::TFReshape reshape_node;
+
+ ASSERT_EQ(reshape_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(reshape_node.opcode(), moco::TFOpcode::Reshape);
+
+ ASSERT_EQ(reshape_node.tensor(), nullptr);
+ ASSERT_EQ(reshape_node.shape(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFRsqrt.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFRsqrt.test.cpp
new file mode 100644
index 000000000..e94336dfe
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFRsqrt.test.cpp
@@ -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 "moco/IR/Nodes//TFRsqrt.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFRsqrtTest, constructor)
+{
+ moco::TFRsqrt rsqrt_node;
+
+ ASSERT_EQ(rsqrt_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(rsqrt_node.opcode(), moco::TFOpcode::Rsqrt);
+
+ ASSERT_EQ(rsqrt_node.x(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFShape.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFShape.test.cpp
new file mode 100644
index 000000000..28110d790
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFShape.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes//TFShape.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFShapeTest, constructor)
+{
+ moco::TFShape shape_node;
+
+ ASSERT_EQ(shape_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(shape_node.opcode(), moco::TFOpcode::Shape);
+
+ ASSERT_EQ(shape_node.input(), nullptr);
+ ASSERT_EQ(shape_node.dtype(), loco::DataType::Unknown);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFSoftmax.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFSoftmax.test.cpp
new file mode 100644
index 000000000..67449feac
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFSoftmax.test.cpp
@@ -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 "moco/IR/Nodes/TFSoftmax.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFSoftmaxTest, constructor)
+{
+ moco::TFSoftmax softmax_node;
+
+ ASSERT_EQ(softmax_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(softmax_node.opcode(), moco::TFOpcode::Softmax);
+
+ ASSERT_EQ(softmax_node.logits(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFSqrt.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFSqrt.test.cpp
new file mode 100644
index 000000000..942769f6c
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFSqrt.test.cpp
@@ -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 "moco/IR/Nodes/TFSqrt.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFSqrtTest, constructor)
+{
+ moco::TFSqrt sqrt_node;
+
+ ASSERT_EQ(sqrt_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(sqrt_node.opcode(), moco::TFOpcode::Sqrt);
+
+ ASSERT_EQ(sqrt_node.x(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFSquaredDifference.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFSquaredDifference.test.cpp
new file mode 100644
index 000000000..c3ece9b70
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFSquaredDifference.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFSquaredDifference.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFSquaredDifferenceTest, constructor)
+{
+ moco::TFSquaredDifference sd_node;
+
+ ASSERT_EQ(sd_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(sd_node.opcode(), moco::TFOpcode::SquaredDifference);
+
+ ASSERT_EQ(sd_node.x(), nullptr);
+ ASSERT_EQ(sd_node.y(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFSqueeze.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFSqueeze.test.cpp
new file mode 100644
index 000000000..034ca70b2
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFSqueeze.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFSqueeze.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFSqueezeTest, constructor)
+{
+ moco::TFSqueeze squeeze_node;
+
+ ASSERT_EQ(squeeze_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(squeeze_node.opcode(), moco::TFOpcode::Squeeze);
+
+ ASSERT_EQ(squeeze_node.input(), nullptr);
+ ASSERT_EQ(squeeze_node.squeeze_dims().size(), 0);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFStopGradient.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFStopGradient.test.cpp
new file mode 100644
index 000000000..054ccda41
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFStopGradient.test.cpp
@@ -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 "moco/IR/Nodes/TFStopGradient.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFStopGradientTest, constructor)
+{
+ moco::TFStopGradient node;
+
+ ASSERT_EQ(node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(node.opcode(), moco::TFOpcode::StopGradient);
+
+ ASSERT_EQ(node.input(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFStridedSlice.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFStridedSlice.test.cpp
new file mode 100644
index 000000000..9e7e45543
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFStridedSlice.test.cpp
@@ -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 "moco/IR/Nodes/TFStridedSlice.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFStridedSliceTest, constructor)
+{
+ moco::TFStridedSlice node;
+
+ ASSERT_EQ(node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(node.opcode(), moco::TFOpcode::StridedSlice);
+
+ ASSERT_EQ(node.input(), nullptr);
+ ASSERT_EQ(node.begin(), nullptr);
+ ASSERT_EQ(node.end(), nullptr);
+ ASSERT_EQ(node.strides(), nullptr);
+ ASSERT_EQ(node.begin_mask(), 0);
+ ASSERT_EQ(node.end_mask(), 0);
+ ASSERT_EQ(node.ellipsis_mask(), 0);
+ ASSERT_EQ(node.new_axis_mask(), 0);
+ ASSERT_EQ(node.shrink_axis_mask(), 0);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFSub.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFSub.test.cpp
new file mode 100644
index 000000000..4b80713bd
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFSub.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFSub.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFSubTest, constructor)
+{
+ moco::TFSub sub_node;
+
+ ASSERT_EQ(sub_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(sub_node.opcode(), moco::TFOpcode::Sub);
+
+ ASSERT_EQ(sub_node.x(), nullptr);
+ ASSERT_EQ(sub_node.y(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/Nodes/TFTanh.test.cpp b/compiler/moco/lang/src/IR/Nodes/TFTanh.test.cpp
new file mode 100644
index 000000000..38458a694
--- /dev/null
+++ b/compiler/moco/lang/src/IR/Nodes/TFTanh.test.cpp
@@ -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 "moco/IR/Nodes/TFTanh.h"
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFTanhTest, constructor)
+{
+ moco::TFTanh tanh_node;
+
+ ASSERT_EQ(tanh_node.dialect(), moco::TFDialect::get());
+ ASSERT_EQ(tanh_node.opcode(), moco::TFOpcode::Tanh);
+
+ ASSERT_EQ(tanh_node.x(), nullptr);
+}
diff --git a/compiler/moco/lang/src/IR/TFDialect.cpp b/compiler/moco/lang/src/IR/TFDialect.cpp
new file mode 100644
index 000000000..35bbcc2c9
--- /dev/null
+++ b/compiler/moco/lang/src/IR/TFDialect.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/TFDialect.h"
+#include "moco/IR/TFNode.h"
+
+#include <loco/IR/Graph.h>
+#include <loco/IR/GraphInputIndex.h>
+#include <loco/IR/GraphOutputIndex.h>
+
+#include <stdex/Memory.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+
+struct GiiQueryServiceImpl final : public loco::GraphInputIndexQueryService
+{
+ bool associated(const loco::Node *node) const final
+ {
+ if (auto tfplaceholder = dynamic_cast<const moco::TFPlaceholder *>(node))
+ {
+ return moco::indexed(tfplaceholder);
+ }
+ return false;
+ }
+
+ loco::GraphOutputIndex index(const loco::Node *node) const final
+ {
+ assert(associated(node));
+ auto tfplaceholder = dynamic_cast<const moco::TFPlaceholder *>(node);
+ assert(tfplaceholder != nullptr);
+ return moco::index(tfplaceholder);
+ }
+};
+
+struct GoiQueryServiceImpl final : public loco::GraphOutputIndexQueryService
+{
+ bool associated(const loco::Node *node) const final
+ {
+ if (auto tfpush = dynamic_cast<const moco::TFPush *>(node))
+ {
+ return tfpush->indexed();
+ }
+ return false;
+ }
+
+ loco::GraphOutputIndex index(const loco::Node *node) const final
+ {
+ assert(associated(node));
+ if (auto tfpush = dynamic_cast<const moco::TFPush *>(node))
+ {
+ return tfpush->index();
+ }
+ throw std::invalid_argument("node");
+ }
+};
+
+} // namespace
+
+namespace moco
+{
+
+TFDialect::TFDialect()
+{
+ service<loco::GraphInputIndexQueryService>(stdex::make_unique<GiiQueryServiceImpl>());
+ service<loco::GraphOutputIndexQueryService>(stdex::make_unique<GoiQueryServiceImpl>());
+}
+
+loco::Dialect *TFDialect::get(void)
+{
+ static TFDialect d;
+ return &d;
+}
+
+} // namespace moco
diff --git a/compiler/moco/lang/src/IR/TFDialect.test.cpp b/compiler/moco/lang/src/IR/TFDialect.test.cpp
new file mode 100644
index 000000000..3c8b1a16b
--- /dev/null
+++ b/compiler/moco/lang/src/IR/TFDialect.test.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/TFDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(TFDialectTest, get)
+{
+ auto d = moco::TFDialect::get();
+
+ // get() SHOULD return a valid(non-null) pointer
+ ASSERT_NE(d, nullptr);
+ // The return value SHOULD be stable across multiple invocations
+ ASSERT_EQ(d, moco::TFDialect::get());
+}
diff --git a/compiler/moco/lang/src/IR/TFNode.cpp b/compiler/moco/lang/src/IR/TFNode.cpp
new file mode 100644
index 000000000..ab9356196
--- /dev/null
+++ b/compiler/moco/lang/src/IR/TFNode.cpp
@@ -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 "moco/IR/TFNode.h"
+#include "moco/IR/TFDialect.h"
+
+#include <cassert>
+
+namespace moco
+{
+
+const loco::Dialect *TFNode::dialect(void) const { return TFDialect::get(); }
+
+} // namespace moco
+
+// TODO move this to appropriate place
+#include <stdex/Memory.h>
+
+namespace moco
+{
+
+struct GraphInputIndexAnnotation : public loco::NodeAnnotation
+{
+public:
+ GraphInputIndexAnnotation(const loco::GraphInputIndex &index) : _index{index}
+ {
+ // DO NOTHING
+ }
+
+public:
+ const loco::GraphInputIndex &index(void) const { return _index; }
+
+private:
+ loco::GraphInputIndex _index;
+};
+
+bool indexed(const TFPlaceholder *node)
+{
+ return (node->annot<GraphInputIndexAnnotation>() != nullptr);
+}
+
+loco::GraphInputIndex index(const TFPlaceholder *node)
+{
+ assert(indexed(node));
+ return node->annot<GraphInputIndexAnnotation>()->index();
+}
+
+void index(TFPlaceholder *node, const loco::GraphInputIndex index)
+{
+ node->annot(stdex::make_unique<GraphInputIndexAnnotation>(index));
+}
+
+loco::TensorShape tensor_shape(const TFPlaceholder *node)
+{
+ assert(node != nullptr);
+
+ loco::TensorShape shape;
+
+ uint32_t rank = node->rank();
+ shape.rank(rank);
+ for (uint32_t index = 0; index < rank; ++index)
+ {
+ if (node->dim(index).known())
+ shape.dim(index) = node->dim(index).value();
+ else
+ shape.dim(index).unset();
+ }
+
+ return shape;
+}
+
+TFPlaceholder *placeholder_node(loco::Graph *g, const loco::GraphInputIndex &idx)
+{
+ for (uint32_t n = 0; n < g->nodes()->size(); ++n)
+ {
+ if (auto tfplaceholder = dynamic_cast<TFPlaceholder *>(g->nodes()->at(n)))
+ {
+ if (indexed(tfplaceholder) && index(tfplaceholder) == idx)
+ {
+ return tfplaceholder;
+ }
+ }
+ }
+ return nullptr;
+}
+
+} // namespace moco
+
+namespace moco
+{
+
+/**
+ * TFPush
+ */
+
+void TFPush::index(const loco::GraphOutputIndex &index)
+{
+ // Push internally stores "GraphOutputIndex" as int64_t
+ _index = static_cast<int64_t>(index);
+}
+
+loco::GraphOutputIndex TFPush::index(void) const
+{
+ assert(_index >= std::numeric_limits<loco::GraphOutputIndex>::min());
+ assert(_index <= std::numeric_limits<loco::GraphOutputIndex>::max());
+ return static_cast<loco::GraphOutputIndex>(_index);
+}
+
+TFPush *push_node(loco::Graph *g, const loco::GraphOutputIndex &index)
+{
+ for (uint32_t n = 0; n < g->nodes()->size(); ++n)
+ {
+ if (auto tfpush = dynamic_cast<TFPush *>(g->nodes()->at(n)))
+ {
+ if (tfpush->indexed() && tfpush->index() == index)
+ {
+ return tfpush;
+ }
+ }
+ }
+ return nullptr;
+}
+
+} // namespace moco
diff --git a/compiler/moco/lang/src/IR/TFNode.test.cpp b/compiler/moco/lang/src/IR/TFNode.test.cpp
new file mode 100644
index 000000000..4df1211db
--- /dev/null
+++ b/compiler/moco/lang/src/IR/TFNode.test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/IR/Nodes/TFPlaceholder.h"
+
+#include <loco.h>
+
+#include <gtest/gtest.h>
+
+TEST(TFNodeTest_Placeholder, index)
+{
+ loco::Graph graph;
+
+ auto test_node = graph.nodes()->create<moco::TFPlaceholder>();
+
+ loco::GraphInputIndex index_set{100};
+ moco::index(test_node, index_set);
+
+ auto index_get = moco::index(test_node);
+ ASSERT_EQ(index_get, index_set);
+}
+
+TEST(TFNodeTest_Placeholder, name)
+{
+ loco::Graph graph;
+
+ auto test_node = graph.nodes()->create<moco::TFPlaceholder>();
+
+ test_node->name("PlaceholderName");
+ ASSERT_EQ(test_node->name(), "PlaceholderName");
+}
diff --git a/compiler/moco/lang/src/IR/VariadicArityNode.test.cpp b/compiler/moco/lang/src/IR/VariadicArityNode.test.cpp
new file mode 100644
index 000000000..57361af98
--- /dev/null
+++ b/compiler/moco/lang/src/IR/VariadicArityNode.test.cpp
@@ -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 "moco/IR/VariadicArityNode.h"
+
+#include <loco/IR/Nodes.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+using namespace moco;
+
+class ArbitraryInputNode : public VariadicArityNode<loco::Node>
+{
+public:
+ ArbitraryInputNode(uint32_t arity) : VariadicArityNode<loco::Node>(arity) {}
+
+ void input(uint32_t idx, loco::Node *node) { at(idx)->node(node); }
+ loco::Node *input(uint32_t idx) const { return at(idx)->node(); }
+
+ const loco::Dialect *dialect(void) const { return nullptr; } // this won't be called for testing
+ uint32_t opnum(void) const { return -1; } // this won't be called for testing
+};
+
+} // namespace
+
+TEST(CustomOpTest, VariadicArityNode_arity_n)
+{
+ loco::ConstGen cg0, cg1, cg2;
+
+ ArbitraryInputNode a_node(3);
+ a_node.input(0, &cg0);
+ a_node.input(1, &cg1);
+ a_node.input(2, &cg2);
+
+ ASSERT_EQ(a_node.arity(), 3);
+ ASSERT_EQ(a_node.input(0), &cg0);
+ ASSERT_EQ(a_node.input(1), &cg1);
+ ASSERT_EQ(a_node.input(2), &cg2);
+}
diff --git a/compiler/moco/pass/CMakeLists.txt b/compiler/moco/pass/CMakeLists.txt
new file mode 100644
index 000000000..1eba86283
--- /dev/null
+++ b/compiler/moco/pass/CMakeLists.txt
@@ -0,0 +1,26 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(moco_pass SHARED ${SOURCES})
+target_include_directories(moco_pass PRIVATE src)
+target_include_directories(moco_pass PUBLIC include)
+target_link_libraries(moco_pass PUBLIC loco)
+target_link_libraries(moco_pass PUBLIC logo_core)
+target_link_libraries(moco_pass PUBLIC moco_lang)
+target_link_libraries(moco_pass PRIVATE moco_support)
+target_link_libraries(moco_pass PRIVATE stdex)
+target_link_libraries(moco_pass PRIVATE oops)
+install(TARGETS moco_pass DESTINATION lib)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
+
+GTest_AddTest(moco_pass_test ${TESTS})
+target_include_directories(moco_pass_test PRIVATE src)
+target_link_libraries(moco_pass_test moco_pass)
+target_link_libraries(moco_pass_test moco_support)
+target_link_libraries(moco_pass_test stdex)
diff --git a/compiler/moco/pass/README.md b/compiler/moco/pass/README.md
new file mode 100644
index 000000000..51921b8db
--- /dev/null
+++ b/compiler/moco/pass/README.md
@@ -0,0 +1,3 @@
+# pass
+
+_pass_ provides _moco_ General Graph Passes for Transformation and Optimization
diff --git a/compiler/moco/pass/include/moco/Pass/Passes.h b/compiler/moco/pass/include/moco/Pass/Passes.h
new file mode 100644
index 000000000..210f0acfc
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_PASS_PASSES_H__
+#define __MOCO_PASS_PASSES_H__
+
+#include "Passes/ConstantFoldAdd.h"
+#include "Passes/ConstantFoldMul.h"
+#include "Passes/ConstantFoldPack.h"
+#include "Passes/ConstantFoldStridedSlice.h"
+#include "Passes/FuseBinaryIntoPreceding.h"
+#include "Passes/RemoveTFIdentityNode.h"
+#include "Passes/ResolveConstantShape.h"
+#include "Passes/ResolveFusedBatchNorm.h"
+#include "Passes/ResolveReshapeWildcardDim.h"
+#include "Passes/ResolveSquaredDifference.h"
+#include "Passes/SqueezeReduceNode.h"
+
+#endif // __MOCO_PASS_PASSES_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldAdd.h b/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldAdd.h
new file mode 100644
index 000000000..ed58d5ee3
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldAdd.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 __MOCO_PASS_CONSTANTFOLD_ADD_H__
+#define __MOCO_PASS_CONSTANTFOLD_ADD_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Constant folder for Const + Add -> Const
+ */
+class ConstantFoldAdd : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "ConstantFoldAdd"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_CONSTANTFOLD_ADD_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldMul.h b/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldMul.h
new file mode 100644
index 000000000..5528b8612
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldMul.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 __MOCO_PASS_CONSTANTFOLD_MUL_H__
+#define __MOCO_PASS_CONSTANTFOLD_MUL_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Constant folder for Const + Mul -> Const
+*/
+class ConstantFoldMul : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "ConstantFoldMul"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_CONSTANTFOLD_MUL_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldPack.h b/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldPack.h
new file mode 100644
index 000000000..fc6bc0ace
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldPack.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_PASS_CONSTANTFOLD_PACK_H__
+#define __MOCO_PASS_CONSTANTFOLD_PACK_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+// TODO Provide like ConstantFoldPass<TFPack> for ConstantFold extension
+
+/**
+ * @brief Constant folder for Const + Pack -> Const
+*/
+class ConstantFoldPack : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "ConstantFoldPack"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_CONSTANTFOLD_PACK_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldStridedSlice.h b/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldStridedSlice.h
new file mode 100644
index 000000000..1e3492c2c
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/ConstantFoldStridedSlice.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_PASS_CONSTANTFOLD_STRIDEDSLICE_H__
+#define __MOCO_PASS_CONSTANTFOLD_STRIDEDSLICE_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Constant folder for Const + StridedSlice -> Const
+*/
+class ConstantFoldStridedSlice : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "ConstantFoldStridedSlice"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_CONSTANTFOLD_STRIDEDSLICE_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/FuseBinaryIntoPreceding.h b/compiler/moco/pass/include/moco/Pass/Passes/FuseBinaryIntoPreceding.h
new file mode 100644
index 000000000..24e3567c0
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/FuseBinaryIntoPreceding.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 __MOCO_PASS_FUSE_BINARY_INTO_PRECEDING_H__
+#define __MOCO_PASS_FUSE_BINARY_INTO_PRECEDING_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Fuse TFAdd, TFMul to preceding TFConv2D or TFDepthWiseConv2D
+*/
+class FuseBinaryIntoPreceding : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "FuseBinaryIntoPreceding"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_FUSE_BINARY_INTO_PRECEDING_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/RemoveTFIdentityNode.h b/compiler/moco/pass/include/moco/Pass/Passes/RemoveTFIdentityNode.h
new file mode 100644
index 000000000..388249b63
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/RemoveTFIdentityNode.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 __MOCO_PASS_REMOVE_TFIDENTITY_NODE_H__
+#define __MOCO_PASS_REMOVE_TFIDENTITY_NODE_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Use the input of "TFIdentity" node instead
+ *
+ * BEFORE:
+ * [X] -> [TFIdentity] -> [Y]
+ *
+ * AFTER:
+ * [X] -> [Y]
+ * [TFIdentity]
+ *
+ * NOTE This transform does not remove "TFIdentity" node
+ * This transform is identical to RemoveForwardNode
+ */
+struct RemoveTFIdentityNode final : public logo::Pass
+{
+ const char *name(void) const final { return "RemoveTFIdentityNode"; }
+
+ bool run(loco::Graph *g) final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_REMOVE_TFIDENTITY_NODE_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/ResolveConstantShape.h b/compiler/moco/pass/include/moco/Pass/Passes/ResolveConstantShape.h
new file mode 100644
index 000000000..16046a052
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/ResolveConstantShape.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 __MOCO_PASS_RESOLVE_CONSTANT_SHAPE_H__
+#define __MOCO_PASS_RESOLVE_CONSTANT_SHAPE_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Replace fully determined TFShape node into TFConst
+ */
+class ResolveConstantShape : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "ResolveConstantShape"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_RESOLVE_CONSTANT_SHAPE_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/ResolveFusedBatchNorm.h b/compiler/moco/pass/include/moco/Pass/Passes/ResolveFusedBatchNorm.h
new file mode 100644
index 000000000..ce5ea0bb0
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/ResolveFusedBatchNorm.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 __MOCO_PASS_RESOLVE_FUSEDBATCHNORM_H__
+#define __MOCO_PASS_RESOLVE_FUSEDBATCHNORM_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Trasform TFFusedBatchNorm into TFAdd + TFRsqrt + TFMul + TFBatchNorm
+*/
+class ResolveFusedBatchNorm : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "ResolveFusedBatchNorm"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_RESOLVE_FUSEDBATCHNORM_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/ResolveReshapeWildcardDim.h b/compiler/moco/pass/include/moco/Pass/Passes/ResolveReshapeWildcardDim.h
new file mode 100644
index 000000000..137c97379
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/ResolveReshapeWildcardDim.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 __MOCO_PASS_RESOLVE_RESHAPE_WILDCARD_DIM_H__
+#define __MOCO_PASS_RESOLVE_RESHAPE_WILDCARD_DIM_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Determine wildcard dimension (denoted as -1) of Reshape's shape input
+ * if possible
+ */
+class ResolveReshapeWildcardDim : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "ResolveReshapeWildcardDim"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_RESOLVE_RESHAPE_WILDCARD_DIM_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/ResolveSquaredDifference.h b/compiler/moco/pass/include/moco/Pass/Passes/ResolveSquaredDifference.h
new file mode 100644
index 000000000..1aa78655e
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/ResolveSquaredDifference.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 __MOCO_PASS_RESOLVE_SQUARED_DIFFERENCE_H__
+#define __MOCO_PASS_RESOLVE_SQUARED_DIFFERENCE_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief Decompose TFSquaredDifference to TFSub, TFMul
+ */
+class ResolveSquaredDifference : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "ResolveSquaredDifference"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_RESOLVE_SQUARED_DIFFERENCE_H__
diff --git a/compiler/moco/pass/include/moco/Pass/Passes/SqueezeReduceNode.h b/compiler/moco/pass/include/moco/Pass/Passes/SqueezeReduceNode.h
new file mode 100644
index 000000000..d4a3e65c6
--- /dev/null
+++ b/compiler/moco/pass/include/moco/Pass/Passes/SqueezeReduceNode.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 __MOCO_PASS_SQUEEZE_REDUCE_NODE_H__
+#define __MOCO_PASS_SQUEEZE_REDUCE_NODE_H__
+
+#include <logo/Pass.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief If ReduceTypeOP don't keep dimensions, replace the ReduceTypeOp
+ * as new one to keep dimensions and insert TFSqueeze
+ */
+class SqueezeReduceNode : public logo::Pass
+{
+public:
+ const char *name(void) const final { return "SqueezeReduceNode"; }
+
+public:
+ bool run(loco::Graph *graph) override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_PASS_SQUEEZE_REDUCE_NODE_H__
diff --git a/compiler/moco/pass/src/ConstantFoldAdd.test.cpp b/compiler/moco/pass/src/ConstantFoldAdd.test.cpp
new file mode 100644
index 000000000..bc9489fbd
--- /dev/null
+++ b/compiler/moco/pass/src/ConstantFoldAdd.test.cpp
@@ -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 "moco/Pass/Passes/ConstantFoldAdd.h"
+#include "TestHelper.h"
+
+#include <moco/IR/TFNodes.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+moco::TFConst *const_vector_init(loco::Graph *graph, std::vector<int32_t> values)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+ auto dim = values.size();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(1);
+ const_node->dim(0).set(dim);
+
+ const_node->size<loco::DataType::S32>(dim);
+ for (int32_t i = 0; i < dim; ++i)
+ const_node->at<loco::DataType::S32>(i) = values[i];
+
+ return const_node;
+}
+
+} // namespace
+
+TEST(ConstantFoldAdd, basic_vector)
+{
+ loco::Graph graph;
+
+ auto add_node = graph.nodes()->create<moco::TFAdd>();
+ {
+ auto const_from_ss = const_vector_init(&graph, {1, 3, 5});
+ add_node->x(const_from_ss);
+
+ auto const_y = const_vector_init(&graph, {2});
+ add_node->y(const_y);
+ }
+ setup_output_node(&graph, add_node);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldAdd>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto ssnode = find_first_node_bytype<moco::TFAdd>(&graph);
+ ASSERT_EQ(ssnode, nullptr);
+
+ auto ssconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(ssconst, nullptr);
+ ASSERT_EQ(ssconst->size<loco::DataType::S32>(), 3);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(0), 3);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(1), 5);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(2), 7);
+}
+
+TEST(ConstantFoldAdd, basic_refinedet_1)
+{
+ loco::Graph graph;
+
+ auto add_node = graph.nodes()->create<moco::TFAdd>();
+ {
+ auto const_from_ss = const_vector_init(&graph, {10});
+ add_node->x(const_from_ss);
+
+ auto const_y = const_vector_init(&graph, {0});
+ add_node->y(const_y);
+ }
+ setup_output_node(&graph, add_node);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldAdd>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto ssnode = find_first_node_bytype<moco::TFAdd>(&graph);
+ ASSERT_EQ(ssnode, nullptr);
+
+ auto ssconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(ssconst, nullptr);
+ ASSERT_EQ(ssconst->size<loco::DataType::S32>(), 1);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(0), 10);
+}
diff --git a/compiler/moco/pass/src/ConstantFoldHelper.cpp b/compiler/moco/pass/src/ConstantFoldHelper.cpp
new file mode 100644
index 000000000..79b04863c
--- /dev/null
+++ b/compiler/moco/pass/src/ConstantFoldHelper.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConstantFoldHelper.h"
+
+#include <cassert>
+#include <sstream>
+#include <string>
+
+namespace
+{
+
+// TODO this may need to be moved to loco
+bool same_shape(const loco::TensorShape *lhs, const loco::TensorShape *rhs)
+{
+ if (lhs->rank() != rhs->rank())
+ return false;
+
+ for (uint32_t r = 0; r < lhs->rank(); r++)
+ {
+ if (lhs->dim(r).value() != rhs->dim(r).value())
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+TFConst *new_const(loco::Graph *graph, loco::TensorShape &tensor_shape, const loco::DataType &dtype)
+{
+ assert(dtype == loco::DataType::S32 || dtype == loco::DataType::FLOAT32);
+
+ auto const_node = graph->nodes()->create<TFConst>();
+ const_node->dtype(dtype);
+ const_node->rank(tensor_shape.rank());
+
+ // Calc number of elements for target node and set shape
+ uint32_t num_elements = 1;
+ for (uint32_t r = 0; r < tensor_shape.rank(); r++)
+ {
+ const_node->dim(r) = tensor_shape.dim(r);
+ assert(const_node->dim(r).known());
+ num_elements = num_elements * const_node->dim(r).value();
+ }
+ if (dtype == loco::DataType::S32)
+ const_node->size<loco::DataType::S32>(num_elements);
+ else if (dtype == loco::DataType::FLOAT32)
+ const_node->size<loco::DataType::FLOAT32>(num_elements);
+
+ // give name for this node from address to be unique
+ std::ostringstream oss;
+ oss << "Const_" << (void *)const_node;
+ const_node->name(oss.str());
+
+ return const_node;
+}
+
+} // namespace moco
+
+namespace moco
+{
+
+template <> int32_t scalar_from_const<int32_t>(const TFConst *tfconst)
+{
+ assert(tfconst->rank() == 0 || tfconst->rank() == 1);
+ assert(tfconst->dtype() == loco::DataType::S32);
+ return tfconst->at<loco::DataType::S32>(0);
+}
+
+template <> float scalar_from_const<float>(const TFConst *tfconst)
+{
+ assert(tfconst->rank() == 0 || tfconst->rank() == 1);
+ assert(tfconst->dtype() == loco::DataType::FLOAT32);
+ return tfconst->at<loco::DataType::FLOAT32>(0);
+}
+
+bool valid_shape_for_constfold_binary_op(const loco::TensorShape &lhs, const loco::TensorShape &rhs)
+{
+ // scalar
+ if (lhs.rank() == 0 || rhs.rank() == 0)
+ return true;
+
+ // same as scalar
+ if (lhs.rank() == 1 && lhs.dim(0).value() == 1)
+ return true;
+ if (rhs.rank() == 1 && rhs.dim(0).value() == 1)
+ return true;
+
+ // for elementwise binary operation
+ return ::same_shape(&lhs, &rhs);
+}
+
+} // namespace moco
+
+namespace moco
+{
+
+float BinaryFunc::apply(float, float) const
+{
+ throw std::runtime_error{"F32 is not supported yet"};
+}
+
+int32_t BinaryFunc::apply(int32_t, int32_t) const
+{
+ throw std::runtime_error{"S32 is not supported yet"};
+}
+
+} // namespace moco
+
+namespace
+{
+
+void apply_binary_s32(const moco::TFConst *lhs, int32_t rhs, moco::TFConst *output,
+ const moco::BinaryFunc &f)
+{
+ assert(lhs->dtype() == loco::DataType::S32);
+ assert(same_shape(lhs, output));
+
+ uint32_t nume = num_elements(lhs);
+ for (uint32_t e = 0; e < nume; e++)
+ {
+ output->at<loco::DataType::S32>(e) = f.apply(lhs->at<loco::DataType::S32>(e), rhs);
+ }
+}
+
+void apply_binary_f32(const moco::TFConst *lhs, float rhs, moco::TFConst *output,
+ const moco::BinaryFunc &f)
+{
+ assert(lhs->dtype() == loco::DataType::FLOAT32);
+ assert(same_shape(lhs, output));
+
+ uint32_t nume = num_elements(lhs);
+ for (uint32_t e = 0; e < nume; e++)
+ {
+ output->at<loco::DataType::FLOAT32>(e) = f.apply(lhs->at<loco::DataType::FLOAT32>(e), rhs);
+ }
+}
+
+void apply_binary_s32(const moco::TFConst *lhs, const moco::TFConst *rhs, moco::TFConst *output,
+ const moco::BinaryFunc &f)
+{
+ assert(same_shape(output, lhs));
+ assert(same_shape(output, rhs));
+ assert(output->dtype() == lhs->dtype());
+ assert(output->dtype() == rhs->dtype());
+
+ uint32_t nume = num_elements(lhs);
+ for (uint32_t e = 0; e < nume; e++)
+ {
+ output->at<loco::DataType::S32>(e) =
+ f.apply(lhs->at<loco::DataType::S32>(e), rhs->at<loco::DataType::S32>(e));
+ }
+}
+
+void apply_binary_f32(const moco::TFConst *lhs, const moco::TFConst *rhs, moco::TFConst *output,
+ const moco::BinaryFunc &f)
+{
+ assert(same_shape(output, lhs));
+ assert(same_shape(output, rhs));
+ assert(output->dtype() == lhs->dtype());
+ assert(output->dtype() == rhs->dtype());
+
+ uint32_t nume = num_elements(lhs);
+ for (uint32_t e = 0; e < nume; e++)
+ {
+ output->at<loco::DataType::FLOAT32>(e) =
+ f.apply(lhs->at<loco::DataType::FLOAT32>(e), rhs->at<loco::DataType::FLOAT32>(e));
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+template <>
+void apply_binary<int32_t>(const moco::TFConst *x_const, const moco::TFConst *y_const,
+ moco::TFConst *output_const, const moco::BinaryFunc &f)
+{
+ auto x_shape = moco::tensor_shape(x_const);
+ auto y_shape = moco::tensor_shape(y_const);
+
+ if (y_shape.rank() == 0 || y_shape.rank() == 1)
+ {
+ auto rhs = scalar_from_const<int32_t>(y_const);
+ apply_binary_s32(x_const, rhs, output_const, f);
+ }
+ else if (x_shape.rank() == 0 || x_shape.rank() == 1)
+ {
+ auto rhs = scalar_from_const<int32_t>(x_const);
+ apply_binary_s32(y_const, rhs, output_const, f);
+ }
+ else
+ {
+ apply_binary_f32(x_const, y_const, output_const, f);
+ }
+}
+
+template <>
+void apply_binary<float>(const moco::TFConst *x_const, const moco::TFConst *y_const,
+ moco::TFConst *output_const, const moco::BinaryFunc &f)
+{
+ auto x_shape = moco::tensor_shape(x_const);
+ auto y_shape = moco::tensor_shape(y_const);
+
+ if (y_shape.rank() == 0 || y_shape.rank() == 1)
+ {
+ auto rhs = scalar_from_const<float>(y_const);
+ apply_binary_f32(x_const, rhs, output_const, f);
+ }
+ else if (x_shape.rank() == 0 || x_shape.rank() == 1)
+ {
+ auto rhs = scalar_from_const<float>(x_const);
+ apply_binary_f32(y_const, rhs, output_const, f);
+ }
+ else
+ {
+ apply_binary_f32(x_const, y_const, output_const, f);
+ }
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/ConstantFoldHelper.h b/compiler/moco/pass/src/ConstantFoldHelper.h
new file mode 100644
index 000000000..393b083f2
--- /dev/null
+++ b/compiler/moco/pass/src/ConstantFoldHelper.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 __MOCO_CONSTANT_FOLD_HELPER_H__
+#define __MOCO_CONSTANT_FOLD_HELPER_H__
+
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <loco.h>
+#include <loco/IR/TensorShape.h>
+
+namespace moco
+{
+
+TFConst *new_const(loco::Graph *graph, loco::TensorShape &tensor_shape,
+ const loco::DataType &dtype);
+
+template <typename T> T scalar_from_const(const TFConst *tfconst);
+template <> int32_t scalar_from_const<int32_t>(const TFConst *tfconst);
+template <> float scalar_from_const<float>(const TFConst *tfconst);
+
+/**
+ * @note Check if it is valid to run Constant folding for binary operations
+ * as-of current implementation. That is currently we support for
+ * element-wise or one of the input is scalar.
+ * TODO Support other shapes of binary operation
+ */
+bool valid_shape_for_constfold_binary_op(const loco::TensorShape &lhs,
+ const loco::TensorShape &rhs);
+
+struct BinaryFunc
+{
+ virtual ~BinaryFunc() = default;
+
+ virtual float apply(float, float) const;
+ virtual int32_t apply(int32_t, int32_t) const;
+};
+
+template <typename T>
+void apply_binary(const moco::TFConst *x_const, const moco::TFConst *y_const,
+ moco::TFConst *output_const, const moco::BinaryFunc &f);
+template <>
+void apply_binary<int32_t>(const moco::TFConst *x_const, const moco::TFConst *y_const,
+ moco::TFConst *output_const, const moco::BinaryFunc &f);
+template <>
+void apply_binary<float>(const moco::TFConst *x_const, const moco::TFConst *y_const,
+ moco::TFConst *output_const, const moco::BinaryFunc &f);
+
+} // namespace moco
+
+#endif // __MOCO_CONSTANT_FOLD_HELPER_H__
diff --git a/compiler/moco/pass/src/ConstantFoldMul.test.cpp b/compiler/moco/pass/src/ConstantFoldMul.test.cpp
new file mode 100644
index 000000000..4e9b78fd4
--- /dev/null
+++ b/compiler/moco/pass/src/ConstantFoldMul.test.cpp
@@ -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 "moco/Pass/Passes/ConstantFoldMul.h"
+#include "TestHelper.h"
+
+#include <moco/IR/TFNodes.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+moco::TFConst *const_vector_init(loco::Graph *graph, std::vector<int32_t> values)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+ auto dim = values.size();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(1);
+ const_node->dim(0).set(dim);
+
+ const_node->size<loco::DataType::S32>(dim);
+ for (int32_t i = 0; i < dim; ++i)
+ const_node->at<loco::DataType::S32>(i) = values[i];
+
+ return const_node;
+}
+
+} // namespace
+
+TEST(ConstantFoldMul, basic_vector)
+{
+ loco::Graph graph;
+
+ auto mul_node = graph.nodes()->create<moco::TFMul>();
+ {
+ auto const_from_ss = const_vector_init(&graph, {1, 3, 5});
+ mul_node->x(const_from_ss);
+
+ auto const_y = const_vector_init(&graph, {2});
+ mul_node->y(const_y);
+ }
+ setup_output_node(&graph, mul_node);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldMul>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto ssnode = find_first_node_bytype<moco::TFMul>(&graph);
+ ASSERT_EQ(ssnode, nullptr);
+
+ auto ssconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(ssconst, nullptr);
+ ASSERT_EQ(ssconst->size<loco::DataType::S32>(), 3);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(0), 2);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(1), 6);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(2), 10);
+}
+
+TEST(ConstantFoldMul, basic_refinedet_1)
+{
+ loco::Graph graph;
+
+ auto mul_node = graph.nodes()->create<moco::TFMul>();
+ {
+ auto const_from_ss = const_vector_init(&graph, {5});
+ mul_node->x(const_from_ss);
+
+ auto const_y = const_vector_init(&graph, {2});
+ mul_node->y(const_y);
+ }
+ setup_output_node(&graph, mul_node);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldMul>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto ssnode = find_first_node_bytype<moco::TFMul>(&graph);
+ ASSERT_EQ(ssnode, nullptr);
+
+ auto ssconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(ssconst, nullptr);
+ ASSERT_EQ(ssconst->size<loco::DataType::S32>(), 1);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(0), 10);
+}
diff --git a/compiler/moco/pass/src/ConstantFoldPack.test.cpp b/compiler/moco/pass/src/ConstantFoldPack.test.cpp
new file mode 100644
index 000000000..cb6eff0c8
--- /dev/null
+++ b/compiler/moco/pass/src/ConstantFoldPack.test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Pass/Passes/ConstantFoldPack.h"
+#include "TestHelper.h"
+
+#include <moco/IR/TFNodes.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+moco::TFConst *const_vector_init(loco::Graph *graph, std::vector<int32_t> values)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+ auto dim = values.size();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(1);
+ const_node->dim(0).set(dim);
+
+ const_node->size<loco::DataType::S32>(dim);
+ for (int32_t i = 0; i < dim; ++i)
+ const_node->at<loco::DataType::S32>(i) = values[i];
+
+ return const_node;
+}
+
+} // namespace
+
+TEST(ConstantFoldPack, basic_scalar4_vector)
+{
+ loco::Graph graph;
+
+ auto pack_node = graph.nodes()->create<moco::TFPack>(4);
+ {
+ auto input_0 = const_vector_init(&graph, {1});
+ pack_node->values(0, input_0);
+
+ auto input_1 = const_vector_init(&graph, {10});
+ pack_node->values(1, input_1);
+
+ auto input_2 = const_vector_init(&graph, {10});
+ pack_node->values(2, input_2);
+
+ auto input_3 = const_vector_init(&graph, {64});
+ pack_node->values(3, input_3);
+ }
+ // add Identity node as the output Pack will be replaced
+ auto identity = graph.nodes()->create<moco::TFIdentity>();
+ identity->input(pack_node);
+ setup_output_node(&graph, identity);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldPack>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto pnode = find_first_node_bytype<moco::TFPack>(&graph);
+ ASSERT_EQ(pnode, nullptr);
+
+ auto pconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(pconst, nullptr);
+ ASSERT_EQ(pconst->rank(), 2);
+ ASSERT_EQ(pconst->size<loco::DataType::S32>(), 4);
+ ASSERT_EQ(pconst->at<loco::DataType::S32>(0), 1);
+ ASSERT_EQ(pconst->at<loco::DataType::S32>(1), 10);
+ ASSERT_EQ(pconst->at<loco::DataType::S32>(2), 10);
+ ASSERT_EQ(pconst->at<loco::DataType::S32>(3), 64);
+}
diff --git a/compiler/moco/pass/src/ConstantFoldStridedSlice.test.cpp b/compiler/moco/pass/src/ConstantFoldStridedSlice.test.cpp
new file mode 100644
index 000000000..b5bada221
--- /dev/null
+++ b/compiler/moco/pass/src/ConstantFoldStridedSlice.test.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Pass/Passes/ConstantFoldStridedSlice.h"
+#include "TestHelper.h"
+
+#include <moco/IR/TFNodes.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+moco::TFConst *const_vector_init(loco::Graph *graph, std::vector<int32_t> values)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+ auto dim = values.size();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(1);
+ const_node->dim(0).set(dim);
+
+ const_node->size<loco::DataType::S32>(dim);
+ for (int32_t i = 0; i < dim; ++i)
+ const_node->at<loco::DataType::S32>(i) = values[i];
+
+ return const_node;
+}
+
+moco::TFConst *const_matrix(loco::Graph *graph, int32_t dimh, int32_t dimw)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(2);
+ const_node->dim(0).set(dimh);
+ const_node->dim(1).set(dimw);
+
+ auto elements = dimh * dimw;
+ const_node->size<loco::DataType::S32>(elements);
+ for (int32_t i = 0; i < elements; ++i)
+ const_node->at<loco::DataType::S32>(i) = i;
+
+ return const_node;
+}
+
+} // namespace
+
+TEST(ConstantFoldStridedSlice, basic_matrix55_11)
+{
+ loco::Graph graph;
+
+ auto sslice_node = graph.nodes()->create<moco::TFStridedSlice>();
+ {
+ auto const_input = const_matrix(&graph, 5, 5);
+ sslice_node->input(const_input);
+
+ auto const_begin = const_vector_init(&graph, {1, 1});
+ sslice_node->begin(const_begin);
+ auto const_end = const_vector_init(&graph, {2, 4});
+ sslice_node->end(const_end);
+ auto const_strides = const_vector_init(&graph, {1, 1});
+ sslice_node->strides(const_strides);
+
+ sslice_node->shrink_axis_mask(1);
+ }
+ setup_output_node(&graph, sslice_node);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldStridedSlice>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto ssnode = find_first_node_bytype<moco::TFStridedSlice>(&graph);
+ ASSERT_EQ(ssnode, nullptr);
+
+ auto ssconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(ssconst, nullptr);
+ ASSERT_EQ(ssconst->size<loco::DataType::S32>(), 3);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(0), 6);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(1), 7);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(2), 8);
+}
+
+TEST(ConstantFoldStridedSlice, basic_vector4_0)
+{
+ loco::Graph graph;
+
+ auto sslice_node = graph.nodes()->create<moco::TFStridedSlice>();
+ {
+ auto const_input = const_vector_init(&graph, {1, 5, 5, 64});
+ sslice_node->input(const_input);
+
+ auto const_begin = const_vector_init(&graph, {0});
+ sslice_node->begin(const_begin);
+ auto const_end = const_vector_init(&graph, {1});
+ sslice_node->end(const_end);
+ auto const_strides = const_vector_init(&graph, {1});
+ sslice_node->strides(const_strides);
+
+ sslice_node->shrink_axis_mask(1);
+ }
+ setup_output_node(&graph, sslice_node);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldStridedSlice>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto ssnode = find_first_node_bytype<moco::TFStridedSlice>(&graph);
+ ASSERT_EQ(ssnode, nullptr);
+
+ auto ssconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(ssconst, nullptr);
+ ASSERT_EQ(ssconst->size<loco::DataType::S32>(), 1);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(0), 1);
+}
+
+TEST(ConstantFoldStridedSlice, basic_vector4_1)
+{
+ loco::Graph graph;
+
+ auto sslice_node = graph.nodes()->create<moco::TFStridedSlice>();
+ {
+ auto const_input = const_vector_init(&graph, {1, 5, 5, 64});
+ sslice_node->input(const_input);
+
+ auto const_begin = const_vector_init(&graph, {1});
+ sslice_node->begin(const_begin);
+ auto const_end = const_vector_init(&graph, {2});
+ sslice_node->end(const_end);
+ auto const_strides = const_vector_init(&graph, {1});
+ sslice_node->strides(const_strides);
+
+ sslice_node->shrink_axis_mask(1);
+ }
+ setup_output_node(&graph, sslice_node);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldStridedSlice>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto ssnode = find_first_node_bytype<moco::TFStridedSlice>(&graph);
+ ASSERT_EQ(ssnode, nullptr);
+
+ auto ssconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(ssconst, nullptr);
+ ASSERT_EQ(ssconst->size<loco::DataType::S32>(), 1);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(0), 5);
+}
+
+TEST(ConstantFoldStridedSlice, basic_vector4_2)
+{
+ loco::Graph graph;
+
+ auto sslice_node = graph.nodes()->create<moco::TFStridedSlice>();
+ {
+ auto const_input = const_vector_init(&graph, {1, 5, 5, 64});
+ sslice_node->input(const_input);
+
+ auto const_begin = const_vector_init(&graph, {2});
+ sslice_node->begin(const_begin);
+ auto const_end = const_vector_init(&graph, {3});
+ sslice_node->end(const_end);
+ auto const_strides = const_vector_init(&graph, {1});
+ sslice_node->strides(const_strides);
+
+ sslice_node->shrink_axis_mask(1);
+ }
+ setup_output_node(&graph, sslice_node);
+
+ auto pass = stdex::make_unique<moco::ConstantFoldStridedSlice>();
+ bool cont = true;
+ while (cont)
+ {
+ cont = pass->run(&graph);
+ }
+
+ auto ssnode = find_first_node_bytype<moco::TFStridedSlice>(&graph);
+ ASSERT_EQ(ssnode, nullptr);
+
+ auto ssconst = find_first_node_bytype<moco::TFConst>(&graph);
+ ASSERT_NE(ssconst, nullptr);
+ ASSERT_EQ(ssconst->size<loco::DataType::S32>(), 1);
+ ASSERT_EQ(ssconst->at<loco::DataType::S32>(0), 5);
+}
+
+namespace
+{
+
+/**
+ * @note tfconst_at() implementation should be same as that of inside
+ * ConstantFoldStridedSlice.cpp for valid testing
+ */
+int32_t tfconst_at(const moco::TFConst *tfconst, const std::vector<uint32_t> &pos)
+{
+ uint32_t rank = tfconst->rank();
+ assert(rank == pos.size());
+
+ uint32_t element = 0;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ uint32_t dim = tfconst->dim(r).value();
+ element = element * dim + pos.at(r);
+ }
+ return tfconst->at<loco::DataType::S32>(element);
+}
+
+} // namespace
+
+TEST(ConstantFoldStridedSlice, tfconst_at)
+{
+ loco::Graph graph;
+
+ auto const_node = graph.nodes()->create<moco::TFConst>();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(3);
+ const_node->dim(0).set(2);
+ const_node->dim(1).set(3);
+ const_node->dim(2).set(4);
+
+ auto elements = 2 * 3 * 4;
+ const_node->size<loco::DataType::S32>(elements);
+ for (int32_t i = 0; i < elements; ++i)
+ const_node->at<loco::DataType::S32>(i) = i;
+ /*
+ [
+ [ 0, 1, 2, 3] <- [0,0,0]
+ [ 4, 5, 6, 7] <- [0,1,0] [0,1,1] [0,1,2]
+ [ 8, 9,10,11]
+ ]
+ [
+ [12,13,14,15]
+ [16,17,18,19] <- [1,1,0] [1,1,1]
+ [20,21,22,23] <- [1,2,0] [1,2,1] [1,2,2] [1,2,3]
+ ]
+ */
+
+ ASSERT_EQ(tfconst_at(const_node, {0, 0, 0}), 0);
+ ASSERT_EQ(tfconst_at(const_node, {1, 1, 1}), 17);
+ ASSERT_EQ(tfconst_at(const_node, {0, 1, 2}), 6);
+ ASSERT_EQ(tfconst_at(const_node, {1, 2, 3}), 23);
+}
diff --git a/compiler/moco/pass/src/Passes/ConstantFoldAdd.cpp b/compiler/moco/pass/src/Passes/ConstantFoldAdd.cpp
new file mode 100644
index 000000000..018749b78
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/ConstantFoldAdd.cpp
@@ -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 "moco/Pass/Passes/ConstantFoldAdd.h"
+
+#include "ConstantFoldHelper.h"
+
+#include <moco/IR/Nodes/TFAdd.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <moco/Support/NodeAs.h>
+
+namespace
+{
+
+struct Func final : public moco::BinaryFunc
+{
+ float apply(float lhs, float rhs) const { return lhs + rhs; }
+ int32_t apply(int32_t lhs, int32_t rhs) const { return lhs + rhs; }
+};
+
+bool constantfold_add(moco::TFAdd *node)
+{
+ auto x_const = moco::as<moco::TFConst>(node->x());
+ auto y_const = moco::as<moco::TFConst>(node->y());
+ if (x_const == nullptr || y_const == nullptr)
+ return false;
+
+ if (x_const->dtype() != y_const->dtype())
+ return false;
+ // TODO support other types
+ if (x_const->dtype() != loco::DataType::S32 && x_const->dtype() != loco::DataType::FLOAT32)
+ return false;
+
+ // NOTE we support limited shape of elementwise add or add with a scalar.
+ // valid_shape_for_constfold_binary_op() explains limited shape.
+ auto x_shape = moco::tensor_shape(x_const);
+ auto y_shape = moco::tensor_shape(y_const);
+ if (!moco::valid_shape_for_constfold_binary_op(x_shape, y_shape))
+ return false;
+
+ loco::TensorShape output_shape;
+ if (y_shape.rank() == 0 || y_shape.rank() == 1)
+ output_shape = x_shape;
+ else
+ output_shape = y_shape;
+
+ auto graph = node->graph();
+ auto output_const = moco::new_const(graph, output_shape, x_const->dtype());
+ Func f;
+
+ if (x_const->dtype() == loco::DataType::S32)
+ {
+ moco::apply_binary<int32_t>(x_const, y_const, output_const, f);
+ }
+ else if (x_const->dtype() == loco::DataType::FLOAT32)
+ {
+ moco::apply_binary<float>(x_const, y_const, output_const, f);
+ }
+
+ // replace
+ loco::replace(node).with(output_const);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+/**
+ * @note This will Replace TFAdd with TFConst when inputs are TFConst
+ *
+ * Before
+ * A --- TFAdd --- C
+ * B --/
+ * After
+ * A --- TFAdd
+ * B --/
+ * TFConst ---------- C
+ * Where
+ * A,B : inputs of TFAdd
+ * C : a node that uses TFAdd as an input
+ * TFAdd is disconnected from C
+ * Nodes are drawn multiple times to simplify the diagram
+ */
+bool ConstantFoldAdd::run(loco::Graph *graph)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(graph)))
+ {
+ if (auto add_node = as<moco::TFAdd>(node))
+ {
+ if (constantfold_add(add_node))
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/ConstantFoldMul.cpp b/compiler/moco/pass/src/Passes/ConstantFoldMul.cpp
new file mode 100644
index 000000000..c1870ffee
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/ConstantFoldMul.cpp
@@ -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 "moco/Pass/Passes/ConstantFoldMul.h"
+
+#include "ConstantFoldHelper.h"
+
+#include <moco/IR/Nodes/TFMul.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <moco/Support/NodeAs.h>
+
+namespace
+{
+
+struct Func final : public moco::BinaryFunc
+{
+ float apply(float lhs, float rhs) const { return lhs * rhs; }
+ int32_t apply(int32_t lhs, int32_t rhs) const { return lhs * rhs; }
+};
+
+bool constantfold_mul(moco::TFMul *node)
+{
+ auto x_const = moco::as<moco::TFConst>(node->x());
+ auto y_const = moco::as<moco::TFConst>(node->y());
+ if (x_const == nullptr || y_const == nullptr)
+ return false;
+
+ if (x_const->dtype() != y_const->dtype())
+ return false;
+ // TODO support other types
+ if (x_const->dtype() != loco::DataType::S32 && x_const->dtype() != loco::DataType::FLOAT32)
+ return false;
+
+ // NOTE we support limited shape of elementwise mul or multiply with a scalar.
+ // valid_shape_for_constfold_binary_op() explains limited shape.
+ auto x_shape = moco::tensor_shape(x_const);
+ auto y_shape = moco::tensor_shape(y_const);
+ if (!moco::valid_shape_for_constfold_binary_op(x_shape, y_shape))
+ return false;
+
+ loco::TensorShape output_shape;
+ if (y_shape.rank() == 0 || y_shape.rank() == 1)
+ output_shape = x_shape;
+ else
+ output_shape = y_shape;
+
+ auto graph = node->graph();
+ auto output_const = moco::new_const(graph, output_shape, x_const->dtype());
+ Func f;
+
+ if (x_const->dtype() == loco::DataType::S32)
+ {
+ moco::apply_binary<int32_t>(x_const, y_const, output_const, f);
+ }
+ else if (x_const->dtype() == loco::DataType::FLOAT32)
+ {
+ moco::apply_binary<float>(x_const, y_const, output_const, f);
+ }
+
+ // replace
+ loco::replace(node).with(output_const);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+/**
+ * @note This will Replace TFMul with TFConst when input are TFConst
+ *
+ * Before
+ * A --- TFMul --- C
+ * B --/
+ * After
+ * A --- TFMul
+ * B --/
+ * TFConst ---------- C
+ * Where
+ * A,B : inputs of TFMul
+ * C : a node that uses TFMul as an input
+ * TFMul is disconnected from C
+ * Nodes are drawn multiple times to simplify the diagram
+ */
+bool ConstantFoldMul::run(loco::Graph *graph)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(graph)))
+ {
+ if (auto mul_node = as<moco::TFMul>(node))
+ {
+ if (constantfold_mul(mul_node))
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/ConstantFoldPack.cpp b/compiler/moco/pass/src/Passes/ConstantFoldPack.cpp
new file mode 100644
index 000000000..cc8a23d18
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/ConstantFoldPack.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Pass/Passes/ConstantFoldPack.h"
+
+#include "ConstantFoldHelper.h"
+#include "TensorPackEnumerator.h"
+
+#include <moco/IR/Nodes/TFPack.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <moco/Support/NodeAs.h>
+
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <vector>
+
+namespace
+{
+
+// TODO move to loco
+bool operator==(const loco::TensorShape &lhs, const loco::TensorShape &rhs)
+{
+ if (lhs.rank() != rhs.rank())
+ return false;
+ for (uint32_t axis = 0; axis < lhs.rank(); ++axis)
+ {
+ if (!(lhs.dim(axis) == rhs.dim(axis)))
+ return false;
+ }
+ return true;
+}
+
+bool valid_axis_range(int32_t output_rank, int32_t pack_axis)
+{
+ // check axis range in [-r-1, r+1)
+ assert(output_rank > 0);
+ return (-output_rank <= pack_axis) && (pack_axis < output_rank);
+}
+
+bool constantfold_pack(moco::TFPack *node)
+{
+ // check if all the inputs are Const
+ std::vector<moco::TFConst *> input_nodes;
+ uint32_t num = node->N();
+
+ for (uint32_t index = 0; index < num; ++index)
+ {
+ auto in = dynamic_cast<moco::TFConst *>(node->values(index));
+ if (in == nullptr)
+ return false;
+
+ input_nodes.push_back(in);
+ }
+ assert(input_nodes.size() == num);
+
+ // check if all inputs have same shape and dtype
+ auto input_0 = input_nodes.at(0);
+ auto shape_0 = moco::tensor_shape(input_0);
+ auto dtype_0 = input_0->dtype();
+ if (dtype_0 != loco::DataType::S32 && dtype_0 != loco::DataType::FLOAT32)
+ {
+ // TODO support other types
+ assert(false);
+ return false;
+ }
+ for (uint32_t index = 1; index < num; ++index)
+ {
+ auto input_i = input_nodes.at(index);
+ auto shape_i = moco::tensor_shape(input_i);
+ auto dtype_i = input_i->dtype();
+ if (!(shape_0 == shape_i))
+ return false;
+ if (dtype_0 != dtype_i)
+ return false;
+ }
+
+ int32_t output_rank = static_cast<int32_t>(shape_0.rank() + 1);
+ int32_t pack_axis = node->axis();
+ if (!valid_axis_range(output_rank, pack_axis))
+ {
+ throw oops::UserExn("axis is out of range: ", node->name());
+ }
+
+ if (pack_axis < 0)
+ {
+ pack_axis = output_rank + pack_axis;
+ }
+
+ // define output shape
+ loco::TensorShape output_shape;
+ output_shape.rank(output_rank);
+
+ for (int32_t r = 0, s = 0; r < output_rank; ++r)
+ {
+ if (r == pack_axis)
+ {
+ output_shape.dim(r).set(num);
+ }
+ else
+ {
+ output_shape.dim(r).set(shape_0.dim(s++).value());
+ }
+ }
+
+ auto graph = node->graph();
+
+ // create new constant
+ auto output_const = moco::new_const(graph, output_shape, input_0->dtype());
+
+ moco::TensorPackEnumerator etor;
+
+ etor.shape(shape_0, output_shape);
+ etor.axis(pack_axis);
+ for (etor.start(); etor.valid(); etor.advance())
+ {
+ uint32_t inp_num = etor.inp_num();
+ uint32_t inp_element = etor.inp_element();
+ uint32_t out_element = etor.out_element();
+
+ auto inp_const = input_nodes[inp_num];
+
+ if (input_0->dtype() == loco::DataType::S32)
+ {
+ int32_t val = inp_const->at<loco::DataType::S32>(inp_element);
+ output_const->at<loco::DataType::S32>(out_element) = val;
+ }
+ else if (input_0->dtype() == loco::DataType::FLOAT32)
+ {
+ float val = inp_const->at<loco::DataType::FLOAT32>(inp_element);
+ output_const->at<loco::DataType::FLOAT32>(out_element) = val;
+ }
+ }
+
+ // replace
+ loco::replace(node).with(output_const);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+/**
+ * @note This will Replace TFPack with TFConst when inputs are TFConst
+ *
+ * Before
+ * A --- TFPack --- C
+ * B --/
+ * After
+ * A --- TFPack
+ * B --/
+ * TFConst ---------- C
+ * Where
+ * A, B : inputs of TFPack
+ * C : a node that uses TFPack as an input
+ * TFPack is disconnected from C
+ * Nodes are drawn multiple times to simplify the diagram
+ */
+bool ConstantFoldPack::run(loco::Graph *graph)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(graph)))
+ {
+ if (auto pack_node = as<moco::TFPack>(node))
+ {
+ if (constantfold_pack(pack_node))
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/ConstantFoldStridedSlice.cpp b/compiler/moco/pass/src/Passes/ConstantFoldStridedSlice.cpp
new file mode 100644
index 000000000..8be47648d
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/ConstantFoldStridedSlice.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Pass/Passes/ConstantFoldStridedSlice.h"
+
+#include "ConstantFoldHelper.h"
+#include "TensorSliceEnumerator.h"
+
+#include <moco/IR/Nodes/TFStridedSlice.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <moco/Support/NodeAs.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <vector>
+
+namespace
+{
+
+loco::TensorShape calc_output_shape(moco::TFStridedSlice *node)
+{
+ auto const_input = dynamic_cast<moco::TFConst *>(node->input());
+ auto const_begin = dynamic_cast<moco::TFConst *>(node->begin());
+ auto const_end = dynamic_cast<moco::TFConst *>(node->end());
+ auto const_strides = dynamic_cast<moco::TFConst *>(node->strides());
+ auto input_rank = const_input->rank();
+ auto output_rank = input_rank;
+ loco::TensorShape output_shape_range;
+
+ output_shape_range.rank(input_rank);
+ for (uint32_t r = 0; r < input_rank; ++r)
+ {
+ // TODO apply begin/end mask
+ // TODO apply ellipsis mask
+ // TODO apply strides
+ auto end = const_end->at<loco::DataType::S32>(r);
+ auto begin = const_begin->at<loco::DataType::S32>(r);
+ auto size = end - begin;
+ output_shape_range.dim(r).set(size);
+ }
+
+ loco::TensorShape output_tensor_shape;
+ if (node->shrink_axis_mask() != 0)
+ {
+ for (uint32_t rs = 0; rs < input_rank; ++rs)
+ {
+ int32_t bit = 1 << rs;
+ int32_t mask = node->shrink_axis_mask();
+ if (bit & mask)
+ {
+ // shrink one dimension
+ assert(output_rank > 0);
+ output_rank = output_rank - 1;
+ }
+ }
+ output_tensor_shape.rank(output_rank);
+ for (uint32_t rs = 0, rd = 0; rs < input_rank; ++rs)
+ {
+ int32_t bit = 1 << rs;
+ int32_t mask = node->shrink_axis_mask();
+ if ((bit & mask) == 0)
+ {
+ // use this dimension
+ output_tensor_shape.dim(rd).set(output_shape_range.dim(rs).value());
+ rd++;
+ }
+ // else this dimension is shrink-ed
+ }
+ }
+ else
+ {
+ output_tensor_shape = output_shape_range;
+ }
+
+ return output_tensor_shape;
+}
+
+moco::u32v_t vector_from_const(moco::TFConst *tfconst)
+{
+ moco::u32v_t result;
+
+ auto rank = tfconst->rank();
+ assert(rank == 1);
+ auto dim = tfconst->dim(0).value();
+
+ result.resize(dim);
+ for (uint32_t r = 0; r < dim; ++r)
+ {
+ auto val = tfconst->at<loco::DataType::S32>(r);
+ result.at(r) = val;
+ }
+
+ return result;
+}
+
+moco::u32v_t operator-(const moco::u32v_t &lhs, const moco::u32v_t &rhs)
+{
+ assert(lhs.size() == rhs.size());
+
+ moco::u32v_t res;
+ res.resize(lhs.size());
+ for (uint32_t r = 0; r < lhs.size(); r++)
+ {
+ res.at(r) = lhs.at(r) - rhs.at(r);
+ }
+ return res;
+}
+
+template <typename T> T tfconst_at(const moco::TFConst *tfconst, const moco::u32v_t &pos);
+
+template <> int32_t tfconst_at<int32_t>(const moco::TFConst *tfconst, const moco::u32v_t &pos)
+{
+ uint32_t rank = tfconst->rank();
+ assert(rank == pos.size());
+ uint32_t element = 0;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ uint32_t dim = tfconst->dim(r).value();
+ element = element * dim + pos.at(r);
+ }
+ return tfconst->at<loco::DataType::S32>(element);
+}
+
+template <> float tfconst_at<float>(const moco::TFConst *tfconst, const moco::u32v_t &pos)
+{
+ uint32_t rank = tfconst->rank();
+ assert(rank == pos.size());
+ uint32_t element = 0;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ uint32_t dim = tfconst->dim(r).value();
+ element = element * dim + pos.at(r);
+ }
+ return tfconst->at<loco::DataType::FLOAT32>(element);
+}
+
+void tfconst_at(moco::TFConst *tfconst, const moco::u32v_t &pos, int32_t value)
+{
+ // tfconst->rank() can be smaller than pos.size()
+ // i.e., tfconst: shape[3] and pos[0,1]
+ // where shape[3] is output result shape
+ // [0,1] is position of input const
+ uint32_t rank = pos.size();
+ uint32_t element = 0;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ // this is like expand the shape from [3] to [1,3] to use same formula as in reading
+ uint32_t dim = tfconst->rank() < r ? tfconst->dim(r).value() : 1;
+ element = element * dim + pos.at(r);
+ }
+
+ tfconst->at<loco::DataType::S32>(element) = value;
+}
+
+void tfconst_at(moco::TFConst *tfconst, const moco::u32v_t &pos, float value)
+{
+ uint32_t rank = pos.size();
+ uint32_t element = 0;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ uint32_t dim = tfconst->rank() < r ? tfconst->dim(r).value() : 1;
+ element = element * dim + pos.at(r);
+ }
+
+ tfconst->at<loco::DataType::FLOAT32>(element) = value;
+}
+
+bool constantfold_stridedslice(moco::TFStridedSlice *node)
+{
+ auto const_input = dynamic_cast<moco::TFConst *>(node->input());
+ if (const_input == nullptr)
+ {
+ // input is not TFConst, there's nothing to do
+ return false;
+ }
+
+ // TODO support full mask features: see import codes also
+ assert(node->begin_mask() == 0);
+ assert(node->end_mask() == 0);
+ assert(node->ellipsis_mask() == 0);
+ assert(node->shrink_axis_mask() == 1);
+
+ // TODO support other dtypes
+ assert(const_input->dtype() == loco::DataType::S32 ||
+ const_input->dtype() == loco::DataType::FLOAT32);
+
+ auto const_begin = dynamic_cast<moco::TFConst *>(node->begin());
+ auto const_end = dynamic_cast<moco::TFConst *>(node->end());
+ auto const_strides = dynamic_cast<moco::TFConst *>(node->strides());
+ if (const_begin == nullptr || const_end == nullptr || const_strides == nullptr)
+ {
+ return false;
+ }
+
+ // NOTE need shape but cannot depend on shape inference service module
+ auto tensor_shape = calc_output_shape(node);
+ auto input_shape = moco::tensor_shape(const_input);
+
+ auto graph = node->graph();
+
+ // Create our target TFConst node with shape from begin~end/strides
+ auto const_sliced = moco::new_const(graph, tensor_shape, const_input->dtype());
+
+ // Copy sliced elements using TensorSliceEnumerator
+ moco::TensorSliceEnumerator etor;
+ auto v_begin = vector_from_const(const_begin);
+ auto v_end = vector_from_const(const_end);
+ moco::u32v_t v_cursor;
+ moco::u32v_t v_offset;
+
+ etor.shape(input_shape);
+ etor.begin(v_begin);
+ etor.end(v_end);
+
+ for (etor.start(); etor.valid(); etor.advance())
+ {
+ v_cursor = etor.cursor();
+ v_offset = v_cursor - v_begin;
+
+ if (const_input->dtype() == loco::DataType::S32)
+ {
+ int32_t value = tfconst_at<int32_t>(const_input, v_cursor);
+ tfconst_at(const_sliced, v_offset, value);
+ }
+ else if (const_input->dtype() == loco::DataType::FLOAT32)
+ {
+ float value = tfconst_at<float>(const_input, v_cursor);
+ tfconst_at(const_sliced, v_offset, value);
+ }
+ }
+
+ // replace
+ loco::replace(node).with(const_sliced);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+/**
+ * @note This will Replace TFStridedSlice with TFConst when 'input' is TFConst
+ *
+ * Before
+ * A --- TFStridedSlice --- C
+ * B --/
+ * After
+ * A --- TFStridedSlice
+ * B --/
+ * TFConst ---------- C
+ * Where
+ * A,B : inputs of TFStridedSlice
+ * C : a node that uses TFStridedSlice as an input
+ * TFStridedSlice is disconnected from C
+ * Nodes are drawn multiple times to simplify the diagram
+ * Limits
+ * Only limit set of inputs are supported for now
+ */
+bool ConstantFoldStridedSlice::run(loco::Graph *graph)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(graph)))
+ {
+ if (auto sslice_node = as<moco::TFStridedSlice>(node))
+ {
+ if (constantfold_stridedslice(sslice_node))
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/FuseBinaryIntoPreceding.cpp b/compiler/moco/pass/src/Passes/FuseBinaryIntoPreceding.cpp
new file mode 100644
index 000000000..4a9631ea9
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/FuseBinaryIntoPreceding.cpp
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Pass/Passes/FuseBinaryIntoPreceding.h"
+
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include <moco/IR/TFDialect.h>
+#include <moco/IR/Nodes/TFAdd.h>
+#include <moco/IR/Nodes/TFBiasAdd.h>
+#include <moco/IR/Nodes/TFConst.h>
+#include <moco/IR/Nodes/TFConv2D.h>
+#include <moco/IR/Nodes/TFDepthwiseConv2dNative.h>
+#include <moco/IR/Nodes/TFMul.h>
+
+#include <cassert>
+#include <memory>
+
+namespace
+{
+
+/**
+ * @brief Fusable operation type
+ */
+enum class FuseType
+{
+ Conv2D,
+ DepthwiseConv2D,
+ // TODO Support FullyConnected
+};
+
+// TODO rename this method when there is a better name
+bool is_only_one_valid(moco::TFConst *xc, moco::TFConst *yc)
+{
+ if (xc == nullptr && yc == nullptr)
+ return false;
+ if (xc != nullptr && yc != nullptr)
+ return false;
+
+ return true;
+}
+
+// TODO Put this in some common place
+void copy_shape(const moco::TFConst *src, moco::TFConst *dst)
+{
+ assert(src != nullptr);
+ assert(dst != nullptr);
+
+ uint32_t rank = src->rank();
+ dst->rank(rank);
+ for (uint32_t index = 0; index < rank; ++index)
+ {
+ if (src->dim(index).known())
+ dst->dim(index) = src->dim(index);
+ else
+ dst->dim(index).unset();
+ }
+}
+
+/**
+ * @brief return true if shape is identical
+ */
+bool shape_match(const moco::TFConst *c1, const moco::TFConst *c2)
+{
+ assert(c1 != nullptr);
+ assert(c2 != nullptr);
+
+ uint32_t rank = c1->rank();
+ if (rank != c2->rank())
+ return false;
+
+ for (uint32_t index = 0; index < rank; ++index)
+ {
+ if (!c1->dim(index).known() || !c2->dim(index).known())
+ return false;
+
+ if (c1->dim(index).value() != c2->dim(index).value())
+ return false;
+ }
+ return true;
+}
+
+template <FuseType FT>
+moco::TFConst *create_kernel_from_fuse_mulparam(loco::Graph *graph, moco::TFConst *ker,
+ moco::TFConst *mulparam);
+
+template <>
+moco::TFConst *create_kernel_from_fuse_mulparam<FuseType::Conv2D>(loco::Graph *graph,
+ moco::TFConst *ker,
+ moco::TFConst *mulparam)
+{
+ auto ker_shape_inf = moco::node_shape(ker);
+ assert(ker_shape_inf.domain() != loco::Domain::Unknown);
+ auto ker_shape = ker_shape_inf.as<loco::TensorShape>();
+
+ auto mulparam_shape_inf = moco::node_shape(mulparam);
+ assert(mulparam_shape_inf.domain() != loco::Domain::Unknown);
+ auto mulparam_shape = mulparam_shape_inf.as<loco::TensorShape>();
+
+ // create new ker_fused with same size of ker
+ auto ker_fused = graph->nodes()->create<moco::TFConst>();
+
+ assert(ker_shape.rank() == 4);
+ assert(mulparam_shape.rank() == 1);
+ assert(ker_shape.dim(3).value() == mulparam_shape.dim(0).value());
+
+ ker_fused->dtype(loco::DataType::FLOAT32);
+ copy_shape(ker, ker_fused);
+ auto ker_num_elements = ker->size<loco::DataType::FLOAT32>();
+ ker_fused->size<loco::DataType::FLOAT32>(ker_num_elements);
+
+ // TensorFlow Conv2D Kernel has HWIO format
+ // Broadcast Mul vector to Kernel tensor by the Output
+ const uint32_t ker_height = ker_shape.dim(0).value();
+ const uint32_t ker_width = ker_shape.dim(1).value();
+ const uint32_t ker_input = ker_shape.dim(2).value();
+ const uint32_t ker_output = ker_shape.dim(3).value();
+
+ for (uint32_t ker_y = 0; ker_y < ker_height; ++ker_y)
+ {
+ for (uint32_t ker_x = 0; ker_x < ker_width; ++ker_x)
+ {
+ for (uint32_t in_ch = 0; in_ch < ker_input; ++in_ch)
+ {
+ uint32_t num_items = ((ker_y * ker_width + ker_x) * ker_input + in_ch) * ker_output;
+ for (uint32_t out_ch = 0; out_ch < ker_output; ++out_ch)
+ {
+ auto mulparam_v = mulparam->at<loco::DataType::FLOAT32>(out_ch);
+ auto ker_v = ker->at<loco::DataType::FLOAT32>(num_items + out_ch);
+ ker_fused->at<loco::DataType::FLOAT32>(num_items + out_ch) = ker_v * mulparam_v;
+ }
+ }
+ }
+ }
+
+ return ker_fused;
+}
+
+/**
+ * @brief Create a kernel from fuse mulparam<FuseType::DepthwiseConv2D> object
+ * @return Kernel of fused mulparam
+ */
+template <>
+moco::TFConst *create_kernel_from_fuse_mulparam<FuseType::DepthwiseConv2D>(loco::Graph *graph,
+ moco::TFConst *ker,
+ moco::TFConst *mulparam)
+{
+ auto ker_shape_inf = moco::node_shape(ker);
+ assert(ker_shape_inf.domain() != loco::Domain::Unknown);
+ auto ker_shape = ker_shape_inf.as<loco::TensorShape>();
+
+ auto mulparam_shape_inf = moco::node_shape(mulparam);
+ assert(mulparam_shape_inf.domain() != loco::Domain::Unknown);
+ auto mulparam_shape = mulparam_shape_inf.as<loco::TensorShape>();
+
+ // create new ker_fused with same size of ker
+ auto ker_fused = graph->nodes()->create<moco::TFConst>();
+
+ assert(ker_shape.rank() == 4);
+ assert(mulparam_shape.rank() == 1);
+ assert(ker_shape.dim(2).value() * ker_shape.dim(3).value() == mulparam_shape.dim(0).value());
+
+ ker_fused->dtype(loco::DataType::FLOAT32);
+ copy_shape(ker, ker_fused);
+ auto ker_num_elements = ker->size<loco::DataType::FLOAT32>();
+ ker_fused->size<loco::DataType::FLOAT32>(ker_num_elements);
+
+ // TensorFlow DepthwiseConv2DNative Kernel has HWIM format
+ // Broadcast Mul vector to Kernel tensor by the Output
+ const uint32_t ker_height = ker_shape.dim(0).value();
+ const uint32_t ker_width = ker_shape.dim(1).value();
+ const uint32_t ker_input = ker_shape.dim(2).value();
+ const uint32_t ker_multiplier = ker_shape.dim(3).value();
+
+ for (uint32_t ker_y = 0; ker_y < ker_height; ++ker_y)
+ {
+ for (uint32_t ker_x = 0; ker_x < ker_width; ++ker_x)
+ {
+ for (uint32_t in_ch = 0; in_ch < ker_input; ++in_ch)
+ {
+ uint32_t num_items = ((ker_y * ker_width + ker_x) * ker_input + in_ch) * ker_multiplier;
+ for (uint32_t ker_ch = 0; ker_ch < ker_multiplier; ++ker_ch)
+ {
+ auto mulparam_v = mulparam->at<loco::DataType::FLOAT32>(in_ch + ker_ch * ker_input);
+ auto ker_v = ker->at<loco::DataType::FLOAT32>(num_items + ker_ch);
+ ker_fused->at<loco::DataType::FLOAT32>(num_items + ker_ch) = ker_v * mulparam_v;
+ }
+ }
+ }
+ }
+
+ return ker_fused;
+}
+
+/**
+ * @brief Create a fused convolution opertion from kernel of fused mulparam
+ * @return Fused convolution operation
+ */
+template <FuseType FT, class T>
+T *fused_conv_node(loco::Graph *graph, moco::TFConst *mulparam, T *conv_node)
+{
+ // LOGGER(l);
+
+ // ker should be constant
+ auto ker = dynamic_cast<moco::TFConst *>(conv_node->filter());
+ if (ker == nullptr)
+ {
+ // Wait until ker is becomes TFConst: there are cases when it's Identity.
+ // INFO(l) << "Mul fuse_to_preceding: precedingOp ker is not TFConst";
+ return nullptr;
+ }
+ auto ifm = conv_node->input();
+ assert(ifm != nullptr);
+
+ // we need shape information, if not wait till it's ready
+ auto ker_shape_inf = moco::node_shape(ker);
+ if (ker_shape_inf.domain() == loco::Domain::Unknown)
+ {
+ // INFO(l) << "Mul fuse_to_preceding: precedingOp ker has no shape";
+ return nullptr;
+ }
+ auto mulparam_shape_inf = moco::node_shape(mulparam);
+ if (mulparam_shape_inf.domain() == loco::Domain::Unknown)
+ {
+ // INFO(l) << "Mul fuse_to_preceding: precedingOp mulparam has no shape";
+ return nullptr;
+ }
+ // if MulParam rank is not 1 we cannot fuse, just skip
+ auto mulparam_shape = mulparam_shape_inf.as<loco::TensorShape>();
+ if (mulparam_shape.rank() != 1)
+ {
+ // INFO(l) << "Mul fuse_to_preceding: Mul rank is not 1";
+ return nullptr;
+ }
+
+ auto ker_fused = create_kernel_from_fuse_mulparam<FT>(graph, ker, mulparam);
+ auto conv_fused = graph->nodes()->create<T>();
+
+ conv_fused->input(ifm);
+ conv_fused->filter(ker_fused);
+ conv_fused->padding(conv_node->padding());
+ conv_fused->data_layout(conv_node->data_layout());
+ conv_fused->strides(conv_node->strides());
+
+ return conv_fused;
+}
+
+/**
+ * @note This creates fused ker:2 from ker:1, 'mulparam' and
+ * new precedingOp:2 that uses ker:2 as the kernel.
+ * Then make C to use precedingOp:2 as new input.
+ *
+ * <Before>
+ * mulparam-\
+ * ker:1 --\ \
+ * ifm ----- precedingOp:1 ----------- Mul --- C
+ *
+ *
+ * <After>
+ * mulparam-\
+ * ker:1 --\ \
+ * - precedingOp:1 ----------- Mul ---
+ * /
+ * ifm ----- precedingOp:2 ------------------- C
+ * ker:2 ---/
+ *
+ *
+ * [Where]
+ * - precedingOp:1 can be one of TFConv2D, TFDepthwiseConv2dNative, FullyConnected
+ * - 'mulparam' and Mul will be disconnected from the Output.
+ * - ker:2 is added with fused values of ker:1 and mulparam
+ * - precedingOp:2 is added using ifm and ker:2 and other parameters
+ * same as precedingOp:1.
+ * - ker:1, precedingOp:1, 'mulparam' and Mul should be removed in
+ * RemoveDeadNodeTransform if not used.
+ */
+bool fuse_to_preceding(loco::Graph *graph, moco::TFMul *node)
+{
+ auto xc = dynamic_cast<moco::TFConst *>(node->x());
+ auto yc = dynamic_cast<moco::TFConst *>(node->y());
+
+ // Note: if both are constants, it should be done by constant-folding
+ if (!(is_only_one_valid(xc, yc)))
+ return false;
+
+ moco::TFConst *mulparam = nullptr;
+ moco::TFNode *precedingOp = nullptr;
+
+ if (xc != nullptr)
+ {
+ mulparam = xc;
+ precedingOp = dynamic_cast<moco::TFNode *>(node->y());
+ }
+ else // yc != nullptr
+ {
+ mulparam = yc;
+ precedingOp = dynamic_cast<moco::TFNode *>(node->x());
+ }
+
+ assert(mulparam->dtype() == loco::DataType::FLOAT32);
+
+ // TODO support FullyConnected
+ moco::TFNode *fused_node = nullptr;
+ if (auto conv2d = dynamic_cast<moco::TFConv2D *>(precedingOp))
+ fused_node = fused_conv_node<FuseType::Conv2D, moco::TFConv2D>(graph, mulparam, conv2d);
+ else if (auto dw_conv2d = dynamic_cast<moco::TFDepthwiseConv2dNative *>(precedingOp))
+ fused_node = fused_conv_node<FuseType::DepthwiseConv2D, moco::TFDepthwiseConv2dNative>(
+ graph, mulparam, dw_conv2d);
+
+ // Not ready yet
+ if (fused_node == nullptr)
+ return false;
+
+ // Replace TFMul node with new precedingOp with fused kernel
+ // This will leave existing precedingOp as-is but can be removed if not used
+ // from other transformations
+ replace(node).with(fused_node);
+ // TODO check if need to disconnect
+ // node->x(nullptr);
+ // node->y(nullptr);
+ // fused_node->ifm(nullptr);
+ // fused_node->ker(nullptr);
+
+ return true;
+}
+
+/**
+ * @brief Create zero-filled BiasAdd opertion and insert after precedingOp
+ * The plan is to fuse 'addparam' to TFBiasAdd bias
+ * @return Zero-filled BiasAdd operation
+ */
+template <class T>
+moco::TFBiasAdd *create_biasadd_node(loco::Graph *graph, moco::TFConst *addparam, T *precedingOp)
+{
+ auto dtype = addparam->dtype();
+ assert(dtype == loco::DataType::FLOAT32);
+
+ // Create TFConst(bias of TFBiasAdd) with same shape and dtype of 'addparam' but
+ // with values 0.0
+ auto biasadd_param = graph->nodes()->create<moco::TFConst>();
+ biasadd_param->dtype(dtype);
+ copy_shape(addparam, biasadd_param);
+ auto biasadd_num_elements = addparam->size<loco::DataType::FLOAT32>();
+ biasadd_param->size<loco::DataType::FLOAT32>(biasadd_num_elements);
+ for (int32_t i = 0; i < biasadd_num_elements; i++)
+ {
+ biasadd_param->at<loco::DataType::FLOAT32>(i) = 0.0f;
+ }
+
+ // Create TFBiasAdd with same shape as TFAdd
+ auto data_layout = precedingOp->data_layout();
+ auto tf_biasadd = graph->nodes()->create<moco::TFBiasAdd>();
+ tf_biasadd->data_layout(data_layout);
+
+ loco::replace(precedingOp).with(tf_biasadd);
+ tf_biasadd->value(precedingOp);
+ tf_biasadd->bias(biasadd_param);
+
+ return tf_biasadd;
+}
+
+/**
+ * @note TFAdd will be fused to TFBiasAdd
+ *
+ * <Before>
+ * If precedingOp is not TFBiasAdd, then insert TFConst:1 + TFBiasAdd that
+ * TFConst:1 has zero values.
+ *
+ * addparam --\
+ * \
+ * precedingOp ---------------------------- TFAdd ----- C
+ *
+ *
+ * <Intermediate>
+ * If it's TFBiasAdd and one of the input is TFConst type,
+ * then we can fuse 'addparam' to the input TFConst:2 value of TFBiasAdd, where
+ * TFConst:2 has added values from 'addparam'
+ *
+ * addparam --\
+ * TFConst:1 --------\ \
+ * precedingOp ------- TFBiasAdd ---------- TFAdd ----- C
+ *
+ *
+ * <After>
+ * addparam --\
+ * TFConst:2 --------\ \
+ * precedingOp ------- TFBiasAdd ---------- TFAdd -----
+ * \--------------------- C
+ *
+ *
+ * [Where]
+ * - precedingOp can be TFConv2D, TFDepthwiseConv2dNative, FullyConnected,
+ * TFBiasAdd.
+ * - Intermediate is to insert TFBiasAdd + TFConst:1
+ * - After is to fuse 'addparam' of TFAdd into TFConst:1 + TFBiasAdd
+ * that becomes TFConst:2 + TFBiasAdd
+ */
+bool fuse_to_preceding(loco::Graph *graph, moco::TFAdd *node)
+{
+ // LOGGER(l);
+
+ auto xc = dynamic_cast<moco::TFConst *>(node->x());
+ auto yc = dynamic_cast<moco::TFConst *>(node->y());
+
+ // Note: if both are constants, it should be done by constant-folding
+ if (!(is_only_one_valid(xc, yc)))
+ return false;
+
+ moco::TFConst *addparam = nullptr;
+ moco::TFNode *precedingOp = nullptr;
+
+ if (xc != nullptr)
+ {
+ addparam = xc;
+ precedingOp = dynamic_cast<moco::TFNode *>(node->y());
+ }
+ else // yc != nullptr
+ {
+ addparam = yc;
+ precedingOp = dynamic_cast<moco::TFNode *>(node->x());
+ }
+
+ auto addparam_shape_inf = moco::node_shape(addparam);
+ if (addparam_shape_inf.domain() == loco::Domain::Unknown)
+ {
+ // INFO(l) << "Add fuse_to_preceding: addparam has no shape";
+ return false;
+ }
+ // if AddParam rank is not 0 or 1 we cannot fuse, just skip
+ auto addparam_shape = addparam_shape_inf.as<loco::TensorShape>();
+ if (addparam_shape.rank() > 1)
+ {
+ // INFO(l) << "Add fuse_to_preceding: Add rank is not 0 or 1";
+ return false;
+ }
+
+ // TODO do something when rank() is 0
+ if (addparam_shape.rank() == 0)
+ {
+ // Not supported yet
+ return false;
+ }
+ assert(addparam_shape.rank() != 0);
+
+ // TODO support FullyConnected
+ moco::TFBiasAdd *biasadd = nullptr;
+ if (auto conv2d = dynamic_cast<moco::TFConv2D *>(precedingOp))
+ biasadd = create_biasadd_node<moco::TFConv2D>(graph, addparam, conv2d);
+ else if (auto dw_conv2d = dynamic_cast<moco::TFDepthwiseConv2dNative *>(precedingOp))
+ biasadd = create_biasadd_node<moco::TFDepthwiseConv2dNative>(graph, addparam, dw_conv2d);
+ else if (auto old_bias_add = dynamic_cast<moco::TFBiasAdd *>(precedingOp))
+ biasadd = old_bias_add;
+
+ if (biasadd == nullptr)
+ {
+ // try next turn
+ return false;
+ }
+
+ // Let's fuse addparam into biasadd bias
+ auto biasadd_bias = dynamic_cast<moco::TFConst *>(biasadd->bias());
+ assert(biasadd_bias != nullptr);
+ if (!shape_match(biasadd_bias, addparam))
+ {
+ // INFO(l) << "TFBiasAdd bias and TFAdd input shape mismatch";
+ return false;
+ }
+ auto add_num_elements = addparam->size<loco::DataType::FLOAT32>();
+ assert(add_num_elements == biasadd_bias->size<loco::DataType::FLOAT32>());
+ for (int32_t i = 0; i < add_num_elements; i++)
+ {
+ biasadd_bias->at<loco::DataType::FLOAT32>(i) += addparam->at<loco::DataType::FLOAT32>(i);
+ }
+
+ replace(node).with(biasadd);
+ // TODO check if need to disconnect
+ // node->x(nullptr);
+ // node->y(nullptr);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool FuseBinaryIntoPreceding::run(loco::Graph *graph)
+{
+ bool changed = false;
+ auto active_nodes = loco::active_nodes(loco::output_nodes(graph));
+
+ for (auto node : active_nodes)
+ {
+ if (node->dialect() == moco::TFDialect::get())
+ {
+ {
+ auto tf_node = dynamic_cast<moco::TFMul *>(node);
+ if (tf_node != nullptr)
+ {
+ if (fuse_to_preceding(graph, tf_node))
+ changed = true;
+ }
+ }
+ {
+ // TODO support Div
+ }
+
+ {
+ auto tf_node = dynamic_cast<moco::TFAdd *>(node);
+ if (tf_node != nullptr)
+ {
+ if (fuse_to_preceding(graph, tf_node))
+ changed = true;
+ }
+ }
+ {
+ // TODO support Sub
+ }
+ }
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/RemoveTFIdentityNode.cpp b/compiler/moco/pass/src/Passes/RemoveTFIdentityNode.cpp
new file mode 100644
index 000000000..d3d22c90e
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/RemoveTFIdentityNode.cpp
@@ -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 "moco/Pass/Passes/RemoveTFIdentityNode.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/IR/TFNode.h>
+
+#include <set>
+
+namespace moco
+{
+
+bool RemoveTFIdentityNode::run(loco::Graph *g)
+{
+ struct Collector final : public moco::TFNodeMutableVisitor<void>
+ {
+ void visit(moco::TFIdentity *node) final
+ {
+ if (node->input() != nullptr)
+ {
+ candidates.insert(node);
+ }
+ }
+
+ void visit(moco::TFNode *) final { return; }
+
+ std::set<moco::TFIdentity *> candidates;
+ };
+
+ Collector collector;
+
+ for (auto node : loco::all_nodes(g))
+ {
+ if (node->dialect() == moco::TFDialect::get())
+ {
+ auto tf_node = dynamic_cast<moco::TFNode *>(node);
+ // NOTE our analysis tool reports an error for tf_node may be nullptr
+ if (tf_node != nullptr)
+ tf_node->accept(&collector);
+ }
+ }
+
+ for (auto node : collector.candidates)
+ {
+ replace(node).with(node->input());
+ node->input(nullptr);
+ }
+
+ return collector.candidates.size() > 0;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/ResolveConstantShape.cpp b/compiler/moco/pass/src/Passes/ResolveConstantShape.cpp
new file mode 100644
index 000000000..2a1323fbc
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/ResolveConstantShape.cpp
@@ -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 "moco/Pass/Passes/ResolveConstantShape.h"
+
+#include <moco/Support/TFShapeInferenceHelper.h>
+#include <moco/Support/NodeAs.h>
+
+#include <moco/IR/Nodes/TFShape.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <loco.h>
+
+#include <oops/UserExn.h>
+
+#include <cassert>
+
+namespace
+{
+
+/**
+ * WHEN:
+ * - TFShape's input shape is determined
+ * DO:
+ * - Replace TFShape into TFConst
+ *
+ *
+ * <Before>
+ * in ---- TFShape ---- out(s)
+ *
+ * <After>
+ * in ---- TFShape
+ *
+ * TFConst ---- out(s)
+ */
+bool resolve_constant_shape(loco::Graph *graph, moco::TFShape *shape_node)
+{
+ auto input_shape = moco::node_shape(shape_node->input());
+
+ // Check condition
+ if (input_shape.domain() == loco::Domain::Unknown)
+ {
+ // Cannot resolve without known input_shape
+ return false;
+ }
+
+ auto input_tensor_shape = input_shape.as<loco::TensorShape>();
+
+ auto shape_rank = input_tensor_shape.rank();
+ for (uint32_t axis = 0; axis < shape_rank; ++axis)
+ {
+ if (!input_tensor_shape.dim(axis).known())
+ {
+ // Cannot resolve with unknown dimension
+ return false;
+ }
+ }
+
+ // Make TFConst to replace TFShape
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+
+ // set dtype
+ auto dtype = shape_node->dtype();
+ const_node->dtype(dtype);
+
+ // set shape
+ const_node->rank(1);
+ const_node->dim(0) = shape_rank;
+
+ // set data
+ if (dtype == loco::DataType::S32)
+ {
+ // TODO Better to make template for this when support new dtype
+ const_node->size<loco::DataType::S32>(shape_rank);
+ for (uint32_t axis = 0; axis < shape_rank; ++axis)
+ {
+ int32_t dim = (int32_t)input_tensor_shape.dim(axis).value();
+ if (!(dim > 0))
+ {
+ throw oops::UserExn("Invalid input shape", shape_node->name());
+ }
+ const_node->at<loco::DataType::S32>(axis) = dim;
+ }
+ }
+ else
+ {
+ throw oops::UserExn("Unsupported data type", shape_node->name());
+ }
+
+ // replace
+ loco::replace(shape_node).with(const_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ResolveConstantShape::run(loco::Graph *graph)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(graph)))
+ {
+ if (auto shape_node = as<moco::TFShape>(node))
+ {
+ if (resolve_constant_shape(graph, shape_node))
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/ResolveFusedBatchNorm.cpp b/compiler/moco/pass/src/Passes/ResolveFusedBatchNorm.cpp
new file mode 100644
index 000000000..6fd1474af
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/ResolveFusedBatchNorm.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Pass/Passes/ResolveFusedBatchNorm.h"
+
+#include <moco/Support/NodeAs.h>
+
+#include <moco/IR/Nodes/TFAdd.h>
+#include <moco/IR/Nodes/TFConst.h>
+#include <moco/IR/Nodes/TFMul.h>
+#include <moco/IR/Nodes/TFFusedBatchNorm.h>
+
+#include <cassert>
+#include <cmath>
+#include <memory>
+
+namespace
+{
+
+bool is_same_shape(moco::TFConst *lc, moco::TFConst *rc)
+{
+ if (lc->rank() != rc->rank())
+ return false;
+
+ for (auto r = 0; r < lc->rank(); ++r)
+ {
+ if (lc->dim(r).value() != rc->dim(r).value())
+ return false;
+ }
+ return true;
+}
+
+void copy_shape(const moco::TFConst *src, moco::TFConst *dst)
+{
+ assert(src != nullptr);
+ assert(dst != nullptr);
+
+ uint32_t rank = src->rank();
+ dst->rank(rank);
+ for (uint32_t index = 0; index < rank; ++index)
+ {
+ if (src->dim(index).known())
+ dst->dim(index) = src->dim(index).value();
+ else
+ dst->dim(index).unset();
+ }
+}
+
+/**
+ * @note resolve_to_muladd() will transform TFFusedBatchNorm to TFMul, TFAdd and two ConstGen
+ *
+ * <arguments>
+ * %0:input
+ * %1:gamma : const
+ * %2:beta : const
+ * %3:mean : const
+ * %4:variance : const
+ * %5:epsilon : const
+ *
+ * <constant operations>
+ * fbn_epsilon_array = make_array(%5:epsilon)
+ * fbn_epsilon = %4:variance + fbn_epsilon_array
+ * fbn_rsqrt = 1.0 / math::sqrt(fbn_epsilon)
+ *
+ * fbn_mean = %3:mean
+ * fbn_mul = fbn_rsqrt * %1:gamma
+ * fbn_offset = %2:beta
+ *
+ * fbn_mul_0_param = fbn_mul
+ * fbn_add_param = fbn_offset - fbn_mean * fbn_mul
+ *
+ * <new replace nodes>
+ * %11:fbn_mul_0_param = ConstGen(fbn_mul_0_param)
+ * %12:fbn_mul_0 = TFMul(%0:input, %11:fbn_mul_0_param)
+ * %21:fbn_add_param = ConstGen(fbn_add_param)
+ * %22:fbn = TFAdd(%12:fbn_mul_0,%21:fbn_add_param)
+ */
+bool resolve_to_muladd(loco::Graph *graph, moco::TFFusedBatchNorm *node)
+{
+ // LOGGER(lfbn);
+
+ auto tffbn_x = node->x();
+ if (tffbn_x == nullptr)
+ {
+ // This node is already converted
+ return false;
+ }
+
+ auto tffbn_scale = dynamic_cast<moco::TFConst *>(node->scale());
+ auto tffbn_offset = dynamic_cast<moco::TFConst *>(node->offset());
+ auto tffbn_mean = dynamic_cast<moco::TFConst *>(node->mean());
+ auto tffbn_variance = dynamic_cast<moco::TFConst *>(node->variance());
+
+ // all should be const
+ if (tffbn_scale == nullptr || tffbn_offset == nullptr || tffbn_mean == nullptr ||
+ tffbn_variance == nullptr)
+ {
+ // INFO(lfbn) << "TFFBN resolve_to_muladd: One of constant input node is not a constant"
+ // << std::endl;
+ return false;
+ }
+ assert(tffbn_scale->dtype() == loco::DataType::FLOAT32);
+ assert(tffbn_offset->dtype() == loco::DataType::FLOAT32);
+ assert(tffbn_mean->dtype() == loco::DataType::FLOAT32);
+ assert(tffbn_variance->dtype() == loco::DataType::FLOAT32);
+
+ // check all const shape are the same
+ if (!is_same_shape(tffbn_scale, tffbn_offset) || !is_same_shape(tffbn_scale, tffbn_mean) ||
+ !is_same_shape(tffbn_scale, tffbn_variance))
+ {
+ // INFO(lfbn) << "TFFBN resolve_to_muladd: Shape of constant are not same" << std::endl;
+ return false;
+ }
+
+ auto tffbn_epsilon = node->epsilon();
+ // INFO(lfbn) << "TFFBN tffbn_epsilon = " << tffbn_epsilon << std::endl;
+ auto const_num_elements = tffbn_scale->size<loco::DataType::FLOAT32>();
+ // INFO(lfbn) << "TFFBN const_num_elements = " << const_num_elements << std::endl;
+
+ // fbn_epsilon = %4:variance + fbn_epsilon_array
+ std::unique_ptr<float[]> fbn_epsilon{new float[const_num_elements]};
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ auto variance = tffbn_variance->at<loco::DataType::FLOAT32>(i);
+ fbn_epsilon.get()[i] = variance + tffbn_epsilon;
+ }
+
+ // fbn_rsqrt = 1.0 / math::sqrt(fbn_epsilon)
+ std::unique_ptr<float[]> fbn_rsqrt{new float[const_num_elements]};
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ fbn_rsqrt.get()[i] = 1.0 / sqrt(fbn_epsilon.get()[i]);
+ }
+
+ // fbn_mean = %3:mean : TODO remove this block and use %3:mean
+ std::unique_ptr<float[]> fbn_mean{new float[const_num_elements]};
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ fbn_mean.get()[i] = tffbn_mean->at<loco::DataType::FLOAT32>(i);
+ }
+
+ // fbn_mul = fbn_rsqrt * %1:gamma
+ std::unique_ptr<float[]> fbn_mul{new float[const_num_elements]};
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ fbn_mul.get()[i] = fbn_rsqrt.get()[i] * tffbn_scale->at<loco::DataType::FLOAT32>(i);
+ }
+
+ // fbn_offset = %2:beta : TODO remove this block and use %2:beta
+ std::unique_ptr<float[]> fbn_offset{new float[const_num_elements]};
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ fbn_offset.get()[i] = tffbn_offset->at<loco::DataType::FLOAT32>(i);
+ }
+
+ // fbn_mul_0_param = fbn_mul : remove this and use fbn_mul
+ std::unique_ptr<float[]> fbn_mul_0_param{new float[const_num_elements]};
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ fbn_mul_0_param.get()[i] = fbn_mul.get()[i];
+ }
+
+ // fbn_add_param = fbn_offset - fbn_mean * fbn_mul
+ std::unique_ptr<float[]> fbn_add_param{new float[const_num_elements]};
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ fbn_add_param.get()[i] = fbn_offset.get()[i] - fbn_mean.get()[i] * fbn_mul.get()[i];
+ }
+
+ // INFO(lfbn) << "TFFBN create ConstGen" << std::endl;
+
+ /*
+ * %11:fbn_mul_0_param = ConstGen(fbn_mul_0_param)
+ * %21:fbn_add_param = ConstGen(fbn_add_param)
+ */
+ auto const_fbn_mul_0_param = graph->nodes()->create<moco::TFConst>();
+ const_fbn_mul_0_param->dtype(loco::DataType::FLOAT32);
+ copy_shape(tffbn_scale, const_fbn_mul_0_param);
+ const_fbn_mul_0_param->size<loco::DataType::FLOAT32>(const_num_elements);
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ const_fbn_mul_0_param->at<loco::DataType::FLOAT32>(i) = fbn_mul_0_param.get()[i];
+ }
+ auto const_fbn_add_param = graph->nodes()->create<moco::TFConst>();
+ const_fbn_add_param->dtype(loco::DataType::FLOAT32);
+ copy_shape(tffbn_scale, const_fbn_add_param);
+ const_fbn_add_param->size<loco::DataType::FLOAT32>(const_num_elements);
+ for (int32_t i = 0; i < const_num_elements; i++)
+ {
+ const_fbn_add_param->at<loco::DataType::FLOAT32>(i) = fbn_add_param.get()[i];
+ }
+
+ // INFO(lfbn) << "TFFBN create TFMul, TFAdd" << std::endl;
+ /*
+ * %12:fbn_mul_0 = TFMul(%0:input, %11:fbn_mul_0_param)
+ * %22:fbn = TFAdd(%12:fbn_mul_0,%21:fbn_add_param)
+ */
+ auto fbn_mul_0 = graph->nodes()->create<moco::TFMul>();
+ fbn_mul_0->x(tffbn_x);
+ fbn_mul_0->y(const_fbn_mul_0_param);
+
+ auto fbn = graph->nodes()->create<moco::TFAdd>();
+ fbn->x(fbn_mul_0);
+ fbn->y(const_fbn_add_param);
+
+ // replace old node with new fbn
+ replace(node).with(fbn);
+ // unlink from graph
+ node->x(nullptr);
+ node->scale(nullptr);
+ node->offset(nullptr);
+ node->mean(nullptr);
+ node->variance(nullptr);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ResolveFusedBatchNorm::run(loco::Graph *graph)
+{
+ for (auto node : loco::active_nodes(loco::output_nodes(graph)))
+ {
+ if (as<moco::TFFusedBatchNorm>(node))
+ {
+ if (resolve_to_muladd(graph, as<moco::TFFusedBatchNorm>(node)))
+ {
+ // tree has been changed. let's return so that we don't need to
+ // considier about following node is correct or not.
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/ResolveReshapeWildcardDim.cpp b/compiler/moco/pass/src/Passes/ResolveReshapeWildcardDim.cpp
new file mode 100644
index 000000000..3446716cb
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/ResolveReshapeWildcardDim.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Pass/Passes/ResolveReshapeWildcardDim.h"
+
+#include <moco/Support/TFShapeInferenceHelper.h>
+#include <moco/Support/NodeAs.h>
+
+#include <moco/IR/Nodes/TFReshape.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <cassert>
+#include <limits>
+
+namespace
+{
+
+/**
+ * @return true when 'node' has one and only one wildcard dimension
+ * @return false when 'node' has no wildcard dimension, i.e. fixed reshape case
+ *
+ * @note Assertions in this function are sanity check for 'node', Reshape's
+ * Const shape input
+ */
+bool has_one_wildcard_dim(const moco::TFConst *node)
+{
+ assert(node->dtype() == loco::DataType::S32);
+ assert(node->rank() == 1);
+
+ auto len = node->dim(0).value();
+ assert(len > 0);
+
+ // Must have one and only wildcard dimension(-1)
+ uint32_t count_wildcard_dim = 0;
+ for (uint32_t i = 0; i < len; ++i)
+ {
+ auto dim = node->at<loco::DataType::S32>(i);
+ if (dim == -1)
+ count_wildcard_dim++;
+ else
+ assert(dim >= 1);
+ }
+
+ assert(count_wildcard_dim <= 1 &&
+ "Invalid Reshape: there should be none or only one wildcard dimension");
+ return count_wildcard_dim;
+}
+
+uint32_t volume(const loco::TensorShape &shape)
+{
+ uint32_t ret = 1;
+ auto rank = shape.rank();
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ ret *= shape.dim(axis).value();
+ }
+ return ret;
+}
+
+void deduce_and_fix_wildcard_dim(moco::TFConst *node, const loco::NodeShape &tensor_input_shape)
+{
+ assert(has_one_wildcard_dim(node));
+
+ assert(tensor_input_shape.domain() == loco::Domain::Tensor);
+ auto shape = tensor_input_shape.as<loco::TensorShape>();
+
+ auto len = node->dim(0).value();
+ uint32_t wildcard_index = std::numeric_limits<uint32_t>::max();
+ uint32_t product_of_non_wildcard_dims = 1;
+
+ // Deduce
+ for (uint32_t i = 0; i < len; ++i)
+ {
+ auto dim = node->at<loco::DataType::S32>(i);
+ if (dim == -1)
+ {
+ wildcard_index = i;
+ }
+ else
+ {
+ product_of_non_wildcard_dims *= dim;
+ }
+ }
+ assert(wildcard_index != std::numeric_limits<uint32_t>::max());
+
+ // Fix
+ assert(volume(shape) % product_of_non_wildcard_dims == 0);
+ node->at<loco::DataType::S32>(wildcard_index) = volume(shape) / product_of_non_wildcard_dims;
+}
+
+/**
+ * WHEN:
+ * - TFReshape's shape input is TFConst
+ * - The TFConst is valid shape input for dynamic reshape, i.e. it has one and
+ * only wildcard dimension(-1)
+ * - TFReshape's tensor input has complete shape inference data
+ * DO:
+ * - Deduce what the wildcard dimension is and fix it
+ */
+bool resolve_wildcard_dim(moco::TFReshape *reshape)
+{
+ // Check conditions (WHEN)
+ auto const_shape_input = dynamic_cast<moco::TFConst *>(reshape->shape());
+ if (!const_shape_input)
+ return false;
+
+ if (!has_one_wildcard_dim(const_shape_input))
+ return false;
+
+ auto tensor_input_shape = moco::node_shape(reshape->tensor());
+ if (tensor_input_shape.domain() == loco::Domain::Unknown)
+ return false;
+
+ // Deduce (DO)
+ deduce_and_fix_wildcard_dim(const_shape_input, tensor_input_shape);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ResolveReshapeWildcardDim::run(loco::Graph *graph)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(graph)))
+ {
+ if (auto reshape = as<moco::TFReshape>(node))
+ {
+ if (resolve_wildcard_dim(reshape))
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/ResolveSquaredDifference.cpp b/compiler/moco/pass/src/Passes/ResolveSquaredDifference.cpp
new file mode 100644
index 000000000..b66add1ae
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/ResolveSquaredDifference.cpp
@@ -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.
+ */
+
+#include "moco/Pass/Passes/ResolveSquaredDifference.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/IR/TFNodes.h>
+#include <moco/IR/TFNodeVisitor.h>
+#include <moco/IR/TFNodeImpl.h>
+
+#include <loco/IR/NodeShape.h>
+#include <loco/Service/ShapeInference.h>
+
+#include <stdex/Memory.h>
+
+namespace
+{
+
+bool decompose_sqdiff(moco::TFSquaredDifference *node)
+{
+ /**
+ * @note This will decompose TFSquaredDifference node into TFSub and TFMul
+ *
+ * Before
+ * A --- TFSquaredDifference -- C
+ * B --/
+ * After
+ * A --- TFSquaredDifference --
+ * B --/
+ * A --- TFSub == TFMul -- C
+ * B --/
+ * Where
+ * A : x of TFSquaredDifference
+ * B : y of TFSquaredDifference
+ * C : a node that uses TFSquaredDifference as an input
+ * TFSquaredDifference is disconnected from C
+ * A and B are drawn multiple times to simplify the diagram
+ */
+
+ auto node_A = node->x();
+ auto node_B = node->y();
+
+ auto sub_node = node->graph()->nodes()->create<moco::TFSub>();
+ auto mul_node = node->graph()->nodes()->create<moco::TFMul>();
+
+ // update connections
+ sub_node->x(node_A);
+ sub_node->y(node_B);
+ mul_node->x(sub_node);
+ mul_node->y(sub_node);
+
+ // replace node
+ replace(node).with(mul_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ResolveSquaredDifference::run(loco::Graph *graph)
+{
+ auto active_nodes = loco::active_nodes(loco::output_nodes(graph));
+ bool changed = false;
+
+ for (auto node : active_nodes)
+ {
+ if (node->dialect() == TFDialect::get())
+ {
+ auto tf_node = dynamic_cast<moco::TFSquaredDifference *>(node);
+ if (tf_node != nullptr)
+ {
+ if (decompose_sqdiff(tf_node))
+ changed = true;
+ }
+ }
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/Passes/SqueezeReduceNode.cpp b/compiler/moco/pass/src/Passes/SqueezeReduceNode.cpp
new file mode 100644
index 000000000..0d9686328
--- /dev/null
+++ b/compiler/moco/pass/src/Passes/SqueezeReduceNode.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Pass/Passes/SqueezeReduceNode.h"
+
+#include <moco/Support/NodeAs.h>
+
+#include <moco/IR/Nodes/TFConst.h>
+#include <moco/IR/Nodes/TFSqueeze.h>
+#include <moco/IR/Nodes/TFMean.h>
+
+#include <cassert>
+
+namespace
+{
+
+/**
+ * WHEN:
+ * - Reduce operations do not keep dimensions
+ * DO:
+ * - Replace original ReduceTypeOp to new ReduceTypeOp, which 'keep_dims' attribute is true
+ * - Insert TFSqueeze after new ReduceTypeOp
+ *
+ *
+ * <Before>
+ * in ---- ReduceTypeOp:0 (keep_dims = false) --- out(s)
+ *
+ * <After>
+ * --- ReduceTypeOp:0 (keep_dims = false)
+ * /
+ * in ---- ReduceTypeOp:1 (keep_dims = true) ---- TFSqueeze --- out(s)
+ *
+ * <Where>
+ * - 'keep_dims' attribute of ReduceTypeOp:0 is false
+ *
+ */
+template <class TFNode> bool squeeze_reduce_node(loco::Graph *graph, TFNode *reduce_node)
+{
+ // Don't need to squeeze reduce node
+ if (reduce_node->keep_dims())
+ return false;
+
+ // Reduction indices are not yet constant
+ auto const_reduction_indices = dynamic_cast<moco::TFConst *>(reduce_node->reduction_indices());
+ if (const_reduction_indices == nullptr)
+ return false;
+
+ auto squeeze_node = graph->nodes()->create<moco::TFSqueeze>();
+ auto new_reduce_node = graph->nodes()->create<TFNode>();
+
+ new_reduce_node->input(reduce_node->input());
+ new_reduce_node->reduction_indices(reduce_node->reduction_indices());
+ new_reduce_node->keep_dims(true);
+
+ // Insert squeeze dims
+ // TODO Support S64 type
+ assert(const_reduction_indices->dtype() == loco::DataType::S32);
+
+ std::vector<int64_t> reduction_values;
+ for (uint32_t i = 0; i < const_reduction_indices->size<loco::DataType::S32>(); ++i)
+ reduction_values.push_back(const_reduction_indices->at<loco::DataType::S32>(i));
+ squeeze_node->squeeze_dims(reduction_values);
+
+ // replace
+ loco::replace(reduce_node).with(squeeze_node);
+ squeeze_node->input(new_reduce_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SqueezeReduceNode::run(loco::Graph *graph)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(graph)))
+ {
+ if (auto shape_node = as<moco::TFMean>(node))
+ {
+ if (squeeze_reduce_node(graph, shape_node))
+ changed = true;
+ }
+ // TODO Add more reduce type operations
+ }
+
+ return changed;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/TensorPackEnumerator.cpp b/compiler/moco/pass/src/TensorPackEnumerator.cpp
new file mode 100644
index 000000000..61a160cfb
--- /dev/null
+++ b/compiler/moco/pass/src/TensorPackEnumerator.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TensorPackEnumerator.h"
+
+#include <cassert>
+
+namespace moco
+{
+
+void TensorPackEnumerator::shape(const loco::TensorShape &si, const loco::TensorShape &so)
+{
+ _shape_inp = si;
+ _shape_out = so;
+
+ assert(_shape_inp.rank() + 1 == _shape_out.rank());
+
+ _rank_out = _shape_out.rank();
+}
+
+void TensorPackEnumerator::increment(uint32_t r)
+{
+ _cursor_out.at(r) = _cursor_out.at(r) + 1;
+
+ if (_cursor_out.at(r) >= _boundary_out.at(r))
+ {
+ if (r > 0)
+ {
+ _cursor_out.at(r) = 0;
+ increment(r - 1);
+ }
+ else
+ {
+ // reached to the end
+ }
+ }
+}
+
+void TensorPackEnumerator::start(void)
+{
+ uint32_t rank = _rank_out;
+
+ _cursor_out.resize(rank);
+ _boundary_out.resize(rank);
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ _cursor_out.at(r) = 0;
+ _boundary_out.at(r) = _shape_out.dim(r).value();
+ }
+
+ rank = _rank_out - 1;
+ _cursor_inp.resize(rank);
+ _boundary_inp.resize(rank);
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ _cursor_inp.at(r) = 0;
+ _boundary_inp.at(r) = _shape_inp.dim(r).value();
+ }
+ _num_inp = 0;
+}
+
+bool TensorPackEnumerator::valid(void)
+{
+ uint32_t rank = _rank_out;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ if (_cursor_out.at(r) >= _boundary_out.at(r))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void TensorPackEnumerator::advance(void)
+{
+ uint32_t r = _rank_out - 1;
+ increment(r);
+
+ // from _cursor_out, set _cursor_inp and _num
+ for (int32_t r = 0, s = 0; r < _rank_out; ++r)
+ {
+ if (r == _axis)
+ {
+ _num_inp = _cursor_out.at(r);
+ }
+ else
+ {
+ _cursor_inp.at(s) = _cursor_out.at(r);
+ s++;
+ }
+ }
+}
+
+uint32_t TensorPackEnumerator::inp_num(void) const { return _num_inp; }
+
+uint32_t TensorPackEnumerator::inp_element(void) const
+{
+ uint32_t rank = _rank_out - 1;
+ uint32_t element = 0;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ uint32_t dim = _boundary_inp.at(r);
+ element = element * dim + _cursor_inp.at(r);
+ }
+ return element;
+}
+
+uint32_t TensorPackEnumerator::out_element(void) const
+{
+ uint32_t rank = _rank_out;
+ uint32_t element = 0;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ uint32_t dim = _boundary_out.at(r);
+ element = element * dim + _cursor_out.at(r);
+ }
+ return element;
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/TensorPackEnumerator.h b/compiler/moco/pass/src/TensorPackEnumerator.h
new file mode 100644
index 000000000..efdec3eb6
--- /dev/null
+++ b/compiler/moco/pass/src/TensorPackEnumerator.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 __MOCO_TENSOR_PACK_ENUMERATOR_H__
+#define __MOCO_TENSOR_PACK_ENUMERATOR_H__
+
+#include <loco/IR/TensorShape.h>
+
+#include <vector>
+
+namespace moco
+{
+
+using u32v_t = std::vector<uint32_t>;
+
+class TensorPackEnumerator
+{
+public:
+ TensorPackEnumerator() = default;
+
+public:
+ void shape(const loco::TensorShape &si, const loco::TensorShape &so);
+ void axis(uint32_t axis) { _axis = axis; }
+
+public:
+ void start(void);
+ bool valid(void);
+ void advance(void);
+
+public:
+ uint32_t inp_num(void) const;
+ uint32_t inp_element(void) const;
+ uint32_t out_element(void) const;
+
+private:
+ void increment(uint32_t);
+
+private:
+ loco::TensorShape _shape_inp;
+ loco::TensorShape _shape_out;
+
+ uint32_t _axis = 0;
+ uint32_t _rank_out = 0;
+ uint32_t _num_inp = 0;
+ u32v_t _cursor_inp;
+ u32v_t _cursor_out;
+ u32v_t _boundary_inp;
+ u32v_t _boundary_out;
+};
+
+} // namespace moco
+
+#endif // __MOCO_TENSOR_PACK_ENUMERATOR_H__
diff --git a/compiler/moco/pass/src/TensorSliceEnumerator.cpp b/compiler/moco/pass/src/TensorSliceEnumerator.cpp
new file mode 100644
index 000000000..58bd0554c
--- /dev/null
+++ b/compiler/moco/pass/src/TensorSliceEnumerator.cpp
@@ -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 "TensorSliceEnumerator.h"
+
+#include <cassert>
+
+namespace moco
+{
+
+void TensorSliceEnumerator::shape(loco::TensorShape &s)
+{
+ _shape_in = s;
+ _rank_in = _shape_in.rank();
+}
+
+void TensorSliceEnumerator::increment(uint32_t r)
+{
+ if (_cursor.at(r) < _boundary.at(r))
+ _cursor.at(r) = _cursor.at(r) + 1;
+ else
+ {
+ if (r > 0)
+ {
+ _cursor.at(r) = _begin[r];
+ increment(r - 1);
+ }
+ else
+ {
+ // reached to the end
+ }
+ }
+}
+
+void TensorSliceEnumerator::start(void)
+{
+ auto rank = _rank_in;
+
+ _cursor.resize(rank);
+ _boundary.resize(rank);
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ _cursor.at(r) = _begin[r];
+ _boundary.at(r) = _end[r];
+ }
+}
+
+bool TensorSliceEnumerator::valid(void)
+{
+ auto rank = _rank_in;
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ if (_cursor.at(r) >= _boundary.at(r))
+ return false;
+ }
+ return true;
+}
+
+void TensorSliceEnumerator::advance(void)
+{
+ uint32_t r = _rank_in - 1;
+ increment(r);
+}
+
+uint32_t TensorSliceEnumerator::cursor(uint32_t rank) const
+{
+ assert(rank < _rank_in);
+ return _cursor.at(rank);
+}
+
+} // namespace moco
diff --git a/compiler/moco/pass/src/TensorSliceEnumerator.h b/compiler/moco/pass/src/TensorSliceEnumerator.h
new file mode 100644
index 000000000..c8206fe9d
--- /dev/null
+++ b/compiler/moco/pass/src/TensorSliceEnumerator.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_TENSOR_SLICE_ENUMERATOR_H__
+#define __MOCO_TENSOR_SLICE_ENUMERATOR_H__
+
+#include <loco/IR/TensorShape.h>
+
+#include <vector>
+
+namespace moco
+{
+
+using u32v_t = std::vector<uint32_t>;
+
+class TensorSliceEnumerator
+{
+public:
+ TensorSliceEnumerator() = default;
+
+public:
+ void shape(loco::TensorShape &s);
+ void begin(u32v_t &b) { _begin = b; }
+ void end(u32v_t &e) { _end = e; }
+
+public:
+ void start(void);
+ bool valid(void);
+ void advance(void);
+
+ uint32_t cursor(uint32_t rank) const;
+ const u32v_t cursor(void) const { return _cursor; }
+
+private:
+ void increment(uint32_t);
+
+private:
+ loco::TensorShape _shape_in;
+
+ uint32_t _rank_in = 0;
+ u32v_t _cursor;
+ u32v_t _boundary;
+ u32v_t _begin;
+ u32v_t _end;
+};
+
+} // namespace moco
+
+#endif // __MOCO_TENSOR_SLICE_ENUMERATOR_H__
diff --git a/compiler/moco/pass/src/TensorSliceEnumerator.test.cpp b/compiler/moco/pass/src/TensorSliceEnumerator.test.cpp
new file mode 100644
index 000000000..078fe423f
--- /dev/null
+++ b/compiler/moco/pass/src/TensorSliceEnumerator.test.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TensorSliceEnumerator.h"
+
+#include <gtest/gtest.h>
+
+TEST(TensorSliceEnumeratorTest, basic_vector)
+{
+ moco::TensorSliceEnumerator iter;
+ loco::TensorShape shape;
+ uint32_t rank = 1;
+
+ shape.rank(rank);
+ shape.dim(0) = loco::Dimension(4);
+
+ std::vector<uint32_t> begin = {1};
+ std::vector<uint32_t> end = {3};
+
+ iter.shape(shape);
+ iter.begin(begin);
+ iter.end(end);
+
+ for (iter.start(); iter.valid(); iter.advance())
+ {
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ printf("%d ", iter.cursor(r));
+ }
+ printf("\n");
+ }
+
+ GTEST_SUCCEED();
+}
+
+TEST(TensorSliceEnumeratorTest, basic_matrix)
+{
+ moco::TensorSliceEnumerator etor;
+ loco::TensorShape shape;
+ uint32_t rank = 2;
+
+ shape.rank(rank);
+ shape.dim(0) = loco::Dimension(5);
+ shape.dim(1) = loco::Dimension(5);
+
+ std::vector<uint32_t> begin = {1, 1};
+ std::vector<uint32_t> end = {2, 4};
+ std::vector<uint32_t> offset;
+ std::vector<uint32_t> cursor;
+
+ etor.shape(shape);
+ etor.begin(begin);
+ etor.end(end);
+
+ for (etor.start(); etor.valid(); etor.advance())
+ {
+ cursor = etor.cursor();
+ assert(cursor.size() == begin.size());
+
+ offset.resize(cursor.size());
+ for (uint32_t r = 0; r < cursor.size(); r++)
+ {
+ offset.at(r) = cursor.at(r) - begin.at(r);
+ std::cout << offset.at(r) << " ";
+ }
+ std::cout << std::endl;
+ }
+
+ GTEST_SUCCEED();
+}
diff --git a/compiler/moco/pass/src/TestHelper.h b/compiler/moco/pass/src/TestHelper.h
new file mode 100644
index 000000000..b97491dba
--- /dev/null
+++ b/compiler/moco/pass/src/TestHelper.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 __TEST_HELPER_H__
+#define __TEST_HELPER_H__
+
+#include <loco.h>
+
+#include <moco/Support/NodeAs.h>
+
+namespace moco
+{
+namespace test
+{
+
+template <typename T> T *find_first_node_bytype(loco::Graph *g)
+{
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ if (auto T_node = as<T>(node))
+ {
+ return T_node;
+ }
+ }
+
+ return nullptr;
+}
+
+template <typename T> std::vector<T *> find_nodes_bytype(loco::Graph *g)
+{
+ std::vector<T *> find_nodes;
+
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ if (auto T_node = as<T>(node))
+ {
+ find_nodes.push_back(T_node);
+ }
+ }
+
+ return find_nodes;
+}
+
+/**
+ * @brief Append setup output of graph by adding loco::Push node
+ *
+ * @note This is subject to change when loco changes I/O treatment
+ */
+void setup_output_node(loco::Graph *graph, loco::Node *last_node);
+
+} // namespace test
+} // namespace moco
+
+#endif // __TEST_HELPER_H__
diff --git a/compiler/moco/pass/src/TestHelper.test.cpp b/compiler/moco/pass/src/TestHelper.test.cpp
new file mode 100644
index 000000000..59915d60f
--- /dev/null
+++ b/compiler/moco/pass/src/TestHelper.test.cpp
@@ -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 "TestHelper.h"
+
+namespace moco
+{
+namespace test
+{
+
+void setup_output_node(loco::Graph *graph, loco::Node *last_node)
+{
+ // add push as output
+ auto push_node = graph->nodes()->create<loco::Push>();
+ push_node->from(last_node);
+
+ // set the graph output name and node object
+ auto graph_output = graph->outputs()->create();
+ graph_output->name("output");
+ graph_output->dtype(loco::DataType::FLOAT32);
+ loco::link(graph_output, push_node);
+}
+
+} // namespace test
+} // namespace moco
diff --git a/compiler/moco/requires.cmake b/compiler/moco/requires.cmake
new file mode 100644
index 000000000..1a7d36454
--- /dev/null
+++ b/compiler/moco/requires.cmake
@@ -0,0 +1,8 @@
+require("loco")
+require("locop")
+require("stdex")
+require("moco-log")
+require("plier-tf")
+require("mio-tf")
+require("logo")
+require("oops")
diff --git a/compiler/moco/service/CMakeLists.txt b/compiler/moco/service/CMakeLists.txt
new file mode 100644
index 000000000..dff0233b1
--- /dev/null
+++ b/compiler/moco/service/CMakeLists.txt
@@ -0,0 +1,24 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(moco_service SHARED ${SOURCES})
+target_include_directories(moco_service PRIVATE src)
+target_include_directories(moco_service PUBLIC include)
+target_link_libraries(moco_service PUBLIC loco)
+target_link_libraries(moco_service PUBLIC moco_lang)
+target_link_libraries(moco_service PRIVATE moco_support)
+target_link_libraries(moco_service PRIVATE nncc_common)
+target_link_libraries(moco_service PRIVATE stdex)
+target_link_libraries(moco_service PRIVATE oops)
+install(TARGETS moco_service DESTINATION lib)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
+
+GTest_AddTest(moco_service_test ${TESTS})
+target_include_directories(moco_service_test PRIVATE src)
+target_link_libraries(moco_service_test moco_service)
diff --git a/compiler/moco/service/README.md b/compiler/moco/service/README.md
new file mode 100644
index 000000000..78906dbfe
--- /dev/null
+++ b/compiler/moco/service/README.md
@@ -0,0 +1,3 @@
+# service
+
+`service` provides TensorFlow Dialect Services
diff --git a/compiler/moco/service/include/moco/Service/TFShapeInferenceRule.h b/compiler/moco/service/include/moco/Service/TFShapeInferenceRule.h
new file mode 100644
index 000000000..98d716c2a
--- /dev/null
+++ b/compiler/moco/service/include/moco/Service/TFShapeInferenceRule.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 __MOCO_SERVICE_SHAPE_INFERENCE_RULE_H__
+#define __MOCO_SERVICE_SHAPE_INFERENCE_RULE_H__
+
+#include <loco/Service/ShapeInferenceRule.h>
+
+namespace moco
+{
+
+/**
+ * @brief Shape inference rule for TensorFlow dialect
+ */
+struct TFShapeInferenceRule final : public loco::ShapeInferenceRule
+{
+ bool support(const API &ver) const final;
+ bool recognize(const loco::Dialect *) const final;
+ bool infer(const loco::Node *, loco::NodeShape &) const final;
+ void infer(const Context *, const loco::Node *, Sink *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_SERVICE_SHAPE_INFERENCE_RULE_H__
diff --git a/compiler/moco/service/include/moco/Service/TFTypeInferenceRule.h b/compiler/moco/service/include/moco/Service/TFTypeInferenceRule.h
new file mode 100644
index 000000000..f712fdb01
--- /dev/null
+++ b/compiler/moco/service/include/moco/Service/TFTypeInferenceRule.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 __MOCO_SERVICE_TYPE_INFERENCE_RULE_H__
+#define __MOCO_SERVICE_TYPE_INFERENCE_RULE_H__
+
+#include <loco/Service/TypeInference.h>
+
+namespace moco
+{
+
+/**
+ * @brief Type Inference Rule for TFDialect
+ */
+struct TFTypeInferenceRule final : public loco::TypeInferenceRule
+{
+ bool recognize(const loco::Dialect *) const final;
+ bool infer(const loco::Node *, loco::DataType &) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_SERVICE_TYPE_INFERENCE_RULE_H__
diff --git a/compiler/moco/service/src/Service/TFShapeInferenceRule.cpp b/compiler/moco/service/src/Service/TFShapeInferenceRule.cpp
new file mode 100644
index 000000000..6d122c863
--- /dev/null
+++ b/compiler/moco/service/src/Service/TFShapeInferenceRule.cpp
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Service/TFShapeInferenceRule.h"
+
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include "moco/IR/TFDialect.h"
+#include "moco/IR/TFNode.h"
+
+#include <loco/IR/NodeShape.h>
+#include <loco/Service/ShapeInference.h>
+
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <cmath>
+
+namespace
+{
+
+class ShapeInferenceAlgorithm final : public moco::TFNodeVisitor<loco::NodeShape>
+{
+public:
+ ShapeInferenceAlgorithm(const loco::ShapeInferenceRule::Context *ctx) : _ctx{ctx}
+ {
+ // DO NOTHING
+ }
+
+private:
+ const loco::ShapeInferenceRule::Context *_ctx;
+
+private:
+ bool shape_known(const loco::Node *node) const { return _ctx->known(node); }
+ loco::NodeShape node_shape(const loco::Node *node) const { return _ctx->get(node); }
+
+private:
+ loco::NodeShape binary_node_shape(const moco::TFNode::Node *node)
+ {
+ // This helper works only for binary node.
+ assert(node->arity() == 2);
+
+ auto lhs_shape = node_shape(node->arg(0));
+ auto rhs_shape = node_shape(node->arg(1));
+
+ loco::TensorShape lhs_tensorshape = lhs_shape.as<loco::TensorShape>();
+ loco::TensorShape rhs_tensorshape = rhs_shape.as<loco::TensorShape>();
+ loco::TensorShape sum_tensorshape = moco::broadcast_shape(lhs_tensorshape, rhs_tensorshape);
+
+ loco::NodeShape sum_shape({sum_tensorshape});
+
+ return sum_shape;
+ }
+
+ loco::NodeShape node_shape_with_check(const moco::TFNode::Node *node)
+ {
+ auto nodeshape = node_shape(node);
+ assert(nodeshape.domain() == loco::Domain::Tensor);
+
+ return nodeshape;
+ }
+
+ bool valid_scalar_value(moco::TFConst *node)
+ {
+ auto nodeshape = node_shape(node);
+ if (nodeshape.domain() != loco::Domain::Tensor)
+ {
+ return false;
+ }
+ if (node->dtype() != loco::DataType::S32)
+ {
+ return false;
+ }
+
+ auto tensor_shape = nodeshape.as<loco::TensorShape>();
+ if (!(tensor_shape.rank() == 0 || tensor_shape.rank() == 1))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ int32_t scalar_value(moco::TFConst *node)
+ {
+ auto nodeshape = node_shape(node);
+ assert(node->dtype() == loco::DataType::S32);
+
+ auto tensor_shape = nodeshape.as<loco::TensorShape>();
+ assert(tensor_shape.rank() == 0 || tensor_shape.rank() == 1);
+
+ return node->at<loco::DataType::S32>(0);
+ }
+
+public:
+ loco::NodeShape visit(const moco::TFAdd *node) final { return binary_node_shape(node); }
+
+ loco::NodeShape visit(const moco::TFAvgPool *node) final
+ {
+ auto value_shape = node_shape(node->value());
+ assert(value_shape.domain() != loco::Domain::Unknown);
+
+ moco::PlaneInference infer_plane_shape;
+
+ infer_plane_shape.padding(node->padding());
+ infer_plane_shape.stride(moco::stride_of(node->strides(), node->data_layout()));
+ infer_plane_shape.window(moco::window_of(node->ksize(), node->data_layout()));
+
+ auto input_feature_shape = moco::as_feature_shape(value_shape, node->data_layout());
+ auto input_plane_shape = moco::make_plane_shape(input_feature_shape);
+ auto output_feature_shape = input_feature_shape;
+ auto output_plane_shape = infer_plane_shape(input_plane_shape);
+
+ moco::update(output_feature_shape).with(output_plane_shape);
+
+ return moco::as_tensor_shape(output_feature_shape, node->data_layout());
+ }
+
+ loco::NodeShape visit(const moco::TFBiasAdd *node) final
+ {
+ return node_shape_with_check(node->value());
+ }
+
+ loco::NodeShape visit(const moco::TFConcatV2 *node) final
+ {
+ // axis shape should be available
+ auto axis_node = node->axis();
+ auto axis_shape = node_shape(axis_node);
+ assert(axis_shape.domain() != loco::Domain::Unknown);
+
+ // check all input shapes and all ranks should be same
+ auto value_a = node->values(0);
+ auto value_a_shape = node_shape(value_a);
+ assert(value_a_shape.domain() == loco::Domain::Tensor);
+ auto value_a_tensor_shape = value_a_shape.as<loco::TensorShape>();
+ uint32_t a_rank = value_a_tensor_shape.rank();
+
+ uint32_t num_values = node->num_values();
+ for (uint32_t ni = 1; ni < num_values; ++ni)
+ {
+ auto value_b = node->values(ni);
+ auto value_b_shape = node_shape(value_b);
+ assert(value_b_shape.domain() == loco::Domain::Tensor);
+ auto value_b_tensor_shape = value_b_shape.as<loco::TensorShape>();
+ assert(a_rank == value_b_tensor_shape.rank());
+ }
+
+ int32_t axis_value = 0;
+ bool axis_available = false;
+ {
+ // check for axis is TFConst
+ auto tfconst = dynamic_cast<moco::TFConst *>(axis_node);
+ if (tfconst != nullptr)
+ {
+ if (valid_scalar_value(tfconst))
+ {
+ axis_value = scalar_value(tfconst);
+ axis_available = true;
+ }
+ }
+ }
+ if (!axis_available)
+ {
+ // TODO may need to refine error message
+ throw oops::UserExn("ConcatV2 node does not have axis input", node->name());
+ }
+
+ uint32_t axis_absolute = (axis_value >= 0) ? axis_value : (int32_t)a_rank + axis_value;
+ loco::TensorShape output_tensor_shape = value_a_tensor_shape;
+
+ for (uint32_t index = 0; index < a_rank; ++index)
+ {
+ if (value_a_tensor_shape.dim(index).known())
+ {
+ uint32_t dim = value_a_tensor_shape.dim(index).value();
+ uint32_t dim_acc = dim;
+
+ for (uint32_t ni = 1; ni < num_values; ++ni)
+ {
+ auto value_b = node->values(ni);
+ auto value_b_shape = node_shape(value_b);
+ assert(value_b_shape.domain() == loco::Domain::Tensor);
+ auto value_b_tensor_shape = value_b_shape.as<loco::TensorShape>();
+ assert(value_b_tensor_shape.dim(index).known());
+ if (index == axis_absolute)
+ dim_acc += value_b_tensor_shape.dim(index).value();
+ else
+ assert(dim == value_b_tensor_shape.dim(index).value());
+ }
+ output_tensor_shape.dim(index) = dim_acc;
+ }
+ else
+ output_tensor_shape.dim(index).unset();
+ }
+ return loco::NodeShape(output_tensor_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFConst *node) final
+ {
+ loco::TensorShape output_tensor_shape;
+
+ uint32_t rank = node->rank();
+ output_tensor_shape.rank(rank);
+ for (uint32_t index = 0; index < rank; ++index)
+ {
+ if (node->dim(index).known())
+ output_tensor_shape.dim(index) = node->dim(index).value();
+ else
+ output_tensor_shape.dim(index).unset();
+ }
+
+ return loco::NodeShape(output_tensor_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFConv2D *node) final
+ {
+ auto input_shape = moco::node_shape(node->input());
+ auto ker_shape = moco::node_shape(node->filter());
+ auto ker_tensor_shape = ker_shape.as<loco::TensorShape>(); // in HWIO
+ auto node_stride = moco::stride_of(node->strides(), node->data_layout());
+ auto node_window = moco::window_of(ker_tensor_shape, "HWIO");
+
+ moco::PlaneInference infer_plane_shape;
+
+ infer_plane_shape.padding(node->padding());
+ infer_plane_shape.stride(node_stride);
+ infer_plane_shape.window(node_window);
+
+ auto input_feature_shape = moco::as_feature_shape(input_shape, node->data_layout());
+ auto input_plane_shape = moco::make_plane_shape(input_feature_shape);
+ // output count is from input count, depth is from kernel 'O' which is dim(3)
+ auto output_feature_shape = input_feature_shape;
+ output_feature_shape.depth() = ker_tensor_shape.dim(3).value();
+
+ auto output_plane_shape = infer_plane_shape(input_plane_shape);
+
+ moco::update(output_feature_shape).with(output_plane_shape);
+
+ return moco::as_tensor_shape(output_feature_shape, node->data_layout());
+ }
+
+ loco::NodeShape visit(const moco::TFConv2DBackpropInput *node) final
+ {
+ // TFConv2DBackpropInput's first input, named 'input_sizes', actually contains shape of node
+ // output's feature map. We can get shape of TFConv2DBackpropInput by just copying this.
+ // TODO Support when 'input_sizes' is not TFConst, or support constant folding
+ auto input_sizes_node = dynamic_cast<moco::TFConst *>(node->input_sizes());
+ if (input_sizes_node == nullptr)
+ {
+ // we are now supporting somekind of constant folding for this node, wait till it is finished
+ loco::NodeShape unknown;
+ return unknown;
+ }
+
+ // Let's support S32 for time being
+ // TODO Support other integer types
+ assert(input_sizes_node->dtype() == loco::DataType::S32);
+ assert(input_sizes_node->size<loco::DataType::S32>() == 4);
+
+ // copy!
+ loco::TensorShape ofm_tensor_shape;
+ ofm_tensor_shape.rank(4);
+ for (uint32_t i = 0; i < 4; ++i)
+ {
+ int32_t dim = input_sizes_node->at<loco::DataType::S32>(i);
+ assert(dim > 0);
+ ofm_tensor_shape.dim(i) = (uint32_t)dim;
+ }
+
+ return loco::NodeShape(ofm_tensor_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFDepthwiseConv2dNative *node) final
+ {
+ auto input_shape = moco::node_shape(node->input()); // NHWC
+ auto ker_shape = moco::node_shape(node->filter());
+ auto ker_tensor_shape = ker_shape.as<loco::TensorShape>(); // in HWCM
+ auto node_stride = moco::stride_of(node->strides(), node->data_layout());
+ auto node_window = moco::window_of(ker_tensor_shape, "HWCM");
+
+ moco::PlaneInference infer_plane_shape;
+
+ infer_plane_shape.padding(node->padding());
+ infer_plane_shape.stride(node_stride);
+ infer_plane_shape.window(node_window);
+
+ auto input_feature_shape = moco::as_feature_shape(input_shape, node->data_layout());
+ auto input_plane_shape = moco::make_plane_shape(input_feature_shape);
+ // output count is from input count, depth is from kernel 'CM' which is dim(2) * dim(3)
+ auto output_feature_shape = input_feature_shape;
+ output_feature_shape.depth() =
+ loco::Dimension(ker_tensor_shape.dim(2).value() * ker_tensor_shape.dim(3).value());
+
+ auto output_plane_shape = infer_plane_shape(input_plane_shape);
+
+ moco::update(output_feature_shape).with(output_plane_shape);
+
+ return moco::as_tensor_shape(output_feature_shape, node->data_layout());
+ }
+
+ loco::NodeShape visit(const moco::TFFakeQuantWithMinMaxVars *node) final
+ {
+ return node_shape_with_check(node->inputs());
+ }
+
+ loco::NodeShape visit(const moco::TFFusedBatchNorm *node) final
+ {
+ return node_shape_with_check(node->x());
+ }
+
+ loco::NodeShape visit(const moco::TFIdentity *node) final
+ {
+ return node_shape_with_check(node->input());
+ }
+
+ loco::NodeShape visit(const moco::TFMaximum *node) final { return binary_node_shape(node); }
+
+ loco::NodeShape visit(const moco::TFMaxPool *node) final
+ {
+ auto input_shape = node_shape(node->input());
+ assert(input_shape.domain() != loco::Domain::Unknown);
+
+ moco::PlaneInference infer_plane_shape;
+
+ infer_plane_shape.padding(node->padding());
+ infer_plane_shape.stride(moco::stride_of(node->strides(), node->data_layout()));
+ infer_plane_shape.window(moco::window_of(node->ksize(), node->data_layout()));
+
+ auto input_feature_shape = moco::as_feature_shape(input_shape, node->data_layout());
+ auto input_plane_shape = moco::make_plane_shape(input_feature_shape);
+ auto output_feature_shape = input_feature_shape;
+ auto output_plane_shape = infer_plane_shape(input_plane_shape);
+
+ moco::update(output_feature_shape).with(output_plane_shape);
+
+ return moco::as_tensor_shape(output_feature_shape, node->data_layout());
+ }
+
+ loco::NodeShape visit(const moco::TFMean *node) final
+ {
+ auto input_shape = node_shape(node->input());
+ auto reduction_indices = node->reduction_indices();
+
+ // Get constant values if reduction_indices is const
+ std::vector<int32_t> reduction_values;
+ if (auto tfconst = dynamic_cast<moco::TFConst *>(reduction_indices))
+ {
+ assert(tfconst->dtype() == loco::DataType::S32);
+ auto const_size = tfconst->size<loco::DataType::S32>();
+ for (uint32_t i = 0; i < const_size; ++i)
+ {
+ int32_t axis = tfconst->at<loco::DataType::S32>(i);
+ if (axis < 0)
+ axis += input_shape.as<loco::TensorShape>().rank();
+ reduction_values.push_back(axis);
+ }
+ }
+ else
+ {
+ // we cannot find a valid reduction indices value
+ loco::NodeShape unknown;
+ return unknown;
+ }
+
+ loco::TensorShape output_shape;
+ auto input_tensor_shape = input_shape.as<loco::TensorShape>();
+
+ if (node->keep_dims())
+ {
+ output_shape.rank(input_tensor_shape.rank());
+ for (uint32_t i = 0; i < input_tensor_shape.rank(); ++i)
+ output_shape.dim(i) = input_tensor_shape.dim(i);
+ for (uint32_t i = 0; i < reduction_values.size(); ++i)
+ output_shape.dim(reduction_values.at(i)) = 1;
+ }
+ else
+ {
+ std::vector<bool> check_reduce(input_tensor_shape.rank(), false);
+ for (uint32_t i = 0; i < reduction_values.size(); ++i)
+ check_reduce.at(reduction_values.at(i)) = true;
+
+ uint32_t reduce_cnt = 0;
+ for (uint32_t i = 0; i < check_reduce.size(); ++i)
+ if (check_reduce.at(i))
+ ++reduce_cnt;
+
+ output_shape.rank(input_tensor_shape.rank() - reduce_cnt);
+ for (uint32_t i = 0, j = 0; i < check_reduce.size(); ++i)
+ if (check_reduce.at(i) == false)
+ output_shape.dim(j++) = i;
+ }
+
+ return loco::NodeShape(output_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFMul *node) final { return binary_node_shape(node); }
+
+ loco::NodeShape visit(const moco::TFPack *node) final
+ {
+ loco::NodeShape unknown;
+
+ auto input_shape_0 = node_shape(node->values(0));
+ if (input_shape_0.domain() != loco::Domain::Tensor)
+ {
+ // TODO fix this for other cases
+ // We support only valid tensor shape for now
+ return unknown;
+ }
+ loco::TensorShape tensor_shape_0 = input_shape_0.as<loco::TensorShape>();
+
+ // all input shapes should be same
+ auto num_values = node->N();
+ for (uint32_t i = 1; i < num_values; ++i)
+ {
+ auto input_shape = node_shape(node->values(i));
+ if (input_shape.domain() != loco::Domain::Tensor)
+ {
+ // TODO ditto
+ return unknown;
+ }
+
+ loco::TensorShape tensor_shape = input_shape.as<loco::TensorShape>();
+ if (!(input_shape_0 == input_shape))
+ {
+ throw oops::UserExn("All input values shape should be same", node->name());
+ }
+ }
+
+ // output rank will be +1 of rank of the input
+ // axis should be in range of [-r, r), where r is rank of the output
+ auto axis = node->axis();
+ int32_t rank = static_cast<int32_t>(tensor_shape_0.rank());
+ assert(rank >= 0);
+ int32_t rank_output = rank + 1;
+ if (axis < -rank_output || rank_output <= axis)
+ {
+ throw oops::UserExn("axis is out of range", node->name());
+ }
+
+ auto axis_stack = (axis >= 0) ? axis : rank_output + axis;
+
+ loco::TensorShape output_tensor_shape;
+
+ output_tensor_shape.rank(rank_output);
+ for (int32_t r = 0; r < axis_stack; ++r)
+ {
+ output_tensor_shape.dim(r).set(tensor_shape_0.dim(r).value());
+ }
+ output_tensor_shape.dim(axis_stack).set(num_values);
+ for (int32_t r = axis_stack; r < rank; ++r)
+ {
+ output_tensor_shape.dim(r + 1).set(tensor_shape_0.dim(r).value());
+ }
+
+ return loco::NodeShape(output_tensor_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFPad *node) final
+ {
+ auto input_shape = node_shape(node->input());
+ assert(input_shape.domain() == loco::Domain::Tensor);
+
+ auto const_paddings = dynamic_cast<moco::TFConst *>(node->paddings());
+ assert(const_paddings);
+ assert(const_paddings->dtype() == loco::DataType::S32);
+ assert(const_paddings->rank() == 2);
+
+ loco::TensorShape input_tensor_shape = input_shape.as<loco::TensorShape>();
+ loco::TensorShape output_tensor_shape;
+
+ output_tensor_shape.rank(input_tensor_shape.rank());
+ for (uint32_t axis = 0; axis < input_tensor_shape.rank(); ++axis)
+ {
+ output_tensor_shape.dim(axis) = input_tensor_shape.dim(axis).value() +
+ const_paddings->at<loco::DataType::S32>(axis * 2) +
+ const_paddings->at<loco::DataType::S32>(axis * 2 + 1);
+ }
+
+ return loco::NodeShape{output_tensor_shape};
+ }
+
+ loco::NodeShape visit(const moco::TFPlaceholder *node) final
+ {
+ loco::TensorShape output_tensor_shape;
+
+ uint32_t rank = node->rank();
+ output_tensor_shape.rank(rank);
+ for (uint32_t index = 0; index < rank; ++index)
+ {
+ if (node->dim(index).known())
+ output_tensor_shape.dim(index) = node->dim(index).value();
+ else
+ output_tensor_shape.dim(index).unset();
+ }
+
+ return loco::NodeShape(output_tensor_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFRealDiv *node) final { return binary_node_shape(node); }
+
+ loco::NodeShape visit(const moco::TFRelu *node) final
+ {
+ return node_shape_with_check(node->features());
+ }
+
+ loco::NodeShape visit(const moco::TFRelu6 *node) final
+ {
+ return node_shape_with_check(node->features());
+ }
+
+ loco::NodeShape visit(const moco::TFReshape *node) final
+ {
+ loco::NodeShape unknown;
+
+ // For now, we only consider Fixed Reshape, i.e. Reshape with determined
+ // 'shape' input. So here we only support case when 'shape' input of
+ // TFReshape is TFConst. If 'shape' input is not TFConst, another
+ // transform (e.g. constant folding) should be done beforehand to make
+ // it TFConst.
+ // TODO Support dynamic Reshape
+ // Note that 'shape()' here is 'shape' input, not node's shape information
+ auto const_shape_input = dynamic_cast<moco::TFConst *>(node->shape());
+ if (!const_shape_input)
+ {
+ // 'shape' input of TFReshape is not TFConst, we can not do shape inference
+ return unknown;
+ }
+
+ // 'Shape' input should be integer tensor of rank 1, e.g. [2, 3, 4] or [3, -1]
+ assert(const_shape_input->dtype() == loco::DataType::S32);
+ assert(const_shape_input->rank() == 1);
+
+ auto shape_rank = const_shape_input->dim(0).value();
+ assert(shape_rank > 0);
+
+ loco::TensorShape output_shape;
+ output_shape.rank(shape_rank);
+ for (uint32_t axis = 0; axis < shape_rank; ++axis)
+ {
+ auto shape_dim = const_shape_input->at<loco::DataType::S32>(axis);
+ if (shape_dim == -1)
+ {
+ // Reshape's new shape has wildcard dimension, i.e. dynamic reshape
+ return unknown;
+ }
+ assert(shape_dim >= 1);
+ output_shape.dim(axis) = shape_dim;
+ }
+
+ // TODO Compare 'tensor' input and validate coherency?
+ // Not sure this is appropriate stage for this task.
+
+ return loco::NodeShape(output_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFRsqrt *node) final
+ {
+ return node_shape_with_check(node->x());
+ }
+
+ loco::NodeShape visit(const moco::TFShape *node) final
+ {
+ auto input_shape = node_shape(node->input());
+ auto input_tensor_shape = input_shape.as<loco::TensorShape>();
+
+ loco::TensorShape output_shape;
+
+ // Note that input shape becomes node(TFShape)'s value
+ output_shape.rank(1);
+ output_shape.dim(0) = input_tensor_shape.rank();
+
+ return loco::NodeShape(output_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFSoftmax *node) final
+ {
+ return node_shape_with_check(node->logits());
+ }
+
+ loco::NodeShape visit(const moco::TFSqrt *node) final { return node_shape_with_check(node->x()); }
+
+ loco::NodeShape visit(const moco::TFSquaredDifference *node) final
+ {
+ return binary_node_shape(node);
+ }
+
+ loco::NodeShape visit(const moco::TFSqueeze *node) final
+ {
+ auto input_shape = node_shape(node->input());
+
+ // TODO Not sure Squeeze only get input as Tensor
+ // Note that tensor_shape() has assertion in it
+ auto input_tensor_shape = input_shape.as<loco::TensorShape>();
+
+ auto squeeze_dims_vec = node->squeeze_dims();
+ std::set<int64_t> squeeze_dims(squeeze_dims_vec.cbegin(), squeeze_dims_vec.cend());
+
+ loco::TensorShape output_shape;
+ uint32_t output_rank = 0;
+
+ if (squeeze_dims.empty())
+ {
+ // Remove all dimensions whose value is 1
+ for (uint32_t axis = 0; axis < input_tensor_shape.rank(); ++axis)
+ {
+ assert(input_tensor_shape.dim(axis).known());
+ auto dim = input_tensor_shape.dim(axis).value();
+ if (dim != 1)
+ {
+ assert(dim > 1);
+ output_shape.rank(++output_rank);
+ output_shape.dim(output_rank - 1) = dim;
+ }
+ }
+ }
+ else
+ {
+ uint32_t input_rank = input_tensor_shape.rank();
+
+ // Sanity check for 'squeeze_dims'
+ auto is_valid_squeeze_dims = [&squeeze_dims, &input_rank]() {
+ if (!(squeeze_dims.size() < input_rank))
+ return false;
+ for (auto squeeze_dim : squeeze_dims)
+ {
+ if (!(squeeze_dim >= -(int64_t)input_rank))
+ return false;
+ if (!(squeeze_dim < (int64_t)input_rank))
+ return false;
+ }
+ return true;
+ };
+
+ if (!is_valid_squeeze_dims())
+ {
+ throw oops::UserExn("Invalid squeeze dimension", node->name());
+ }
+
+ // Resolve negative squeeze dimension
+ std::set<int64_t> resolved_squeeze_dims;
+ for (auto squeeze_dim : squeeze_dims)
+ {
+ if (squeeze_dim < 0)
+ resolved_squeeze_dims.insert(squeeze_dim + (int64_t)input_rank);
+ else
+ resolved_squeeze_dims.insert(squeeze_dim);
+ }
+
+ // Remove squeeze dimensions only
+ for (uint32_t axis = 0; axis < input_rank; ++axis)
+ {
+ assert(input_tensor_shape.dim(axis).known());
+ auto dim = input_tensor_shape.dim(axis).value();
+ if (resolved_squeeze_dims.find((int64_t)axis) == resolved_squeeze_dims.cend())
+ {
+ // Not squeeze dim
+ output_shape.rank(++output_rank);
+ output_shape.dim(output_rank - 1) = dim;
+ }
+ else
+ {
+ // Is squeeze dim
+ assert(dim == 1);
+ // DO NOTHING
+ }
+ }
+ }
+
+ assert(output_shape.rank() > 0);
+
+ return loco::NodeShape(output_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFStopGradient *node) final
+ {
+ return node_shape_with_check(node->input());
+ }
+
+ loco::NodeShape visit(const moco::TFStridedSlice *node) final
+ {
+ loco::NodeShape unknown;
+ auto input_shape = node_shape(node->input());
+ if (input_shape.domain() != loco::Domain::Tensor)
+ {
+ // TODO fix this for other cases
+ // We support only tensor shape for now
+ return unknown;
+ }
+
+ // TODO support full mask features: see import codes also
+ // Limited attributes for now
+ assert(node->begin_mask() == 0);
+ assert(node->end_mask() == 0);
+ assert(node->ellipsis_mask() == 0);
+ assert(node->shrink_axis_mask() == 1);
+
+ auto const_begin = dynamic_cast<moco::TFConst *>(node->begin());
+ auto const_end = dynamic_cast<moco::TFConst *>(node->end());
+ auto const_strides = dynamic_cast<moco::TFConst *>(node->strides());
+
+ assert(dynamic_cast<moco::TFConst *>(node->input()) != nullptr);
+ assert(const_begin != nullptr);
+ assert(const_end != nullptr);
+ assert(const_strides != nullptr);
+
+ auto input_tensor_shape = input_shape.as<loco::TensorShape>();
+ auto input_rank = input_tensor_shape.rank();
+ auto output_rank = input_rank;
+
+ // TODO support strides with > 1
+ uint32_t elements = const_strides->size<loco::DataType::S32>();
+ for (uint32_t e = 0; e < elements; ++e)
+ assert(const_strides->at<loco::DataType::S32>(e) == 1);
+
+ // lets apply begin ~ end range from input shape
+ loco::TensorShape output_shape_range;
+
+ output_shape_range.rank(input_rank);
+ for (uint32_t r = 0; r < input_rank; ++r)
+ {
+ // TODO apply begin/end mask
+ // TODO apply ellipsis mask
+ // TODO apply strides
+ auto end = const_end->at<loco::DataType::S32>(r);
+ auto begin = const_begin->at<loco::DataType::S32>(r);
+ auto size = end - begin;
+ output_shape_range.dim(r).set(size);
+ }
+
+ // get final tensor shape from applying shrink mask to output_shape_range
+ loco::TensorShape output_tensor_shape;
+
+ if (node->shrink_axis_mask() != 0)
+ {
+ for (uint32_t rs = 0; rs < input_rank; ++rs)
+ {
+ int32_t bit = 1 << rs;
+ int32_t mask = node->shrink_axis_mask();
+ if (bit & mask)
+ {
+ // shrink one dimension
+ assert(output_rank > 0);
+ output_rank = output_rank - 1;
+ }
+ }
+ output_tensor_shape.rank(output_rank);
+ for (uint32_t rs = 0, rd = 0; rs < input_rank; ++rs)
+ {
+ int32_t bit = 1 << rs;
+ int32_t mask = node->shrink_axis_mask();
+ if ((bit & mask) == 0)
+ {
+ // use this dimension
+ output_tensor_shape.dim(rd).set(output_shape_range.dim(rs).value());
+ rd++;
+ }
+ // else this dimension is shrink-ed
+ }
+ }
+ else
+ {
+ output_tensor_shape = output_shape_range;
+ }
+
+ return loco::NodeShape(output_tensor_shape);
+ }
+
+ loco::NodeShape visit(const moco::TFSub *node) final { return binary_node_shape(node); }
+
+ loco::NodeShape visit(const moco::TFTanh *node) final { return node_shape_with_check(node->x()); }
+
+ // For virtual nodes
+ loco::NodeShape visit(const moco::TFPush *node) { return node_shape_with_check(node->from()); }
+
+public:
+ loco::NodeShape visit(const moco::TFNode *) final
+ {
+ loco::NodeShape unknown;
+ return unknown;
+ }
+};
+
+} // namespace
+
+namespace
+{
+namespace compat
+{
+
+struct Context final : public loco::ShapeInferenceRule::Context
+{
+ bool known(const loco::Node *node) const final { return loco::shape_known(node); }
+ loco::NodeShape get(const loco::Node *node) const final { return loco::shape_get(node); }
+};
+
+class Sink final : public loco::ShapeInferenceRule::Sink
+{
+public:
+ enum Status
+ {
+ Unknown,
+ Okay,
+ Fail,
+ };
+
+public:
+ const Status &status(void) const { return _status; }
+ const loco::NodeShape &shape(void) const { return _shape; }
+
+public:
+ void okay(const loco::NodeShape &shape) final
+ {
+ _status = Okay;
+ _shape = shape;
+ }
+
+ void fail(void) final
+ {
+ // Notify failrue
+ _status = Fail;
+ }
+
+private:
+ Status _status = Unknown;
+ loco::NodeShape _shape;
+};
+
+} // namespace compat
+} // namespace
+
+namespace moco
+{
+
+bool TFShapeInferenceRule::support(const API &api) const
+{
+ return api == API::V1 or api == API::V2;
+}
+
+bool TFShapeInferenceRule::recognize(const loco::Dialect *d) const
+{
+ // handle only TensorFlow dialect
+ return TFDialect::get() == d;
+}
+
+bool TFShapeInferenceRule::infer(const loco::Node *node, loco::NodeShape &shape) const
+{
+ ::compat::Context ctx;
+ ::compat::Sink sink;
+
+ infer(&ctx, node, &sink);
+
+ assert(sink.status() == ::compat::Sink::Okay or sink.status() == ::compat::Sink::Fail);
+
+ if (sink.status() == ::compat::Sink::Fail)
+ {
+ return false;
+ }
+
+ shape = sink.shape();
+
+ return true;
+}
+
+void TFShapeInferenceRule::infer(const Context *ctx, const loco::Node *node, Sink *sink) const
+{
+ assert(node->dialect() == TFDialect::get());
+ assert(dynamic_cast<const TFNode *>(node) != nullptr);
+
+ ShapeInferenceAlgorithm alg{ctx};
+ auto shape = dynamic_cast<const TFNode *>(node)->accept(&alg);
+
+ if (shape.domain() == loco::Domain::Unknown)
+ sink->fail();
+ else
+ sink->okay(shape);
+}
+
+} // namespace moco
diff --git a/compiler/moco/service/src/Service/TFShapeInferenceRule.test.cpp b/compiler/moco/service/src/Service/TFShapeInferenceRule.test.cpp
new file mode 100644
index 000000000..1e1b48ca7
--- /dev/null
+++ b/compiler/moco/service/src/Service/TFShapeInferenceRule.test.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Service/TFShapeInferenceRule.h"
+
+#include "TestHelper.h"
+
+#include "moco/IR/TFNodes.h"
+
+#include <loco.h>
+#include <loco/Service/ShapeInference.h>
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+moco::TFAvgPool *avgpool_network_simple1331(loco::Graph *graph)
+{
+ auto avgpool_node = graph->nodes()->create<moco::TFAvgPool>();
+
+ avgpool_node->data_layout("NHWC");
+ avgpool_node->ksize({1, 3, 3, 1});
+ avgpool_node->strides({1, 1, 1, 1});
+
+ // Dummy const node as ifm, just to fake TFShapeInferenceRule for TFAvgPool.
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+ {
+ const_node->rank(4);
+ const_node->dim(0).set(1);
+ const_node->dim(1).set(3);
+ const_node->dim(2).set(3);
+ const_node->dim(3).set(1);
+ }
+ avgpool_node->value(const_node);
+
+ setup_output_node(graph, avgpool_node);
+
+ return avgpool_node;
+}
+
+} // namespace
+
+TEST(TFShapeInferenceRule, avgpool_same)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto avgpool_node = avgpool_network_simple1331(&graph);
+ avgpool_node->padding("SAME");
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(avgpool_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+ ASSERT_EQ(tshape.rank(), 4);
+ ASSERT_EQ(tshape.dim(0).value(), 1);
+ ASSERT_EQ(tshape.dim(1).value(), 3);
+ ASSERT_EQ(tshape.dim(2).value(), 3);
+ ASSERT_EQ(tshape.dim(3).value(), 1);
+}
+
+TEST(TFShapeInferenceRule, avgpool_valid)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto avgpool_node = avgpool_network_simple1331(&graph);
+ avgpool_node->padding("VALID");
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(avgpool_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+ ASSERT_EQ(tshape.rank(), 4);
+ ASSERT_EQ(tshape.dim(0).value(), 1);
+ ASSERT_EQ(tshape.dim(1).value(), 1);
+ ASSERT_EQ(tshape.dim(2).value(), 1);
+ ASSERT_EQ(tshape.dim(3).value(), 1);
+}
+
+namespace
+{
+
+void conv2d_test(const std::array<uint32_t, 4> ifm_shape, const std::array<uint32_t, 4> ker_shape,
+ const std::array<uint32_t, 2> stride_h_w, std::string padding,
+ const std::array<uint32_t, 4> expected_shape)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto conv2d_node = graph.nodes()->create<moco::TFConv2D>();
+ conv2d_node->data_layout("NHWC");
+ conv2d_node->strides({1, stride_h_w[0], stride_h_w[1], 1});
+ conv2d_node->padding(padding);
+
+ auto ifm_node = graph.nodes()->create<moco::TFConst>();
+ {
+ ifm_node->rank(4);
+ ifm_node->dim(0).set(ifm_shape[0]);
+ ifm_node->dim(1).set(ifm_shape[1]);
+ ifm_node->dim(2).set(ifm_shape[2]);
+ ifm_node->dim(3).set(ifm_shape[3]);
+ }
+
+ auto ker_node = graph.nodes()->create<moco::TFConst>();
+ {
+ ker_node->rank(4);
+ ker_node->dim(0).set(ker_shape[0]);
+ ker_node->dim(1).set(ker_shape[1]);
+ ker_node->dim(2).set(ker_shape[2]);
+ ker_node->dim(3).set(ker_shape[3]);
+ }
+
+ conv2d_node->input(ifm_node);
+ conv2d_node->filter(ker_node);
+
+ setup_output_node(&graph, conv2d_node);
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(conv2d_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+ ASSERT_EQ(tshape.rank(), 4);
+ ASSERT_EQ(tshape.dim(0).value(), expected_shape[0]);
+ ASSERT_EQ(tshape.dim(1).value(), expected_shape[1]);
+ ASSERT_EQ(tshape.dim(2).value(), expected_shape[2]);
+ ASSERT_EQ(tshape.dim(3).value(), expected_shape[3]);
+}
+
+} // namespace
+
+/*
+ Testing "InceptionV3/InceptionV3/Conv2d_1a_3x3/Conv2D" Conv2D node in Inception_v3:
+ The result shape of this test is generated with the code below:
+
+ ifm = tf.constant(value=1.1, shape=[1, 299, 299, 3])
+ ker = tf.constant(value=1.1, shape=[3, 3, 3, 32])
+
+ out = tf.nn.conv2d(ifm, ker, strides = [1, 2, 2, 1], padding= 'VALID')
+
+ with tf.Session() as sess:
+ res = sess.run(out)
+ print(res.shape)
+ */
+TEST(TFShapeInferenceRule, conv2d_VALID)
+{
+ conv2d_test({1, 299, 299, 3}, // ifm
+ {3, 3, 3, 32}, // ker
+ {2, 2}, // strides
+ "VALID", // padding
+ {1, 149, 149, 32}); // expected shape after FixShape
+}
+
+/*
+ Testing "InceptionV3/InceptionV3/Conv2d_2b_3x3/Conv2D" Conv2D node in Inception_v3:
+ The result shape of this test is generated with the code below:
+
+ ifm = tf.constant(value=1.1, shape=[1, 147, 147, 32])
+ ker = tf.constant(value=1.1, shape=[3, 3, 32, 64])
+
+ out = tf.nn.conv2d(ifm, ker, strides = [1, 1, 1, 1], padding= 'SAME')
+
+ with tf.Session() as sess:
+ res = sess.run(out)
+ print(res.shape)
+ */
+TEST(TFShapeInferenceRule, conv2d_SAME)
+{
+ conv2d_test({1, 147, 147, 32}, // ifm
+ {3, 3, 32, 64}, // ker
+ {1, 1}, // strides
+ "SAME", // padding
+ {1, 147, 147, 64}); // expected shape after FixShape
+}
+
+/*
+ Testing Pack
+*/
+namespace
+{
+
+moco::TFConst *const_scalar(loco::Graph *graph, int32_t val)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(0);
+ const_node->size<loco::DataType::S32>(1);
+ const_node->at<loco::DataType::S32>(0) = val;
+
+ return const_node;
+}
+
+moco::TFConst *const_vector(loco::Graph *graph, int32_t dim)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(1);
+ const_node->dim(0).set(dim);
+
+ const_node->size<loco::DataType::S32>(dim);
+ for (int32_t i = 0; i < dim; ++i)
+ const_node->at<loco::DataType::S32>(i) = i;
+
+ return const_node;
+}
+
+moco::TFConst *const_vector_init(loco::Graph *graph, std::vector<int32_t> values)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+ auto dim = values.size();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(1);
+ const_node->dim(0).set(dim);
+
+ const_node->size<loco::DataType::S32>(dim);
+ for (int32_t i = 0; i < dim; ++i)
+ const_node->at<loco::DataType::S32>(i) = values[i];
+
+ return const_node;
+}
+
+moco::TFConst *const_matrix(loco::Graph *graph, int32_t dimh, int32_t dimw)
+{
+ auto const_node = graph->nodes()->create<moco::TFConst>();
+
+ const_node->dtype(loco::DataType::S32);
+ const_node->rank(2);
+ const_node->dim(0).set(dimh);
+ const_node->dim(1).set(dimw);
+
+ auto elements = dimh * dimw;
+ const_node->size<loco::DataType::S32>(elements);
+ for (int32_t i = 0; i < elements; ++i)
+ const_node->at<loco::DataType::S32>(i) = i;
+
+ return const_node;
+}
+
+} // namespace
+
+TEST(TFShapeInferenceRule, pack_scalar_2)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto pack_node = graph.nodes()->create<moco::TFPack>(2);
+ pack_node->axis(0);
+ {
+ auto const_node_0 = const_scalar(&graph, 1);
+ pack_node->values(0, const_node_0);
+ auto const_node_1 = const_scalar(&graph, 1);
+ pack_node->values(1, const_node_1);
+ }
+ setup_output_node(&graph, pack_node);
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(pack_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+ ASSERT_EQ(tshape.rank(), 1);
+ ASSERT_EQ(tshape.dim(0).value(), 2);
+}
+
+TEST(TFShapeInferenceRule, pack_vector3_2)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto pack_node = graph.nodes()->create<moco::TFPack>(2);
+ pack_node->axis(0);
+ {
+ auto const_node_0 = const_vector(&graph, 3);
+ pack_node->values(0, const_node_0);
+ auto const_node_1 = const_vector(&graph, 3);
+ pack_node->values(1, const_node_1);
+ }
+ setup_output_node(&graph, pack_node);
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(pack_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+
+ ASSERT_EQ(tshape.rank(), 2);
+ ASSERT_EQ(tshape.dim(0).value(), 2);
+ ASSERT_EQ(tshape.dim(1).value(), 3);
+}
+
+TEST(TFShapeInferenceRule, pack_vector3_2_axis_1)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto pack_node = graph.nodes()->create<moco::TFPack>(2);
+ pack_node->axis(1);
+ {
+ auto const_node_0 = const_vector(&graph, 3);
+ pack_node->values(0, const_node_0);
+ auto const_node_1 = const_vector(&graph, 3);
+ pack_node->values(1, const_node_1);
+ }
+ setup_output_node(&graph, pack_node);
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(pack_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+
+ ASSERT_EQ(tshape.rank(), 2);
+ ASSERT_EQ(tshape.dim(0).value(), 3);
+ ASSERT_EQ(tshape.dim(1).value(), 2);
+}
+
+TEST(TFShapeInferenceRule, pack_vector3_2_axis_m2)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto pack_node = graph.nodes()->create<moco::TFPack>(2);
+ pack_node->axis(-2);
+ {
+ auto const_node_0 = const_vector(&graph, 3);
+ pack_node->values(0, const_node_0);
+ auto const_node_1 = const_vector(&graph, 3);
+ pack_node->values(1, const_node_1);
+ }
+ setup_output_node(&graph, pack_node);
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(pack_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+
+ ASSERT_EQ(tshape.rank(), 2);
+ ASSERT_EQ(tshape.dim(0).value(), 2);
+ ASSERT_EQ(tshape.dim(1).value(), 3);
+}
+
+TEST(TFShapeInferenceRule, pack_vector3_2_axis_m3)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto pack_node = graph.nodes()->create<moco::TFPack>(2);
+ pack_node->axis(-3);
+ {
+ auto const_node_0 = const_vector(&graph, 3);
+ pack_node->values(0, const_node_0);
+ auto const_node_1 = const_vector(&graph, 3);
+ pack_node->values(1, const_node_1);
+ }
+ setup_output_node(&graph, pack_node);
+
+ // -3 is out of range and should throw
+ EXPECT_ANY_THROW(loco::apply(&shape_infer).to(&graph));
+}
+
+TEST(TFShapeInferenceRule, pack_matrix3x4_2_axis_1)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto pack_node = graph.nodes()->create<moco::TFPack>(2);
+ pack_node->axis(1);
+ {
+ auto const_node_0 = const_matrix(&graph, 3, 4);
+ pack_node->values(0, const_node_0);
+ auto const_node_1 = const_matrix(&graph, 3, 4);
+ pack_node->values(1, const_node_1);
+ }
+ setup_output_node(&graph, pack_node);
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(pack_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+
+ ASSERT_EQ(tshape.rank(), 3);
+ ASSERT_EQ(tshape.dim(0).value(), 3);
+ ASSERT_EQ(tshape.dim(1).value(), 2);
+ ASSERT_EQ(tshape.dim(2).value(), 4);
+}
+
+TEST(TFShapeInferenceRule, stridedslice_matrix5x5_shrink)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto sslice_node = graph.nodes()->create<moco::TFStridedSlice>();
+ {
+ auto const_input = const_matrix(&graph, 5, 5);
+ sslice_node->input(const_input);
+
+ auto const_begin = const_vector_init(&graph, {1, 1});
+ sslice_node->begin(const_begin);
+ auto const_end = const_vector_init(&graph, {2, 4});
+ sslice_node->end(const_end);
+ auto const_strides = const_vector_init(&graph, {1, 1});
+ sslice_node->strides(const_strides);
+
+ sslice_node->shrink_axis_mask(1);
+ }
+ setup_output_node(&graph, sslice_node);
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(sslice_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+
+ ASSERT_EQ(tshape.rank(), 1);
+ ASSERT_EQ(tshape.dim(0).value(), 3);
+}
+
+TEST(TFShapeInferenceRule, stridedslice_4_shrink)
+{
+ moco::TFShapeInferenceRule shape_infer;
+ loco::Graph graph;
+
+ auto sslice_node = graph.nodes()->create<moco::TFStridedSlice>();
+ {
+ auto const_input = const_vector(&graph, 4);
+ sslice_node->input(const_input);
+
+ auto const_begin = const_vector_init(&graph, {0});
+ sslice_node->begin(const_begin);
+ auto const_end = const_vector_init(&graph, {1});
+ sslice_node->end(const_end);
+ auto const_strides = const_vector_init(&graph, {1});
+ sslice_node->strides(const_strides);
+
+ sslice_node->shrink_axis_mask(1);
+ }
+ setup_output_node(&graph, sslice_node);
+
+ bool cont = true;
+ while (cont)
+ {
+ cont = loco::apply(&shape_infer).to(&graph);
+ };
+
+ auto nodeshape = loco::shape_get(sslice_node);
+ auto tshape = nodeshape.as<loco::TensorShape>();
+
+ ASSERT_EQ(tshape.rank(), 0);
+}
diff --git a/compiler/moco/service/src/Service/TFTypeInferenceRule.cpp b/compiler/moco/service/src/Service/TFTypeInferenceRule.cpp
new file mode 100644
index 000000000..112ab955d
--- /dev/null
+++ b/compiler/moco/service/src/Service/TFTypeInferenceRule.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Service/TFTypeInferenceRule.h"
+
+#include "moco/IR/TFDialect.h"
+#include "moco/IR/TFNodeVisitor.h"
+#include "moco/IR/TFNodes.h"
+
+#include "moco/IR/TFNodeImpl.h"
+
+#include <cassert>
+
+namespace
+{
+
+using namespace moco;
+
+struct TypeForwardAlgorithm final : public moco::TFNodeVisitor<loco::DataType>
+{
+ loco::DataType visit(const TFAdd *node) { return dtype_get(node->x()); }
+ loco::DataType visit(const TFAvgPool *node) { return dtype_get(node->value()); }
+ loco::DataType visit(const TFBiasAdd *node) { return dtype_get(node->value()); }
+ loco::DataType visit(const TFConcatV2 *node) { return dtype_get(node->values(0)); }
+
+ loco::DataType visit(const TFConst *node) { return node->dtype(); }
+
+ loco::DataType visit(const TFConv2D *node) { return dtype_get(node->input()); }
+ loco::DataType visit(const TFConv2DBackpropInput *node)
+ {
+ return dtype_get(node->out_backprop());
+ }
+ loco::DataType visit(const TFDepthwiseConv2dNative *node) { return dtype_get(node->input()); }
+ loco::DataType visit(const TFFakeQuantWithMinMaxVars *node) { return dtype_get(node->inputs()); }
+ loco::DataType visit(const TFFusedBatchNorm *node) { return dtype_get(node->x()); }
+ loco::DataType visit(const TFIdentity *node) { return dtype_get(node->input()); }
+ loco::DataType visit(const TFMaximum *node) { return dtype_get(node->x()); }
+ loco::DataType visit(const TFMaxPool *node) { return dtype_get(node->input()); }
+ loco::DataType visit(const TFMean *node) { return dtype_get(node->input()); }
+ loco::DataType visit(const TFMul *node) { return dtype_get(node->x()); }
+ loco::DataType visit(const TFPack *node) { return dtype_get(node->values(0)); }
+ loco::DataType visit(const TFPad *node) { return dtype_get(node->input()); }
+
+ loco::DataType visit(const TFPlaceholder *node) { return node->dtype(); }
+
+ loco::DataType visit(const TFRealDiv *node) { return dtype_get(node->x()); }
+ loco::DataType visit(const TFRelu *node) { return dtype_get(node->features()); }
+ loco::DataType visit(const TFRelu6 *node) { return dtype_get(node->features()); }
+ loco::DataType visit(const TFReshape *node) { return dtype_get(node->tensor()); }
+ loco::DataType visit(const TFRsqrt *node) { return dtype_get(node->x()); }
+
+ loco::DataType visit(const TFShape *node) { return node->dtype(); }
+
+ loco::DataType visit(const TFSoftmax *node) { return dtype_get(node->logits()); }
+ loco::DataType visit(const TFSqrt *node) { return dtype_get(node->x()); }
+ loco::DataType visit(const TFSquaredDifference *node) { return dtype_get(node->x()); }
+ loco::DataType visit(const TFSqueeze *node) { return dtype_get(node->input()); }
+ loco::DataType visit(const TFStopGradient *node) { return dtype_get(node->input()); }
+ loco::DataType visit(const TFStridedSlice *node) { return dtype_get(node->input()); }
+ loco::DataType visit(const TFSub *node) { return dtype_get(node->x()); }
+ loco::DataType visit(const TFTanh *node) { return dtype_get(node->x()); }
+
+ // For virtual nodes
+ loco::DataType visit(const TFPush *node) { return dtype_get(node->from()); }
+};
+
+} // namespace
+
+namespace moco
+{
+
+bool TFTypeInferenceRule::recognize(const loco::Dialect *d) const
+{
+ // This rule recognizes only "TFDialect" dialect!
+ return TFDialect::get() == d;
+}
+
+bool TFTypeInferenceRule::infer(const loco::Node *node, loco::DataType &dtype) const
+{
+ assert(node->dialect() == TFDialect::get());
+
+ TypeForwardAlgorithm alg;
+
+// clang-format off
+#define TENSORFLOW_NODE(OPCODE,CLASS) \
+ if (dynamic_cast<const moco::CLASS *>(node)) \
+ { \
+ auto tfnode = dynamic_cast<const moco::CLASS *>(node); \
+ dtype = tfnode->accept(&alg); \
+ assert(dtype != loco::DataType::Unknown); \
+ return true; \
+ }
+#include "moco/IR/TFNodes.lst"
+#undef TENSORFLOW_NODE
+ // clang-format on
+
+ return false;
+}
+
+} // namespace moco
diff --git a/compiler/moco/service/src/TestHelper.h b/compiler/moco/service/src/TestHelper.h
new file mode 100644
index 000000000..8f3ff764e
--- /dev/null
+++ b/compiler/moco/service/src/TestHelper.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 __TEST_HELPER_H__
+#define __TEST_HELPER_H__
+
+#include <loco.h>
+
+namespace moco
+{
+namespace test
+{
+
+template <typename T> T *find_first_node_bytype(loco::Graph *g)
+{
+ T *first_node = nullptr;
+ loco::Graph::NodeContext *nodes = g->nodes();
+ uint32_t count = nodes->size();
+
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ first_node = dynamic_cast<T *>(nodes->at(i));
+ if (first_node != nullptr)
+ break;
+ }
+
+ return first_node;
+}
+
+template <typename T> std::vector<T *> find_nodes_bytype(loco::Graph *g)
+{
+ std::vector<T *> find_nodes;
+ loco::Graph::NodeContext *nodes = g->nodes();
+ uint32_t count = nodes->size();
+
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ auto node = dynamic_cast<T *>(nodes->at(i));
+ if (node != nullptr)
+ find_nodes.push_back(node);
+ }
+
+ return find_nodes;
+}
+
+/**
+ * @brief Append setup output of graph by adding loco::Push node
+ *
+ * @note This is subject to change when loco changes I/O treatment
+ */
+void setup_output_node(loco::Graph *graph, loco::Node *last_node);
+
+} // namespace test
+} // namespace moco
+
+#endif // __TEST_HELPER_H__
diff --git a/compiler/moco/service/src/TestHelper.test.cpp b/compiler/moco/service/src/TestHelper.test.cpp
new file mode 100644
index 000000000..59915d60f
--- /dev/null
+++ b/compiler/moco/service/src/TestHelper.test.cpp
@@ -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 "TestHelper.h"
+
+namespace moco
+{
+namespace test
+{
+
+void setup_output_node(loco::Graph *graph, loco::Node *last_node)
+{
+ // add push as output
+ auto push_node = graph->nodes()->create<loco::Push>();
+ push_node->from(last_node);
+
+ // set the graph output name and node object
+ auto graph_output = graph->outputs()->create();
+ graph_output->name("output");
+ graph_output->dtype(loco::DataType::FLOAT32);
+ loco::link(graph_output, push_node);
+}
+
+} // namespace test
+} // namespace moco
diff --git a/compiler/moco/support/CMakeLists.txt b/compiler/moco/support/CMakeLists.txt
new file mode 100644
index 000000000..2a896d495
--- /dev/null
+++ b/compiler/moco/support/CMakeLists.txt
@@ -0,0 +1,9 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(moco_support SHARED ${SOURCES})
+target_include_directories(moco_support PRIVATE src)
+target_include_directories(moco_support PUBLIC include)
+target_link_libraries(moco_support PUBLIC loco)
+target_link_libraries(moco_support PUBLIC moco_lang)
+target_link_libraries(moco_support PRIVATE oops)
+install(TARGETS moco_support DESTINATION lib)
diff --git a/compiler/moco/support/README.md b/compiler/moco/support/README.md
new file mode 100644
index 000000000..081f65d39
--- /dev/null
+++ b/compiler/moco/support/README.md
@@ -0,0 +1,3 @@
+# support
+
+_support_ privides _moco_ support libraries
diff --git a/compiler/moco/support/include/moco/Support/NodeAs.h b/compiler/moco/support/include/moco/Support/NodeAs.h
new file mode 100644
index 000000000..dc78ff94a
--- /dev/null
+++ b/compiler/moco/support/include/moco/Support/NodeAs.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_SUPPORT_NODE_AS_H__
+#define __MOCO_SUPPORT_NODE_AS_H__
+
+#include <loco.h>
+
+namespace moco
+{
+
+template <typename DERIVED> DERIVED *as(loco::Node *node) { return dynamic_cast<DERIVED *>(node); }
+
+} // namespace moco
+
+#endif // __MOCO_SUPPORT_NODE_AS_H__
diff --git a/compiler/moco/support/include/moco/Support/TFShapeInferenceHelper.h b/compiler/moco/support/include/moco/Support/TFShapeInferenceHelper.h
new file mode 100644
index 000000000..52324700a
--- /dev/null
+++ b/compiler/moco/support/include/moco/Support/TFShapeInferenceHelper.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MOCO_SUPPORT_SHAPE_INFERENCE_HELPER_H__
+#define __MOCO_SUPPORT_SHAPE_INFERENCE_HELPER_H__
+
+#include <moco/IR/TFDataLayout.h>
+#include <moco/IR/TFPadding.h>
+
+#include <loco.h>
+#include <loco/IR/NodeShape.h>
+#include <loco/IR/Padding2D.h>
+#include <loco/IR/Stride.h>
+#include <loco/IR/Window.h>
+
+#include <cassert>
+
+namespace moco
+{
+
+/**
+ * @note Helper for return broadcasted shape for binary operators having
+ * different shape for input x and y
+ */
+loco::TensorShape broadcast_shape(const loco::TensorShape &x, const loco::TensorShape &y);
+
+} // namespace moco
+
+namespace moco
+{
+
+/**
+ * @brief Return true if node has shape inference data for checking shape
+ * inference is done or not
+ *
+ * @note Will be deprecated in near future
+ */
+bool shape_inference_done(const loco::Node *node);
+
+/**
+ * @note While in shape inference, Node maybe Canonical, TF dialect or other dialects
+ * This will provide common loco::NodeShape as shape information
+ */
+loco::NodeShape node_shape(const loco::Node *node);
+bool node_shape(const loco::Node *node, loco::NodeShape &nodeshape);
+
+loco::TensorShape as_tensor_shape(const loco::FeatureShape &feature_shape,
+ const TFDataLayout &data_layout);
+
+loco::FeatureShape as_feature_shape(const loco::NodeShape &nodeshape,
+ const TFDataLayout &data_layout);
+
+} // namespace moco
+
+namespace moco
+{
+
+struct PlaneShape
+{
+ loco::Dimension height;
+ loco::Dimension width;
+};
+
+class FeatureShapeUpdater final
+{
+public:
+ FeatureShapeUpdater(loco::FeatureShape *ptr) : _feature_shape_ptr{ptr}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void with(const PlaneShape &plane_shape) const
+ {
+ _feature_shape_ptr->height() = plane_shape.height;
+ _feature_shape_ptr->width() = plane_shape.width;
+ }
+
+private:
+ loco::FeatureShape *_feature_shape_ptr;
+};
+
+PlaneShape make_plane_shape(const loco::FeatureShape &feature_shape);
+
+FeatureShapeUpdater update(loco::FeatureShape &feature_shape);
+
+class PlaneInference
+{
+protected:
+ struct Parameters
+ {
+ PlaneShape input;
+ PlaneShape stride;
+ PlaneShape window;
+ PlaneShape dilation;
+ PlaneShape effective_window;
+ PlaneShape output;
+ };
+
+ void fill(Parameters &p, const PlaneShape &in)
+ {
+ p.input.height = in.height;
+ p.input.width = in.width;
+
+ p.stride.height = _stride.vertical();
+ p.stride.width = _stride.horizontal();
+
+ p.window.height = _window.vertical();
+ p.window.width = _window.horizontal();
+
+ // TODO support dilation
+ p.dilation.height = 1;
+ p.dilation.width = 1;
+
+ p.effective_window.height = p.dilation.height.value() * (p.window.height.value() - 1) + 1;
+ p.effective_window.width = p.dilation.width.value() * (p.window.width.value() - 1) + 1;
+ }
+
+ PlaneShape infer(const Parameters &p, const PlaneShape &)
+ {
+ PlaneShape res;
+
+ if (_padding == "VALID")
+ {
+ res.height =
+ (p.input.height.value() + p.stride.height.value() - p.effective_window.height.value()) /
+ p.stride.height.value();
+ res.width =
+ (p.input.width.value() + p.stride.width.value() - p.effective_window.width.value()) /
+ p.stride.width.value();
+ }
+ else if (_padding == "SAME")
+ {
+ res.height = (p.input.height.value() + p.stride.height.value() - 1) / p.stride.height.value();
+ res.width = (p.input.width.value() + p.stride.width.value() - 1) / p.stride.width.value();
+ }
+ else
+ assert(false);
+
+ return res;
+ }
+
+public:
+ PlaneShape operator()(const PlaneShape &in)
+ {
+ Parameters p;
+
+ fill(p, in);
+
+ return infer(p, in);
+ }
+
+public:
+ void padding(const TFPadding &value) { _padding = value; }
+ void window(const loco::Window<2> value) { _window = value; }
+ void stride(const loco::Stride<2> value) { _stride = value; }
+
+private:
+ TFPadding _padding;
+ loco::Window<2> _window;
+ loco::Stride<2> _stride;
+};
+
+class Padding2DInference final : public PlaneInference
+{
+public:
+ loco::Padding2D operator()(const PlaneShape &in)
+ {
+ Parameters p;
+
+ fill(p, in);
+
+ auto output = infer(p, in);
+
+ int64_t i_height = (int64_t)(output.height.value() - 1) * (int64_t)p.stride.height.value() +
+ (int64_t)p.effective_window.height.value() - (int64_t)p.input.height.value();
+ int64_t i_width = (int64_t)(output.width.value() - 1) * (int64_t)p.stride.width.value() +
+ (int64_t)p.effective_window.width.value() - (int64_t)p.input.width.value();
+
+ uint32_t pad_height = i_height >= 0 ? (uint32_t)i_height : 0U;
+ uint32_t pad_width = i_width >= 0 ? (uint32_t)i_width : 0U;
+
+ loco::Padding2D padding2d;
+
+ padding2d.top(pad_height / 2);
+ padding2d.bottom(pad_height - padding2d.top());
+ padding2d.left(pad_width / 2);
+ padding2d.right(pad_width - padding2d.left());
+
+ return padding2d;
+ }
+};
+
+} // namespace moco
+
+namespace moco
+{
+
+using TFStrides = std::vector<int64_t>;
+using TFKSize = std::vector<int64_t>;
+
+loco::Stride<2> stride_of(const TFStrides &strides, const TFDataLayout &datalayout);
+loco::Window<2> window_of(const TFKSize &ksize, const TFDataLayout &datalayout);
+loco::Window<2> window_of(const loco::TensorShape &shape, const TFDataLayout &datalayout);
+
+} // namespace moco
+
+#endif // __MOCO_SERVICE_SHAPE_INFERENCE_HELPER_H__
diff --git a/compiler/moco/support/src/TFShapeInferenceHelper.cpp b/compiler/moco/support/src/TFShapeInferenceHelper.cpp
new file mode 100644
index 000000000..13e514a78
--- /dev/null
+++ b/compiler/moco/support/src/TFShapeInferenceHelper.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "moco/Support/TFShapeInferenceHelper.h"
+
+#include <loco/Service/ShapeInference.h>
+
+#include <oops/InternalExn.h>
+
+#include <cassert>
+
+namespace
+{
+
+// TODO Use codes in loco and remove duplicate broadcast_shape() and related
+/**
+ * @brief Create a higher-rank TensorShape following NumPy broadcasting semantics
+ *
+ * HOW TO USE:
+ *
+ * auto expanded_tensor_shape = expand(tensor_shape).to(N);
+ */
+class TensorShapeExpander
+{
+public:
+ TensorShapeExpander(const loco::TensorShape &shape) : _shape{shape}
+ {
+ // DO NOTHING
+ }
+
+public:
+ loco::TensorShape to(uint32_t output_rank)
+ {
+ auto const &input_shape = _shape;
+ uint32_t const input_rank = input_shape.rank();
+
+ assert(input_rank <= output_rank && "Cannot shrink rank");
+ uint32_t const axis_shift = output_rank - input_rank;
+
+ loco::TensorShape output_shape;
+
+ output_shape.rank(output_rank);
+ for (uint32_t axis = 0; axis < output_rank; ++axis)
+ {
+ output_shape.dim(axis) = (axis < axis_shift) ? 1 : input_shape.dim(axis - axis_shift);
+ }
+
+ return output_shape;
+ }
+
+private:
+ const loco::TensorShape _shape;
+};
+
+/**
+ * @breif Expand shape x and y to same rank by align right and filling with 1
+ */
+void expand_rank(loco::TensorShape &x, loco::TensorShape &y)
+{
+ auto x_rank = x.rank();
+ auto y_rank = y.rank();
+
+ if (x_rank == y_rank)
+ return;
+
+ TensorShapeExpander x_exp(x);
+ TensorShapeExpander y_exp(y);
+
+ auto xy_rank = std::max(x_rank, y_rank);
+
+ x = x_rank > y_rank ? x : x_exp.to(xy_rank);
+ y = y_rank > x_rank ? y : y_exp.to(xy_rank);
+}
+
+/**
+ * @breif Returns shape of expanded dimension of input x and y having same rank
+ */
+loco::TensorShape expand_dimension(const loco::TensorShape &x, const loco::TensorShape &y)
+{
+ assert(x.rank() == y.rank());
+
+ auto rank = x.rank();
+
+ loco::TensorShape output_shape;
+
+ output_shape.rank(rank);
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ assert(x.dim(axis).known() && y.dim(axis).known());
+
+ auto x_dim = x.dim(axis).value();
+ auto y_dim = y.dim(axis).value();
+
+ // each dimension of x and y should be same or one must be 1 if different
+ if (!((x_dim == y_dim) || (x_dim == 1 || y_dim == 1)))
+ {
+ // TODO may need to refine message
+ INTERNAL_EXN("ShapeInference: Input shapes don't match");
+ }
+
+ output_shape.dim(axis) = std::max(x_dim, y_dim);
+ }
+
+ return output_shape;
+}
+
+} // namespace
+
+namespace moco
+{
+
+loco::TensorShape broadcast_shape(const loco::TensorShape &x, const loco::TensorShape &y)
+{
+ auto x_match = x;
+ auto y_match = y;
+
+ expand_rank(x_match, y_match);
+
+ auto output_shape = expand_dimension(x_match, y_match);
+
+ return output_shape;
+}
+
+} // namespace moco
+
+namespace moco
+{
+
+loco::NodeShape node_shape(const loco::Node *node)
+{
+ loco::NodeShape nodeshape; // default domain is Unknown
+
+ if (loco::shape_known(node))
+ {
+ nodeshape = loco::shape_get(node);
+ }
+
+ return nodeshape;
+}
+
+bool node_shape(const loco::Node *node, loco::NodeShape &nodeshape)
+{
+ nodeshape = node_shape(node);
+ return (nodeshape.domain() != loco::Domain::Unknown);
+}
+
+loco::TensorShape as_tensor_shape(const loco::FeatureShape &feature_shape,
+ const TFDataLayout &data_layout)
+{
+ loco::TensorShape tensor_shape;
+
+ tensor_shape.rank(4);
+ if (data_layout == "NHWC")
+ {
+ tensor_shape.dim(0) = feature_shape.count();
+ tensor_shape.dim(1) = feature_shape.height();
+ tensor_shape.dim(2) = feature_shape.width();
+ tensor_shape.dim(3) = feature_shape.depth();
+ }
+ else if (data_layout == "NCHW")
+ {
+ tensor_shape.dim(0) = feature_shape.count();
+ tensor_shape.dim(1) = feature_shape.depth();
+ tensor_shape.dim(2) = feature_shape.height();
+ tensor_shape.dim(3) = feature_shape.width();
+ }
+ else
+ {
+ // TODO support for other data_layout if needed
+ INTERNAL_EXN_V("ShapeInference: Unknown data_format", data_layout);
+ }
+
+ return tensor_shape;
+}
+
+loco::FeatureShape as_feature_shape(const loco::NodeShape &nodeshape,
+ const TFDataLayout &data_layout)
+{
+ if (nodeshape.domain() == loco::Domain::Feature)
+ return nodeshape.as<loco::FeatureShape>();
+
+ loco::FeatureShape feature_shape;
+
+ // only convert from tensor to feature
+ if (nodeshape.domain() != loco::Domain::Tensor)
+ {
+ INTERNAL_EXN("ShapeInference: Invalid shape information");
+ }
+
+ loco::TensorShape tensor_shape = nodeshape.as<loco::TensorShape>();
+
+ if (tensor_shape.rank() != 4)
+ {
+ INTERNAL_EXN("ShapeInference: Rank is not 4");
+ }
+
+ if (data_layout == "NHWC")
+ {
+ feature_shape.count() = tensor_shape.dim(0);
+ feature_shape.height() = tensor_shape.dim(1);
+ feature_shape.width() = tensor_shape.dim(2);
+ feature_shape.depth() = tensor_shape.dim(3);
+ }
+ else if (data_layout == "NCHW")
+ {
+ feature_shape.count() = tensor_shape.dim(0);
+ feature_shape.depth() = tensor_shape.dim(1);
+ feature_shape.height() = tensor_shape.dim(2);
+ feature_shape.width() = tensor_shape.dim(3);
+ }
+ else
+ {
+ // TODO support for other data_layout if needed
+ INTERNAL_EXN_V("ShapeInference: Unknown data_format", data_layout);
+ }
+
+ return feature_shape;
+}
+
+} // namespace moco
+
+namespace moco
+{
+
+PlaneShape make_plane_shape(const loco::FeatureShape &feature_shape)
+{
+ PlaneShape plane_shape;
+
+ plane_shape.height = feature_shape.height();
+ plane_shape.width = feature_shape.width();
+
+ return plane_shape;
+}
+
+FeatureShapeUpdater update(loco::FeatureShape &feature_shape)
+{
+ return FeatureShapeUpdater{&feature_shape};
+}
+
+} // namespace moco
+
+namespace
+{
+
+/**
+ * @brief Class to represent TensorFlow "data_format" attr.
+ */
+enum class DataLayout
+{
+ NHWC,
+ NCHW,
+};
+
+DataLayout as_data_layout(const std::string &tf_layout_str)
+{
+ if (tf_layout_str == "NHWC")
+ return DataLayout::NHWC;
+ else if (tf_layout_str == "NCHW")
+ return DataLayout::NCHW;
+ else
+ /// @note data layout tag in TensorFlow is 'data_format'
+ INTERNAL_EXN_V("ShapeInference: Unknown data_format", tf_layout_str);
+}
+
+} // namespace
+
+namespace moco
+{
+
+loco::Stride<2> stride_of(const TFStrides &strides, const TFDataLayout &datalayout)
+{
+ loco::Stride<2> stride;
+
+ auto data_layout = as_data_layout(datalayout);
+ if (data_layout == DataLayout::NHWC)
+ {
+ stride.vertical(strides[1]);
+ stride.horizontal(strides[2]);
+ }
+ else if (data_layout == DataLayout::NCHW)
+ {
+ stride.vertical(strides[2]);
+ stride.horizontal(strides[3]);
+ }
+ else
+ {
+ // TODO add more datalayout supports if needed
+ INTERNAL_EXN("ShapeInference: Unknown data_format");
+ }
+
+ return stride;
+}
+
+loco::Window<2> window_of(const TFKSize &ksize, const TFDataLayout &datalayout)
+{
+ loco::Window<2> window;
+
+ auto data_layout = as_data_layout(datalayout);
+ if (data_layout == DataLayout::NHWC)
+ {
+ window.vertical(ksize[1]);
+ window.horizontal(ksize[2]);
+ }
+ else if (data_layout == DataLayout::NCHW)
+ {
+ window.vertical(ksize[2]);
+ window.horizontal(ksize[3]);
+ }
+ else
+ {
+ // TODO add more datalayout supports if needed
+ INTERNAL_EXN("ShapeInference: Unknown data_format");
+ }
+
+ return window;
+}
+
+loco::Window<2> window_of(const loco::TensorShape &shape, const TFDataLayout &datalayout)
+{
+ loco::Window<2> window;
+
+ if (datalayout == "HWIO")
+ {
+ window.vertical(shape.dim(0).value());
+ window.horizontal(shape.dim(1).value());
+ }
+ else if (datalayout == "HWCM")
+ {
+ window.vertical(shape.dim(0).value());
+ window.horizontal(shape.dim(1).value());
+ }
+ else
+ {
+ // TODO add more datalayout supports if needed
+ INTERNAL_EXN_V("ShapeInference: Unknown data_format", datalayout);
+ }
+
+ return window;
+}
+
+} // namespace moco