summaryrefslogtreecommitdiff
path: root/compiler/luci
diff options
context:
space:
mode:
authorChunseok Lee <chunseok.lee@samsung.com>2020-07-30 11:32:26 +0900
committerChunseok Lee <chunseok.lee@samsung.com>2020-07-30 11:32:26 +0900
commit05e0ec30a632339a8533082476f27bda31ccde16 (patch)
tree5f220ac83084fe133ffb08a6a17e99f9bb36ec1c /compiler/luci
parente2ef8438a24f7c56a0744eb579a6e293ee2fbf8e (diff)
downloadnnfw-05e0ec30a632339a8533082476f27bda31ccde16.tar.gz
nnfw-05e0ec30a632339a8533082476f27bda31ccde16.tar.bz2
nnfw-05e0ec30a632339a8533082476f27bda31ccde16.zip
Imported Upstream version 1.7.0upstream/1.7.0
Diffstat (limited to 'compiler/luci')
-rw-r--r--compiler/luci/CMakeLists.txt1
-rw-r--r--compiler/luci/env/CMakeLists.txt18
-rw-r--r--compiler/luci/env/README.md3
-rw-r--r--compiler/luci/env/include/luci/UserSettings.h45
-rw-r--r--compiler/luci/env/src/UserSettings.cpp77
-rw-r--r--compiler/luci/env/src/UserSettings.test.cpp68
-rw-r--r--compiler/luci/export/CMakeLists.txt1
-rw-r--r--compiler/luci/export/src/CircleExporterImpl.cpp59
-rw-r--r--compiler/luci/export/src/CircleExporterUtils.cpp35
-rw-r--r--compiler/luci/export/src/CircleExporterUtils.h1
-rw-r--r--compiler/luci/export/src/CircleOperationExporter.cpp1205
-rw-r--r--compiler/luci/export/src/CircleTensorExporter.cpp179
-rw-r--r--compiler/luci/export/src/ProgressReporter.cpp28
-rw-r--r--compiler/luci/export/src/SerializedData.h23
-rw-r--r--compiler/luci/export/src/TypeBridge.cpp105
-rw-r--r--compiler/luci/export/src/TypeBridge.h44
-rw-r--r--compiler/luci/import/CMakeLists.txt1
-rw-r--r--compiler/luci/import/include/luci/Import/CircleReader.h13
-rw-r--r--compiler/luci/import/include/luci/Import/GraphBuilder.h18
-rw-r--r--compiler/luci/import/include/luci/Import/GraphBuilderBase.h48
-rw-r--r--compiler/luci/import/include/luci/Import/GraphBuilderContext.h23
-rw-r--r--compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h12
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes.h80
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleAddN.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleArgMin.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleBCQFullyConnected.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleBCQGather.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleBatchMatMul.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleCast.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleCeil.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleCustom.h35
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleDepthToSpace.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleElu.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleExpandDims.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleFill.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleFloor.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleFloorDiv.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleFloorMod.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleGather.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleGatherNd.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleGreater.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleGreaterEqual.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleIf.h35
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleInstanceNorm.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleL2Normalize.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleL2Pool2D.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleLeakyRelu.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleLess.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleLessEqual.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleLocalResponseNormalization.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleLog.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleLogSoftmax.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleLogicalAnd.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleLogistic.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleMatrixDiag.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleMatrixSetDiag.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleMaximum.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleMinimum.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleMirrorPad.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleNeg.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleNotEqual.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleOneHot.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CirclePRelu.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CirclePow.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleRange.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleRank.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleReduceAny.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleReduceMax.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleReduceMin.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleReduceProd.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleRelu6.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleReluN1To1.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleResizeBilinear.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleResizeNearestNeighbor.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleReverseSequence.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleReverseV2.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleRound.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleScatterNd.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSegmentSum.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSelect.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSelectV2.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleShape.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSin.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSlice.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToBatchND.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToDepth.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSparseToDense.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSplit.h35
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSplitV.h35
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSqrt.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSquare.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSquaredDifference.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSqueeze.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleStridedSlice.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleSum.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleTanh.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleTile.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleTopKV2.h35
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleTransposeConv.h37
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleUnpack.h35
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleWhere.h36
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleWhile.h35
-rw-r--r--compiler/luci/import/include/luci/Import/Nodes/CircleZerosLike.h37
-rw-r--r--compiler/luci/import/include/luci/Importer.h2
-rw-r--r--compiler/luci/import/src/CircleReader.cpp43
-rw-r--r--compiler/luci/import/src/GraphBuilder.cpp37
-rw-r--r--compiler/luci/import/src/GraphBuilderContext.cpp23
-rw-r--r--compiler/luci/import/src/GraphBuilderRegistry.cpp209
-rw-r--r--compiler/luci/import/src/Importer.cpp113
-rw-r--r--compiler/luci/import/src/Nodes/CircleAddN.cpp50
-rw-r--r--compiler/luci/import/src/Nodes/CircleArgMin.cpp48
-rw-r--r--compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp62
-rw-r--r--compiler/luci/import/src/Nodes/CircleBCQGather.cpp52
-rw-r--r--compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp47
-rw-r--r--compiler/luci/import/src/Nodes/CircleCast.cpp99
-rw-r--r--compiler/luci/import/src/Nodes/CircleCeil.cpp50
-rw-r--r--compiler/luci/import/src/Nodes/CircleConst.cpp108
-rw-r--r--compiler/luci/import/src/Nodes/CircleConv2D.cpp3
-rw-r--r--compiler/luci/import/src/Nodes/CircleCustom.cpp88
-rw-r--r--compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp67
-rw-r--r--compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp3
-rw-r--r--compiler/luci/import/src/Nodes/CircleElu.cpp64
-rw-r--r--compiler/luci/import/src/Nodes/CircleExp.cpp4
-rw-r--r--compiler/luci/import/src/Nodes/CircleExpandDims.cpp51
-rw-r--r--compiler/luci/import/src/Nodes/CircleFill.cpp49
-rw-r--r--compiler/luci/import/src/Nodes/CircleFloor.cpp50
-rw-r--r--compiler/luci/import/src/Nodes/CircleFloorDiv.cpp68
-rw-r--r--compiler/luci/import/src/Nodes/CircleFloorMod.cpp57
-rw-r--r--compiler/luci/import/src/Nodes/CircleFullyConnected.cpp12
-rw-r--r--compiler/luci/import/src/Nodes/CircleGather.cpp68
-rw-r--r--compiler/luci/import/src/Nodes/CircleGatherNd.cpp64
-rw-r--r--compiler/luci/import/src/Nodes/CircleGreater.cpp76
-rw-r--r--compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp62
-rw-r--r--compiler/luci/import/src/Nodes/CircleIf.cpp138
-rw-r--r--compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp52
-rw-r--r--compiler/luci/import/src/Nodes/CircleL2Normalize.cpp56
-rw-r--r--compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp54
-rw-r--r--compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp50
-rw-r--r--compiler/luci/import/src/Nodes/CircleLess.cpp78
-rw-r--r--compiler/luci/import/src/Nodes/CircleLessEqual.cpp62
-rw-r--r--compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp51
-rw-r--r--compiler/luci/import/src/Nodes/CircleLog.cpp65
-rw-r--r--compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp46
-rw-r--r--compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp55
-rw-r--r--compiler/luci/import/src/Nodes/CircleLogistic.cpp66
-rw-r--r--compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp56
-rw-r--r--compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp57
-rw-r--r--compiler/luci/import/src/Nodes/CircleMaximum.cpp72
-rw-r--r--compiler/luci/import/src/Nodes/CircleMinimum.cpp72
-rw-r--r--compiler/luci/import/src/Nodes/CircleMirrorPad.cpp50
-rw-r--r--compiler/luci/import/src/Nodes/CircleNeg.cpp44
-rw-r--r--compiler/luci/import/src/Nodes/CircleNotEqual.cpp62
-rw-r--r--compiler/luci/import/src/Nodes/CircleOneHot.cpp77
-rw-r--r--compiler/luci/import/src/Nodes/CirclePRelu.cpp50
-rw-r--r--compiler/luci/import/src/Nodes/CirclePow.cpp50
-rw-r--r--compiler/luci/import/src/Nodes/CircleRange.cpp46
-rw-r--r--compiler/luci/import/src/Nodes/CircleRank.cpp46
-rw-r--r--compiler/luci/import/src/Nodes/CircleReduceAny.cpp69
-rw-r--r--compiler/luci/import/src/Nodes/CircleReduceMax.cpp64
-rw-r--r--compiler/luci/import/src/Nodes/CircleReduceMin.cpp64
-rw-r--r--compiler/luci/import/src/Nodes/CircleReduceProd.cpp64
-rw-r--r--compiler/luci/import/src/Nodes/CircleRelu6.cpp47
-rw-r--r--compiler/luci/import/src/Nodes/CircleReluN1To1.cpp49
-rw-r--r--compiler/luci/import/src/Nodes/CircleReshape.cpp12
-rw-r--r--compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp51
-rw-r--r--compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp49
-rw-r--r--compiler/luci/import/src/Nodes/CircleReverseSequence.cpp71
-rw-r--r--compiler/luci/import/src/Nodes/CircleReverseV2.cpp67
-rw-r--r--compiler/luci/import/src/Nodes/CircleRound.cpp71
-rw-r--r--compiler/luci/import/src/Nodes/CircleScatterNd.cpp58
-rw-r--r--compiler/luci/import/src/Nodes/CircleSegmentSum.cpp68
-rw-r--r--compiler/luci/import/src/Nodes/CircleSelect.cpp56
-rw-r--r--compiler/luci/import/src/Nodes/CircleSelectV2.cpp60
-rw-r--r--compiler/luci/import/src/Nodes/CircleShape.cpp53
-rw-r--r--compiler/luci/import/src/Nodes/CircleSin.cpp63
-rw-r--r--compiler/luci/import/src/Nodes/CircleSlice.cpp52
-rw-r--r--compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp80
-rw-r--r--compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp52
-rw-r--r--compiler/luci/import/src/Nodes/CircleSparseToDense.cpp50
-rw-r--r--compiler/luci/import/src/Nodes/CircleSplit.cpp119
-rw-r--r--compiler/luci/import/src/Nodes/CircleSplitV.cpp121
-rw-r--r--compiler/luci/import/src/Nodes/CircleSqrt.cpp44
-rw-r--r--compiler/luci/import/src/Nodes/CircleSquare.cpp63
-rw-r--r--compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp77
-rw-r--r--compiler/luci/import/src/Nodes/CircleSqueeze.cpp51
-rw-r--r--compiler/luci/import/src/Nodes/CircleStridedSlice.cpp60
-rw-r--r--compiler/luci/import/src/Nodes/CircleSum.cpp46
-rw-r--r--compiler/luci/import/src/Nodes/CircleTanh.cpp60
-rw-r--r--compiler/luci/import/src/Nodes/CircleTile.cpp68
-rw-r--r--compiler/luci/import/src/Nodes/CircleTopKV2.cpp117
-rw-r--r--compiler/luci/import/src/Nodes/CircleTransposeConv.cpp54
-rw-r--r--compiler/luci/import/src/Nodes/CircleUnpack.cpp151
-rw-r--r--compiler/luci/import/src/Nodes/CircleWhere.cpp60
-rw-r--r--compiler/luci/import/src/Nodes/CircleWhile.cpp123
-rw-r--r--compiler/luci/import/src/Nodes/CircleZerosLike.cpp49
-rw-r--r--compiler/luci/import/src/PostImport.cpp354
-rw-r--r--compiler/luci/import/src/PostImport.h34
-rw-r--r--compiler/luci/lang/CMakeLists.txt2
-rw-r--r--compiler/luci/lang/include/luci/IR/AttrDilation.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/AttrMirrorPadMode.h33
-rw-r--r--compiler/luci/lang/include/luci/IR/CircleNodeDecl.h16
-rw-r--r--compiler/luci/lang/include/luci/IR/CircleNodeImpl.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/CircleNodes.h98
-rw-r--r--compiler/luci/lang/include/luci/IR/CircleNodes.lst85
-rw-r--r--compiler/luci/lang/include/luci/IR/LuciNodeMixins.h5
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleAddN.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleArgMin.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleBCQFullyConnected.h66
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleBCQGather.h60
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleBatchMatMul.h54
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleCast.h51
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleCeil.h40
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h2
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h5
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h5
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleCustom.h61
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleCustomOut.h51
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleDepthToSpace.h48
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h5
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleElu.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleExpandDims.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleFill.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleFloor.h40
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleFloorDiv.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleFloorMod.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h9
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleGatherNd.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleGreater.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleGreaterEqual.h44
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleIf.h79
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleIfOut.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h5
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleL2Normalize.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleL2Pool2D.h62
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleLeakyRelu.h49
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleLess.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleLessEqual.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleLocalResponseNormalization.h60
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleLog.h40
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleLogSoftmax.h40
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleLogicalAnd.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleLogistic.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixDiag.h40
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixSetDiag.h44
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleMinimum.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleMirrorPad.h54
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleNeg.h40
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleNotEqual.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleOneHot.h56
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h22
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CirclePRelu.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CirclePow.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleRange.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleRank.h40
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleReduceAny.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMax.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMin.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleReduceProd.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleReluN1To1.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h5
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleResizeBilinear.h57
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleResizeNearestNeighbor.h53
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleReverseSequence.h58
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleReverseV2.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleRound.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleScatterNd.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSegmentSum.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSelect.h49
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSelectV2.h49
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleShape.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSin.h40
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSlice.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h2
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToBatchND.h47
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToDepth.h48
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSparseToDense.h57
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSplit.h51
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSplitOut.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSplitV.h54
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSplitVOut.h51
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSquare.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSqueeze.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleStridedSlice.h73
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleSum.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleTanh.h43
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleTile.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2Out.h51
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h1
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h3
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleUnpack.h54
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleUnpackOut.h51
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleWhere.h45
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleWhile.h79
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleWhileOut.h50
-rw-r--r--compiler/luci/lang/include/luci/IR/Nodes/CircleZerosLike.h46
-rw-r--r--compiler/luci/lang/include/luci/IR/PropertyShapeStatus.h38
-rw-r--r--compiler/luci/lang/include/luci/IR/VariadicArityNode.h12
-rw-r--r--compiler/luci/lang/src/CircleDialect.cpp9
-rw-r--r--compiler/luci/lang/src/CircleDialect.test.cpp59
-rw-r--r--compiler/luci/lang/src/CircleNodeShapeDtype.test.cpp52
-rw-r--r--compiler/luci/lang/src/CircleNodes.cpp35
-rw-r--r--compiler/luci/lang/src/DeadNodeQueryService.cpp74
-rw-r--r--compiler/luci/lang/src/DeadNodeQueryService.h34
-rw-r--r--compiler/luci/lang/src/Module.cpp2
-rw-r--r--compiler/luci/lang/src/Module.test.cpp14
-rw-r--r--compiler/luci/lang/src/Nodes/CircleAbs.test.cpp69
-rw-r--r--compiler/luci/lang/src/Nodes/CircleAdd.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CircleAddN.test.cpp91
-rw-r--r--compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp59
-rw-r--r--compiler/luci/lang/src/Nodes/CircleArgMin.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleAveragePool2D.test.cpp90
-rw-r--r--compiler/luci/lang/src/Nodes/CircleBCQFullyConnected.test.cpp38
-rw-r--r--compiler/luci/lang/src/Nodes/CircleBCQGather.test.cpp37
-rw-r--r--compiler/luci/lang/src/Nodes/CircleBatchMatMul.test.cpp84
-rw-r--r--compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp63
-rw-r--r--compiler/luci/lang/src/Nodes/CircleCast.test.cpp78
-rw-r--r--compiler/luci/lang/src/Nodes/CircleCeil.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp63
-rw-r--r--compiler/luci/lang/src/Nodes/CircleConst.cpp3
-rw-r--r--compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp85
-rw-r--r--compiler/luci/lang/src/Nodes/CircleCos.test.cpp51
-rw-r--r--compiler/luci/lang/src/Nodes/CircleCustom.test.cpp45
-rw-r--r--compiler/luci/lang/src/Nodes/CircleCustomOut.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleDepthToSpace.test.cpp80
-rw-r--r--compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp93
-rw-r--r--compiler/luci/lang/src/Nodes/CircleDiv.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CircleElu.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleEqual.test.cpp59
-rw-r--r--compiler/luci/lang/src/Nodes/CircleExp.test.cpp51
-rw-r--r--compiler/luci/lang/src/Nodes/CircleExpandDims.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleFill.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleFloor.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleFloorDiv.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleFloorMod.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp68
-rw-r--r--compiler/luci/lang/src/Nodes/CircleGather.test.cpp62
-rw-r--r--compiler/luci/lang/src/Nodes/CircleGatherNd.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleGreater.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleGreaterEqual.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleIf.test.cpp87
-rw-r--r--compiler/luci/lang/src/Nodes/CircleIfOut.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp68
-rw-r--r--compiler/luci/lang/src/Nodes/CircleL2Pool2D.test.cpp94
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLeakyRelu.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLess.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLessEqual.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLocalResponseNormalization.test.cpp90
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLog.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLogSoftmax.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLogicalAnd.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp51
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CircleLogistic.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleMatrixDiag.test.cpp78
-rw-r--r--compiler/luci/lang/src/Nodes/CircleMatrixSetDiag.test.cpp84
-rw-r--r--compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp67
-rw-r--r--compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CircleMean.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleMinimum.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleMirrorPad.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleMul.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CircleNeg.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleNotEqual.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleOneHot.test.cpp95
-rw-r--r--compiler/luci/lang/src/Nodes/CirclePRelu.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CirclePack.test.cpp63
-rw-r--r--compiler/luci/lang/src/Nodes/CirclePad.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CirclePow.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleRange.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleRank.test.cpp31
-rw-r--r--compiler/luci/lang/src/Nodes/CircleReduceAny.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleReduceMax.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleReduceMin.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleReduceProd.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleRelu.test.cpp51
-rw-r--r--compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp51
-rw-r--r--compiler/luci/lang/src/Nodes/CircleReluN1To1.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleReshape.test.cpp65
-rw-r--r--compiler/luci/lang/src/Nodes/CircleResizeBilinear.test.cpp88
-rw-r--r--compiler/luci/lang/src/Nodes/CircleResizeNearestNeighbor.test.cpp85
-rw-r--r--compiler/luci/lang/src/Nodes/CircleReverseSequence.test.cpp35
-rw-r--r--compiler/luci/lang/src/Nodes/CircleReverseV2.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleRound.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp51
-rw-r--r--compiler/luci/lang/src/Nodes/CircleScatterNd.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSegmentSum.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSelect.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSelectV2.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleShape.test.cpp80
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSin.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSlice.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp51
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSpaceToBatchND.test.cpp86
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSpaceToDepth.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSparseToDense.test.cpp93
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSplit.test.cpp85
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSplitOut.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSplitV.test.cpp90
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSplitVOut.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp51
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSquare.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSqueeze.test.cpp87
-rw-r--r--compiler/luci/lang/src/Nodes/CircleStridedSlice.test.cpp108
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSub.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CircleSum.test.cpp85
-rw-r--r--compiler/luci/lang/src/Nodes/CircleTanh.test.cpp76
-rw-r--r--compiler/luci/lang/src/Nodes/CircleTile.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleTopKV2.test.cpp81
-rw-r--r--compiler/luci/lang/src/Nodes/CircleTopKV2Out.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp57
-rw-r--r--compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp75
-rw-r--r--compiler/luci/lang/src/Nodes/CircleUnpack.test.cpp83
-rw-r--r--compiler/luci/lang/src/Nodes/CircleUnpackOut.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleWhere.test.cpp33
-rw-r--r--compiler/luci/lang/src/Nodes/CircleWhile.test.cpp87
-rw-r--r--compiler/luci/lang/src/Nodes/CircleWhileOut.test.cpp32
-rw-r--r--compiler/luci/lang/src/Nodes/CircleZerosLike.test.cpp76
-rw-r--r--compiler/luci/log/CMakeLists.txt1
-rw-r--r--compiler/luci/log/include/luci/Log.h10
-rw-r--r--compiler/luci/log/src/Log.cpp40
-rw-r--r--compiler/luci/logex/src/FormattedGraph.cpp884
-rw-r--r--compiler/luci/pass/CMakeLists.txt24
-rw-r--r--compiler/luci/pass/include/luci/CircleOptimizer.h19
-rw-r--r--compiler/luci/pass/include/luci/Pass/FuseBCQPass.h38
-rw-r--r--compiler/luci/pass/include/luci/Pass/QuantizationParameters.h31
-rw-r--r--compiler/luci/pass/include/luci/Pass/QuantizeDequantizeWeightsPass.h54
-rw-r--r--compiler/luci/pass/include/luci/Pass/QuantizeWithMinMaxPass.h54
-rw-r--r--compiler/luci/pass/include/luci/Pass/ResolveCustomOpAddPass.h37
-rw-r--r--compiler/luci/pass/include/luci/Pass/ResolveCustomOpBatchMatMulPass.h37
-rw-r--r--compiler/luci/pass/include/luci/Pass/ResolveCustomOpMatMulPass.h37
-rw-r--r--compiler/luci/pass/src/CircleOptimizer.cpp121
-rw-r--r--compiler/luci/pass/src/CircleOptimizerUtils.cpp89
-rw-r--r--compiler/luci/pass/src/CircleOptimizerUtils.h42
-rw-r--r--compiler/luci/pass/src/FuseBCQPass.cpp405
-rw-r--r--compiler/luci/pass/src/FuseInstanceNormPass.cpp231
-rw-r--r--compiler/luci/pass/src/FuseInstanceNormPass.test.cpp64
-rw-r--r--compiler/luci/pass/src/FuseInstanceNormPassInternal.h28
-rw-r--r--compiler/luci/pass/src/QuantizationUtils.cpp172
-rw-r--r--compiler/luci/pass/src/QuantizationUtils.h38
-rw-r--r--compiler/luci/pass/src/QuantizeDequantizeWeightsPass.cpp495
-rw-r--r--compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp551
-rw-r--r--compiler/luci/pass/src/ResolveCustomOpAddPass.cpp124
-rw-r--r--compiler/luci/pass/src/ResolveCustomOpBatchMatMulPass.cpp69
-rw-r--r--compiler/luci/pass/src/ResolveCustomOpMatMulPass.cpp185
-rw-r--r--compiler/luci/requires.cmake2
-rw-r--r--compiler/luci/service/src/CircleShapeInference.cpp7
-rw-r--r--compiler/luci/service/src/CircleShapeInferenceRule.cpp1645
-rw-r--r--compiler/luci/service/src/CircleShapeInferenceRule.test.cpp532
-rw-r--r--compiler/luci/service/src/CircleTypeInference.cpp10
-rw-r--r--compiler/luci/service/src/CircleTypeInferenceRule.cpp452
-rw-r--r--compiler/luci/service/src/CircleTypeInferenceRule.test.cpp24
-rw-r--r--compiler/luci/service/src/GraphBlock.h201
-rw-r--r--compiler/luci/service/src/GraphBlock.test.cpp246
-rw-r--r--compiler/luci/service/src/ShapeInfer_StridedSlice.cpp298
-rw-r--r--compiler/luci/service/src/ShapeInfer_StridedSlice.h31
-rw-r--r--compiler/luci/service/src/TestGraph.h216
-rw-r--r--compiler/luci/service/src/TestGraph.test.cpp101
-rw-r--r--compiler/luci/service/src/Validate.cpp31
-rw-r--r--compiler/luci/tester/CMakeLists.txt12
-rw-r--r--compiler/luci/tester/src/Model.cpp62
-rw-r--r--compiler/luci/tester/src/Model.h27
-rw-r--r--compiler/luci/tester/src/ReadTester.cpp39
-rw-r--r--compiler/luci/tester/src/WriteTester.cpp43
-rw-r--r--compiler/luci/tests/CMakeLists.txt29
-rwxr-xr-xcompiler/luci/tests/readverify.sh3
-rw-r--r--compiler/luci/tests/test.lst296
475 files changed, 29882 insertions, 1907 deletions
diff --git a/compiler/luci/CMakeLists.txt b/compiler/luci/CMakeLists.txt
index 387c22487..214a1bbf2 100644
--- a/compiler/luci/CMakeLists.txt
+++ b/compiler/luci/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(env)
add_subdirectory(log)
add_subdirectory(lang)
add_subdirectory(service)
diff --git a/compiler/luci/env/CMakeLists.txt b/compiler/luci/env/CMakeLists.txt
new file mode 100644
index 000000000..3d8387a47
--- /dev/null
+++ b/compiler/luci/env/CMakeLists.txt
@@ -0,0 +1,18 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(luci_env SHARED ${SOURCES})
+target_include_directories(luci_env PUBLIC include)
+target_link_libraries(luci_env PRIVATE nncc_common)
+install(TARGETS luci_env DESTINATION lib)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
+
+GTest_AddTest(luci_env_test ${TESTS})
+target_include_directories(luci_env_test PRIVATE src)
+target_link_libraries(luci_env_test luci_env)
diff --git a/compiler/luci/env/README.md b/compiler/luci/env/README.md
new file mode 100644
index 000000000..cda007867
--- /dev/null
+++ b/compiler/luci/env/README.md
@@ -0,0 +1,3 @@
+# luci-env
+
+_luci-env_ provides user environment settings that control _luci_
diff --git a/compiler/luci/env/include/luci/UserSettings.h b/compiler/luci/env/include/luci/UserSettings.h
new file mode 100644
index 000000000..bcfd16071
--- /dev/null
+++ b/compiler/luci/env/include/luci/UserSettings.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_USER_SETTINGS__
+#define __LUCI_USER_SETTINGS__
+
+// NOTE Revise the logic if we find a better way not using global status
+
+namespace luci
+{
+
+/**
+ * @brief UserSettings provides user settings by key-value
+ */
+struct UserSettings
+{
+ enum Key
+ {
+ Undefined,
+ MuteWarnings,
+ DisableValidation,
+ };
+
+ static UserSettings *settings();
+
+ virtual void set(const Key key, bool value) = 0;
+ virtual bool get(const Key key) const = 0;
+};
+
+} // namespace luci
+
+#endif // __LUCI_USER_SETTINGS__
diff --git a/compiler/luci/env/src/UserSettings.cpp b/compiler/luci/env/src/UserSettings.cpp
new file mode 100644
index 000000000..27dec762d
--- /dev/null
+++ b/compiler/luci/env/src/UserSettings.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/UserSettings.h"
+
+#include <stdexcept>
+
+namespace luci
+{
+
+class UserSettingsImpl : public UserSettings
+{
+public:
+ void set(const Key key, bool value) override;
+ bool get(const Key key) const override;
+
+private:
+ bool _MuteWarnings{false};
+ bool _DisableValidation{false};
+};
+
+void UserSettingsImpl::set(const Key key, bool value)
+{
+ switch (key)
+ {
+ case Key::MuteWarnings:
+ _MuteWarnings = value;
+ break;
+ case Key::DisableValidation:
+ _DisableValidation = value;
+ break;
+ default:
+ throw std::runtime_error("Invalid key in boolean set");
+ break;
+ }
+}
+
+bool UserSettingsImpl::get(const Key key) const
+{
+ switch (key)
+ {
+ case Key::MuteWarnings:
+ return _MuteWarnings;
+ case Key::DisableValidation:
+ return _DisableValidation;
+ default:
+ throw std::runtime_error("Invalid key in boolean get");
+ break;
+ }
+ return false;
+}
+
+} // namespace luci
+
+namespace luci
+{
+
+UserSettings *UserSettings::settings()
+{
+ static UserSettingsImpl _this;
+ return &_this;
+}
+
+} // namespace luci
diff --git a/compiler/luci/env/src/UserSettings.test.cpp b/compiler/luci/env/src/UserSettings.test.cpp
new file mode 100644
index 000000000..8d9d1875b
--- /dev/null
+++ b/compiler/luci/env/src/UserSettings.test.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/UserSettings.h"
+
+#include <gtest/gtest.h>
+
+TEST(UserSettings, instance)
+{
+ auto settings = luci::UserSettings::settings();
+ ASSERT_NE(nullptr, settings);
+
+ auto s2 = luci::UserSettings::settings();
+ ASSERT_EQ(s2, settings);
+}
+
+TEST(UserSettings, MuteWarnings)
+{
+ auto settings = luci::UserSettings::settings();
+ ASSERT_NE(nullptr, settings);
+
+ settings->set(luci::UserSettings::Key::MuteWarnings, false);
+ ASSERT_FALSE(settings->get(luci::UserSettings::Key::MuteWarnings));
+
+ settings->set(luci::UserSettings::Key::MuteWarnings, true);
+ ASSERT_TRUE(settings->get(luci::UserSettings::Key::MuteWarnings));
+}
+
+TEST(UserSettings, DisableValidation)
+{
+ auto settings = luci::UserSettings::settings();
+ ASSERT_NE(nullptr, settings);
+
+ settings->set(luci::UserSettings::Key::DisableValidation, false);
+ ASSERT_FALSE(settings->get(luci::UserSettings::Key::DisableValidation));
+
+ settings->set(luci::UserSettings::Key::DisableValidation, true);
+ ASSERT_TRUE(settings->get(luci::UserSettings::Key::DisableValidation));
+}
+
+TEST(UserSettings, undefined_set_NEG)
+{
+ auto settings = luci::UserSettings::settings();
+ ASSERT_NE(nullptr, settings);
+
+ ASSERT_THROW(settings->set(luci::UserSettings::Key::Undefined, true), std::exception);
+}
+
+TEST(UserSettings, undefined_get_NEG)
+{
+ auto settings = luci::UserSettings::settings();
+ ASSERT_NE(nullptr, settings);
+
+ ASSERT_THROW(settings->get(luci::UserSettings::Key::Undefined), std::exception);
+}
diff --git a/compiler/luci/export/CMakeLists.txt b/compiler/luci/export/CMakeLists.txt
index e32eca366..fe4382ecd 100644
--- a/compiler/luci/export/CMakeLists.txt
+++ b/compiler/luci/export/CMakeLists.txt
@@ -10,6 +10,7 @@ target_link_libraries(luci_export PRIVATE luci_lang)
target_link_libraries(luci_export PRIVATE luci_service)
target_link_libraries(luci_export PRIVATE luci_pass)
target_link_libraries(luci_export PRIVATE mio_circle)
+target_link_libraries(luci_export PRIVATE luci_env)
target_link_libraries(luci_export PRIVATE luci_log)
target_link_libraries(luci_export PRIVATE luci_logex)
target_link_libraries(luci_export PRIVATE nncc_common)
diff --git a/compiler/luci/export/src/CircleExporterImpl.cpp b/compiler/luci/export/src/CircleExporterImpl.cpp
index 81109ee62..860cebf6e 100644
--- a/compiler/luci/export/src/CircleExporterImpl.cpp
+++ b/compiler/luci/export/src/CircleExporterImpl.cpp
@@ -16,6 +16,7 @@
#include "CircleExporterImpl.h"
#include "Optimize.h"
+#include "TypeBridge.h"
#include "CircleTensorExporter.h"
#include "CircleOperationExporter.h"
#include "CircleExporterUtils.h"
@@ -36,11 +37,11 @@ luci::CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index
{
for (uint32_t n = 0; n < g->nodes()->size(); ++n)
{
- if (auto pull = dynamic_cast<luci::CircleInput *>(g->nodes()->at(n)))
+ if (auto input = dynamic_cast<luci::CircleInput *>(g->nodes()->at(n)))
{
- if (pull->indexed() && pull->index() == index)
+ if (input->indexed() && input->index() == index)
{
- return pull;
+ return input;
}
}
}
@@ -51,11 +52,11 @@ luci::CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &in
{
for (uint32_t n = 0; n < g->nodes()->size(); ++n)
{
- if (auto push = dynamic_cast<luci::CircleOutput *>(g->nodes()->at(n)))
+ if (auto output = dynamic_cast<luci::CircleOutput *>(g->nodes()->at(n)))
{
- if (push->indexed() && push->index() == index)
+ if (output->indexed() && output->index() == index)
{
- return push;
+ return output;
}
}
}
@@ -80,6 +81,13 @@ void registerGraphOutputTensors(loco::Graph *graph, luci::SubGraphContext &ctx)
assert(push != nullptr);
auto node = push->from();
assert(node != nullptr);
+
+ // Do not export CircleOutput when it's input is CircleOutputExclude
+ if (dynamic_cast<luci::CircleOutputExclude *>(push->from()) != nullptr)
+ {
+ continue;
+ }
+
ctx._outputs.push_back(luci::get_tensor_index(node));
}
}
@@ -93,8 +101,7 @@ using namespace circle;
using namespace flatbuffers;
Offset<Vector<Offset<OperatorCode>>>
-encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode, uint32_t> &opcodes,
- std::unordered_map<luci::OpCode, std::string> &custom_opcodes)
+encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode, uint32_t> &opcodes)
{
std::vector<Offset<OperatorCode>> operator_codes_vec(opcodes.size());
for (auto it : opcodes)
@@ -102,19 +109,15 @@ encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode,
uint32_t idx = it.second;
if (it.first.opcode != BuiltinOperator_CUSTOM)
{
- operator_codes_vec[idx] = CreateOperatorCode(builder, it.first.opcode);
+ operator_codes_vec[idx] = CreateOperatorCode(builder, it.first.opcode, 0, it.first.version);
}
- else // custom op
+ else
{
- auto opCode = it.first;
- auto custom_code = custom_opcodes.find(opCode);
- if (custom_code == custom_opcodes.end())
- INTERNAL_EXN("Cannot find code for customop even though opcode is BuiltinOperator_CUSTOM");
-
operator_codes_vec[idx] =
- CreateOperatorCode(builder, it.first.opcode, builder.CreateString(custom_code->second));
+ CreateOperatorCode(builder, it.first.opcode, builder.CreateString(it.first.custom_code));
}
}
+
return builder.CreateVector(operator_codes_vec);
}
@@ -136,8 +139,9 @@ CircleExporterImpl::exportSubgraph(SerializedGraphData &gd)
auto inputs = _builder.CreateVector(gd._inputs);
auto outputs = _builder.CreateVector(gd._outputs);
auto operators = _builder.CreateVector(gd._operators);
+ auto name = _builder.CreateString(gd._name);
auto df = gd._data_format;
- auto subgraph = CreateSubGraph(_builder, tensors, inputs, outputs, operators, df);
+ auto subgraph = CreateSubGraph(_builder, tensors, inputs, outputs, operators, name, df);
return subgraph;
}
@@ -146,6 +150,9 @@ void CircleExporterImpl::exportGraph(loco::Graph *graph)
// do graph optimization
optimize(graph);
+ // copy shape/dtype inference data to CircleNode
+ copy_shape_dtype(graph);
+
_builder.Clear();
SerializedModelData md;
@@ -154,6 +161,9 @@ void CircleExporterImpl::exportGraph(loco::Graph *graph)
// This version is taken from comment in fbs
constexpr uint32_t version = 0;
+ // set Subgraph name
+ gd._name = graph->name();
+
// TODO set this value properly
gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST;
@@ -170,8 +180,7 @@ void CircleExporterImpl::exportGraph(loco::Graph *graph)
exportNodes(graph, _builder, md, gd);
// encode operator codes
- auto operator_codes =
- encodeOperatorCodes(_builder, md._operator_codes, md._custom_operator_codes);
+ auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes);
// Subgraphs
Offset<SubGraph> subgraph = exportSubgraph(gd);
@@ -203,6 +212,9 @@ void CircleExporterImpl::exportModule(Module *module)
_builder.Clear();
+ // prepare model data
+ prepareModelData(_builder, md);
+
std::vector<flatbuffers::Offset<circle::SubGraph>> subgraph_vec;
for (size_t g = 0; g < module->size(); ++g)
@@ -211,8 +223,14 @@ void CircleExporterImpl::exportModule(Module *module)
optimize(graph);
+ // copy shape/dtype inference data to CircleNode
+ copy_shape_dtype(graph);
+
SerializedGraphData gd;
+ // set Subgraph name
+ gd._name = graph->name();
+
// TODO set this value properly
gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST;
@@ -233,8 +251,7 @@ void CircleExporterImpl::exportModule(Module *module)
auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph_vec});
// encode operator codes
- auto operator_codes =
- encodeOperatorCodes(_builder, md._operator_codes, md._custom_operator_codes);
+ auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes);
// Description
std::string description_str = "nnpackage";
diff --git a/compiler/luci/export/src/CircleExporterUtils.cpp b/compiler/luci/export/src/CircleExporterUtils.cpp
index 1272facb2..f097e71c5 100644
--- a/compiler/luci/export/src/CircleExporterUtils.cpp
+++ b/compiler/luci/export/src/CircleExporterUtils.cpp
@@ -70,28 +70,49 @@ circle::TensorType to_circle_tensortype(loco::DataType type)
}
}
+circle::MirrorPadMode to_circle_mirrorpadmode(luci::MirrorPadMode mode)
+{
+ switch (mode)
+ {
+ case luci::MirrorPadMode::REFLECT:
+ return circle::MirrorPadMode::MirrorPadMode_REFLECT;
+ case luci::MirrorPadMode::SYMMETRIC:
+ return circle::MirrorPadMode::MirrorPadMode_SYMMETRIC;
+ default:
+ INTERNAL_EXN_V("trying to convert unsupported luci::MirrorPadMode", oops::to_uint32(mode));
+ }
+}
+
} // namespace luci
namespace luci
{
-uint32_t SerializedModelData::registerBuiltinOpcode(circle::BuiltinOperator builtin_code)
+uint32_t SerializedModelData::registerBuiltinOpcode(circle::BuiltinOperator builtin_code,
+ const int32_t op_version)
{
- auto it = _operator_codes.find(OpCode{builtin_code});
+ assert(op_version > 0);
+
+ auto it = _operator_codes.find(OpCode{builtin_code, "", op_version});
if (it != _operator_codes.end())
{
return it->second;
}
auto idx = static_cast<uint32_t>(_operator_codes.size());
- _operator_codes.emplace(OpCode{builtin_code}, idx);
+ _operator_codes.emplace(OpCode{builtin_code, "", op_version}, idx);
return idx;
}
-uint32_t SerializedModelData::registerCustomOpcode(const std::string &custom_op)
+uint32_t SerializedModelData::registerCustomOpcode(const std::string &custom_code)
{
- circle::BuiltinOperator custom_code = circle::BuiltinOperator_CUSTOM;
- auto idx = registerBuiltinOpcode(custom_code);
- _custom_operator_codes.emplace(OpCode{custom_code}, custom_op);
+ const circle::BuiltinOperator builtin_code = circle::BuiltinOperator_CUSTOM;
+ auto it = _operator_codes.find(OpCode{builtin_code, custom_code});
+ if (it != _operator_codes.end())
+ {
+ return it->second;
+ }
+ auto idx = static_cast<uint32_t>(_operator_codes.size());
+ _operator_codes.emplace(OpCode{builtin_code, custom_code}, idx);
return idx;
}
diff --git a/compiler/luci/export/src/CircleExporterUtils.h b/compiler/luci/export/src/CircleExporterUtils.h
index 6b970fd3c..f9ce6d2bf 100644
--- a/compiler/luci/export/src/CircleExporterUtils.h
+++ b/compiler/luci/export/src/CircleExporterUtils.h
@@ -31,6 +31,7 @@ namespace luci
circle::ActivationFunctionType to_circle_actfunc(luci::FusedActFunc func);
circle::TensorType to_circle_tensortype(loco::DataType type);
+circle::MirrorPadMode to_circle_mirrorpadmode(luci::MirrorPadMode mode);
} // namespace luci
diff --git a/compiler/luci/export/src/CircleOperationExporter.cpp b/compiler/luci/export/src/CircleOperationExporter.cpp
index ad9c7fd4b..3c01b676f 100644
--- a/compiler/luci/export/src/CircleOperationExporter.cpp
+++ b/compiler/luci/export/src/CircleOperationExporter.cpp
@@ -22,6 +22,8 @@
#include <luci/IR/CircleNodes.h>
#include <luci/IR/CircleNodeVisitor.h>
#include <luci/Service/CircleShapeInference.h>
+#include <luci/UserSettings.h>
+#include <luci/Log.h>
#include <loco/IR/CanonicalNodeVisitor.h>
#include <oops/InternalExn.h>
@@ -49,42 +51,125 @@ public:
public:
void visit(luci::CircleAbs *) final;
void visit(luci::CircleAdd *) final;
+ void visit(luci::CircleAddN *) final;
void visit(luci::CircleArgMax *) final;
+ void visit(luci::CircleArgMin *) final;
void visit(luci::CircleAveragePool2D *) final;
+ void visit(luci::CircleBatchMatMul *) final;
void visit(luci::CircleBatchToSpaceND *) final;
+ void visit(luci::CircleCast *) final;
+ void visit(luci::CircleCeil *) final;
void visit(luci::CircleConcatenation *) final;
void visit(luci::CircleConst *) final{/* skip, everything is done in exportOpDefinedTensors */};
void visit(luci::CircleConv2D *) final;
void visit(luci::CircleCos *) final;
+ void visit(luci::CircleCustom *) final;
+ void visit(luci::CircleDepthToSpace *) final;
void visit(luci::CircleDepthwiseConv2D *) final;
void visit(luci::CircleDiv *) final;
- void visit(luci::CircleExp *) final;
+ void visit(luci::CircleElu *) final;
void visit(luci::CircleEqual *) final;
+ void visit(luci::CircleExp *) final;
+ void visit(luci::CircleExpandDims *) final;
+ void visit(luci::CircleFill *) final;
+ void visit(luci::CircleFloor *) final;
+ void visit(luci::CircleFloorDiv *) final;
+ void visit(luci::CircleFloorMod *) final;
void visit(luci::CircleFullyConnected *) final;
+ void visit(luci::CircleGather *) final;
+ void visit(luci::CircleGatherNd *) final;
+ void visit(luci::CircleGreater *) final;
+ void visit(luci::CircleGreaterEqual *) final;
+ void visit(luci::CircleIf *) final;
+ void visit(luci::CircleL2Normalize *) final;
+ void visit(luci::CircleL2Pool2D *) final;
+ void visit(luci::CircleLeakyRelu *) final;
+ void visit(luci::CircleLess *) final;
+ void visit(luci::CircleLessEqual *) final;
+ void visit(luci::CircleLocalResponseNormalization *) final;
+ void visit(luci::CircleLog *) final;
+ void visit(luci::CircleLogicalAnd *) final;
void visit(luci::CircleLogicalNot *) final;
void visit(luci::CircleLogicalOr *) final;
+ void visit(luci::CircleLogistic *) final;
+ void visit(luci::CircleLogSoftmax *) final;
+ void visit(luci::CircleMatrixDiag *) final;
+ void visit(luci::CircleMatrixSetDiag *) final;
void visit(luci::CircleMaximum *) final;
void visit(luci::CircleMaxPool2D *) final;
void visit(luci::CircleMean *) final;
+ void visit(luci::CircleMinimum *) final;
+ void visit(luci::CircleMirrorPad *) final;
void visit(luci::CircleMul *) final;
+ void visit(luci::CircleNeg *) final;
+ void visit(luci::CircleNotEqual *) final;
+ void visit(luci::CircleOneHot *) final;
void visit(luci::CirclePack *) final;
void visit(luci::CirclePad *) final;
+ void visit(luci::CirclePow *) final;
+ void visit(luci::CirclePRelu *) final;
+ void visit(luci::CircleRange *) final;
+ void visit(luci::CircleRank *) final;
+ void visit(luci::CircleReduceAny *) final;
+ void visit(luci::CircleReduceMax *) final;
+ void visit(luci::CircleReduceMin *) final;
+ void visit(luci::CircleReduceProd *) final;
void visit(luci::CircleRelu *) final;
void visit(luci::CircleRelu6 *) final;
+ void visit(luci::CircleReluN1To1 *) final;
void visit(luci::CircleReshape *) final;
+ void visit(luci::CircleResizeBilinear *) final;
+ void visit(luci::CircleResizeNearestNeighbor *) final;
+ void visit(luci::CircleReverseSequence *) final;
+ void visit(luci::CircleReverseV2 *) final;
+ void visit(luci::CircleRound *) final;
void visit(luci::CircleRsqrt *) final;
+ void visit(luci::CircleScatterNd *) final;
+ void visit(luci::CircleSegmentSum *) final;
+ void visit(luci::CircleSelect *) final;
+ void visit(luci::CircleSelectV2 *) final;
+ void visit(luci::CircleShape *) final;
+ void visit(luci::CircleSin *) final;
+ void visit(luci::CircleSlice *) final;
void visit(luci::CircleSoftmax *) final;
+ void visit(luci::CircleSpaceToBatchND *) final;
+ void visit(luci::CircleSpaceToDepth *) final;
+ void visit(luci::CircleSparseToDense *) final;
+ void visit(luci::CircleSplit *) final;
+ void visit(luci::CircleSplitV *) final;
void visit(luci::CircleSqrt *) final;
+ void visit(luci::CircleSquare *) final;
void visit(luci::CircleSquaredDifference *) final;
+ void visit(luci::CircleSqueeze *) final;
+ void visit(luci::CircleStridedSlice *) final;
void visit(luci::CircleSub *) final;
- // TODO CircleTanh
+ void visit(luci::CircleSum *) final;
+ void visit(luci::CircleTanh *) final;
+ void visit(luci::CircleTile *) final;
+ void visit(luci::CircleTopKV2 *) final;
void visit(luci::CircleTranspose *) final;
void visit(luci::CircleTransposeConv *) final;
+ void visit(luci::CircleUnpack *) final;
+ void visit(luci::CircleWhere *) final;
+ void visit(luci::CircleWhile *) final;
+ void visit(luci::CircleZerosLike *) final;
// Circle only
+ void visit(luci::CircleBCQFullyConnected *) final;
+ void visit(luci::CircleBCQGather *) final;
void visit(luci::CircleInstanceNorm *) final;
// Virtual
void visit(luci::CircleInput *) final {}
void visit(luci::CircleOutput *) final {}
+ void visit(luci::CircleOutputDummy *) final {}
+ void visit(luci::CircleOutputExclude *) final {}
+ // Virtual for multiple-outputs
+ void visit(luci::CircleCustomOut *) final {}
+ void visit(luci::CircleIfOut *) final {}
+ void visit(luci::CircleSplitOut *) final {}
+ void visit(luci::CircleSplitVOut *) final {}
+ void visit(luci::CircleTopKV2Out *) final {}
+ void visit(luci::CircleUnpackOut *) final {}
+ void visit(luci::CircleWhileOut *) final {}
private:
/**
@@ -95,6 +180,17 @@ private:
template <class CirclePool2D>
void export_pool_2d(CirclePool2D *node, circle::BuiltinOperator builtin_op);
+ /**
+ * @brief export simple nodes
+ */
+ void export_simple(loco::Node *node, circle::BuiltinOperator bop, circle::BuiltinOptions bot,
+ flatbuffers::Offset<void> options_offset);
+
+ /**
+ * @brief export simple nodes having void options
+ */
+ void export_simple(loco::Node *node, circle::BuiltinOperator bop);
+
private:
FlatBufferBuilder &builder;
SerializedModelData &md;
@@ -105,11 +201,12 @@ template <class CirclePool2D>
void OperationExporter::export_pool_2d(CirclePool2D *node, circle::BuiltinOperator builtin_op)
{
LUCI_ASSERT(builtin_op == circle::BuiltinOperator_MAX_POOL_2D ||
+ builtin_op == circle::BuiltinOperator_L2_POOL_2D ||
builtin_op == circle::BuiltinOperator_AVERAGE_POOL_2D,
- "Should be MaxPool or AvgPool");
+ "Should be L2Pool, MaxPool or AvgPool");
LUCI_ASSERT(node->padding() != luci::Padding::UNDEFINED, "Padding is not set");
- uint32_t op_idx = md.registerBuiltinOpcode(builtin_op);
+ uint32_t op_idx = md.registerBuiltinOpcode(builtin_op, node->op_version());
std::vector<int32_t> inputs_vec{get_tensor_index(node->value())};
std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
auto inputs = builder.CreateVector(inputs_vec);
@@ -125,54 +222,122 @@ void OperationExporter::export_pool_2d(CirclePool2D *node, circle::BuiltinOperat
gd._operators.push_back(op_offset);
}
-void OperationExporter::visit(luci::CircleAbs *node)
+void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop,
+ circle::BuiltinOptions bot,
+ flatbuffers::Offset<void> options_offset)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ABS);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
+ uint32_t op_idx =
+ md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version());
+ std::vector<int32_t> inputs_vec;
+ std::vector<int32_t> outputs_vec{get_tensor_index(node)};
+ for (uint32_t i = 0; i < node->arity(); ++i)
+ inputs_vec.push_back(get_tensor_index(node->arg(i)));
+ auto inputs = builder.CreateVector(inputs_vec);
+ auto outputs = builder.CreateVector(outputs_vec);
+ auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, bot, options_offset);
+ gd._operators.push_back(op_offset);
+}
+
+void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop)
+{
+ uint32_t op_idx =
+ md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version());
+ std::vector<int32_t> inputs_vec;
std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
+ for (uint32_t i = 0; i < node->arity(); ++i)
+ inputs_vec.push_back(get_tensor_index(node->arg(i)));
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateAbsOptions(builder);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_AbsOptions, options.Union());
+ auto op_offset = CreateOperator(builder, op_idx, inputs, outputs);
gd._operators.push_back(op_offset);
}
+void OperationExporter::visit(luci::CircleAbs *node)
+{
+ export_simple(node, circle::BuiltinOperator_ABS, circle::BuiltinOptions_AbsOptions,
+ CreateAbsOptions(builder).Union());
+}
+
void OperationExporter::visit(luci::CircleAdd *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ADD);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())};
+ export_simple(
+ node, circle::BuiltinOperator_ADD, circle::BuiltinOptions_AddOptions,
+ CreateAddOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
+}
+
+void OperationExporter::visit(luci::CircleAddN *node)
+{
+ uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ADD_N, node->op_version());
+ std::vector<int32_t> inputs_vec;
std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
+
+ for (uint32_t i = 0; i < node->arity(); ++i)
+ inputs_vec.push_back(get_tensor_index(node->inputs(i)));
+
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateAddOptions(builder, to_circle_actfunc(node->fusedActivationFunction()));
+ auto options = CreateAddNOptions(builder);
auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_AddOptions, options.Union());
+ circle::BuiltinOptions_AddNOptions, options.Union());
gd._operators.push_back(op_offset);
}
void OperationExporter::visit(luci::CircleArgMax *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ARG_MAX);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
- get_tensor_index(node->dimension())};
+ export_simple(node, circle::BuiltinOperator_ARG_MAX, circle::BuiltinOptions_ArgMaxOptions,
+ CreateArgMaxOptions(builder, to_circle_tensortype(node->output_type())).Union());
+}
+
+void OperationExporter::visit(luci::CircleArgMin *node)
+{
+ export_simple(node, circle::BuiltinOperator_ARG_MIN, circle::BuiltinOptions_ArgMinOptions,
+ CreateArgMinOptions(builder, to_circle_tensortype(node->output_type())).Union());
+}
+
+void OperationExporter::visit(luci::CircleAveragePool2D *node)
+{
+ export_pool_2d<luci::CircleAveragePool2D>(node, circle::BuiltinOperator_AVERAGE_POOL_2D);
+}
+
+void OperationExporter::visit(luci::CircleBatchMatMul *node)
+{
+ export_simple(node, circle::BuiltinOperator_BATCH_MATMUL,
+ circle::BuiltinOptions_BatchMatMulOptions,
+ CreateBatchMatMulOptions(builder, node->adj_x(), node->adj_y()).Union());
+}
+
+void OperationExporter::visit(luci::CircleCast *node)
+{
+ uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_CAST, node->op_version());
+ std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateArgMaxOptions(builder, to_circle_tensortype(node->output_type()));
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_ArgMaxOptions, options.Union());
+
+ flatbuffers::Offset<Operator> op_offset;
+ if (node->out_data_type() != loco::DataType::Unknown)
+ {
+ auto options = CreateCastOptions(builder, to_circle_tensortype(node->in_data_type()),
+ to_circle_tensortype(node->out_data_type()));
+ op_offset = CreateOperator(builder, op_idx, inputs, outputs, circle::BuiltinOptions_CastOptions,
+ options.Union());
+ }
+ else
+ {
+ op_offset = CreateOperator(builder, op_idx, inputs, outputs);
+ }
gd._operators.push_back(op_offset);
}
-void OperationExporter::visit(luci::CircleAveragePool2D *node)
+void OperationExporter::visit(luci::CircleCeil *node)
{
- export_pool_2d<luci::CircleAveragePool2D>(node, circle::BuiltinOperator_AVERAGE_POOL_2D);
+ export_simple(node, circle::BuiltinOperator_CEIL);
}
void OperationExporter::visit(luci::CircleConcatenation *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_CONCATENATION);
+ uint32_t op_idx =
+ md.registerBuiltinOpcode(circle::BuiltinOperator_CONCATENATION, node->op_version());
std::vector<int32_t> inputs_vec;
std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
@@ -190,169 +355,304 @@ void OperationExporter::visit(luci::CircleConcatenation *node)
void OperationExporter::visit(luci::CircleBatchToSpaceND *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_BATCH_TO_SPACE_ND);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
- get_tensor_index(node->block_shape()),
- get_tensor_index(node->crops())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
-
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateBatchToSpaceNDOptions(builder);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_BatchToSpaceNDOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_BATCH_TO_SPACE_ND,
+ circle::BuiltinOptions_BatchToSpaceNDOptions,
+ CreateBatchToSpaceNDOptions(builder).Union());
}
void OperationExporter::visit(luci::CircleConv2D *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_CONV_2D);
-
- // Make input, output and options for operator
- std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->filter()),
- get_tensor_index(node->bias())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- circle::Padding padding = getOpPadding(node->padding());
- auto options = CreateConv2DOptions(builder, padding, node->stride()->w(), node->stride()->h(),
- to_circle_actfunc(node->fusedActivationFunction()));
-
- // Make CONV_2D operator
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_Conv2DOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_CONV_2D, circle::BuiltinOptions_Conv2DOptions,
+ CreateConv2DOptions(builder, getOpPadding(node->padding()), node->stride()->w(),
+ node->stride()->h(),
+ to_circle_actfunc(node->fusedActivationFunction()),
+ node->dilation()->w(), node->dilation()->h())
+ .Union());
}
void OperationExporter::visit(luci::CircleCos *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_COS);
+ export_simple(node, circle::BuiltinOperator_COS, circle::BuiltinOptions_CosOptions,
+ CreateCosOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleCustom *node)
+{
+ auto custom_outputs = loco::succs(node);
+
+ uint32_t op_idx = md.registerCustomOpcode(node->custom_code());
+ std::vector<int32_t> inputs_vec;
+ std::vector<int32_t> outputs_vec;
+
+ for (uint32_t index = 0; index < node->numInputs(); index++)
+ {
+ inputs_vec.push_back(get_tensor_index(node->inputs(index)));
+ }
+ for (uint32_t index = 0; index < custom_outputs.size(); index++)
+ {
+ // store in order of index
+ bool found = false;
+ for (auto out : custom_outputs)
+ {
+ auto custom_out = loco::must_cast<luci::CircleCustomOut *>(out);
+ if (custom_out->index() == static_cast<int32_t>(index))
+ {
+ outputs_vec.push_back(get_tensor_index(custom_out));
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ INTERNAL_EXN("Invalid Custom output");
+ }
+ }
- // Make input, output and options for operator
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateCosOptions(builder);
-
- // Make COS operator
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_CosOptions, options.Union());
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> circle_custom_options;
+ std::vector<uint8_t> custom_options_vec{node->custom_options().begin(),
+ node->custom_options().end()};
+ circle_custom_options = builder.CreateVector(custom_options_vec);
+ auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, circle::BuiltinOptions_NONE,
+ flatbuffers::Offset<void>(), circle_custom_options);
gd._operators.push_back(op_offset);
}
+void OperationExporter::visit(luci::CircleDepthToSpace *node)
+{
+ export_simple(node, circle::BuiltinOperator_DEPTH_TO_SPACE,
+ circle::BuiltinOptions_DepthToSpaceOptions,
+ CreateDepthToSpaceOptions(builder, node->block_size()).Union());
+}
+
void OperationExporter::visit(luci::CircleDepthwiseConv2D *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_DEPTHWISE_CONV_2D);
+ export_simple(node, circle::BuiltinOperator_DEPTHWISE_CONV_2D,
+ circle::BuiltinOptions_DepthwiseConv2DOptions,
+ CreateDepthwiseConv2DOptions(builder, getOpPadding(node->padding()),
+ node->stride()->w(), node->stride()->h(),
+ node->depthMultiplier(),
+ to_circle_actfunc(node->fusedActivationFunction()),
+ node->dilation()->w(), node->dilation()->h())
+ .Union());
+}
- // Make input, output and options for operator
- std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->filter()),
- get_tensor_index(node->bias())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- circle::Padding padding = getOpPadding(node->padding());
- auto options = CreateDepthwiseConv2DOptions(builder, padding, node->stride()->w(),
- node->stride()->h(), node->depthMultiplier(),
- to_circle_actfunc(node->fusedActivationFunction()));
+void OperationExporter::visit(luci::CircleDiv *node)
+{
+ export_simple(
+ node, circle::BuiltinOperator_DIV, circle::BuiltinOptions_DivOptions,
+ CreateDivOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
+}
- // Make DEPTHWISE_CONV_2D operator
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_DepthwiseConv2DOptions, options.Union());
- gd._operators.push_back(op_offset);
+void OperationExporter::visit(luci::CircleElu *node)
+{
+ export_simple(node, circle::BuiltinOperator_ELU);
}
-void OperationExporter::visit(luci::CircleDiv *node)
+void OperationExporter::visit(luci::CircleEqual *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_DIV);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateDivOptions(builder, to_circle_actfunc(node->fusedActivationFunction()));
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_DivOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_EQUAL, circle::BuiltinOptions_EqualOptions,
+ CreateEqualOptions(builder).Union());
}
void OperationExporter::visit(luci::CircleExp *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_EXP);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateAbsOptions(builder);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_ExpOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_EXP, circle::BuiltinOptions_ExpOptions,
+ CreateExpOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleExpandDims *node)
+{
+ export_simple(node, circle::BuiltinOperator_EXPAND_DIMS, circle::BuiltinOptions_ExpandDimsOptions,
+ CreateExpandDimsOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleFill *node)
+{
+ export_simple(node, circle::BuiltinOperator_FILL, circle::BuiltinOptions_FillOptions,
+ CreateFillOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleFloor *node)
+{
+ export_simple(node, circle::BuiltinOperator_FLOOR);
+}
+
+void OperationExporter::visit(luci::CircleFloorDiv *node)
+{
+ export_simple(node, circle::BuiltinOperator_FLOOR_DIV, circle::BuiltinOptions_FloorDivOptions,
+ CreateFloorDivOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleFloorMod *node)
+{
+ export_simple(node, circle::BuiltinOperator_FLOOR_MOD, circle::BuiltinOptions_FloorModOptions,
+ CreateFloorModOptions(builder).Union());
}
void OperationExporter::visit(luci::CircleFullyConnected *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_FULLY_CONNECTED);
+ export_simple(
+ node, circle::BuiltinOperator_FULLY_CONNECTED, circle::BuiltinOptions_FullyConnectedOptions,
+ CreateFullyConnectedOptions(builder, to_circle_actfunc(node->fusedActivationFunction()))
+ .Union());
+}
- // Make input, output and options for operator
- std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
- get_tensor_index(node->weights()),
- get_tensor_index(node->bias())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options =
- CreateFullyConnectedOptions(builder, to_circle_actfunc(node->fusedActivationFunction()));
+void OperationExporter::visit(luci::CircleGather *node)
+{
+ export_simple(node, circle::BuiltinOperator_GATHER, circle::BuiltinOptions_GatherOptions,
+ CreateGatherOptions(builder, node->axis()).Union());
+}
- // Make FULLY_CONNECTED operator
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_FullyConnectedOptions, options.Union());
- gd._operators.push_back(op_offset);
+void OperationExporter::visit(luci::CircleGatherNd *node)
+{
+ export_simple(node, circle::BuiltinOperator_GATHER_ND, circle::BuiltinOptions_GatherNdOptions,
+ CreateGatherNdOptions(builder).Union());
}
-void OperationExporter::visit(luci::CircleLogicalNot *node)
+void OperationExporter::visit(luci::CircleGreater *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_LOGICAL_NOT);
+ export_simple(node, circle::BuiltinOperator_GREATER, circle::BuiltinOptions_GreaterOptions,
+ CreateGreaterOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleGreaterEqual *node)
+{
+ export_simple(node, circle::BuiltinOperator_GREATER_EQUAL,
+ circle::BuiltinOptions_GreaterEqualOptions,
+ CreateGreaterEqualOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleIf *node)
+{
+ auto if_outs = loco::succs(node);
+ assert(if_outs.size() == node->output_count());
+
+ uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_IF, node->op_version());
+ std::vector<int32_t> inputs_vec;
+ std::vector<int32_t> outputs_vec;
+
+ inputs_vec.push_back(get_tensor_index(node->cond()));
+ for (uint32_t idx = 0; idx < node->input_count(); ++idx)
+ inputs_vec.push_back(get_tensor_index(node->input(idx)));
+
+ for (uint32_t idx = 0; idx < node->output_count(); ++idx)
+ {
+ // store in order of index
+ bool found = false;
+ for (auto out : if_outs)
+ {
+ auto if_out = loco::must_cast<luci::CircleIfOut *>(out);
+ if (if_out->index() == static_cast<int32_t>(idx))
+ {
+ outputs_vec.push_back(get_tensor_index(if_out));
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ INTERNAL_EXN("Invalid CircleIf output");
+ }
+ }
- // Make input, output and options for operator
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateLogicalNotOptions(builder);
-
- // Make LOGICAL_NOT operator
+ auto options = CreateIfOptions(builder, node->then_branch(), node->else_branch());
auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_LogicalNotOptions, options.Union());
+ circle::BuiltinOptions_IfOptions, options.Union());
gd._operators.push_back(op_offset);
}
+void OperationExporter::visit(luci::CircleL2Normalize *node)
+{
+ export_simple(
+ node, circle::BuiltinOperator_L2_NORMALIZATION, circle::BuiltinOptions_L2NormOptions,
+ CreateL2NormOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
+}
+
+void OperationExporter::visit(luci::CircleL2Pool2D *node)
+{
+ export_pool_2d<luci::CircleL2Pool2D>(node, circle::BuiltinOperator_L2_POOL_2D);
+}
+
+void OperationExporter::visit(luci::CircleLeakyRelu *node)
+{
+ export_simple(node, circle::BuiltinOperator_LEAKY_RELU, circle::BuiltinOptions_LeakyReluOptions,
+ CreateLeakyReluOptions(builder, node->alpha()).Union());
+}
+
+void OperationExporter::visit(luci::CircleLess *node)
+{
+ export_simple(node, circle::BuiltinOperator_LESS, circle::BuiltinOptions_LessOptions,
+ CreateLessOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleLessEqual *node)
+{
+ export_simple(node, circle::BuiltinOperator_LESS_EQUAL, circle::BuiltinOptions_LessEqualOptions,
+ CreateLessEqualOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleLocalResponseNormalization *node)
+{
+ export_simple(node, circle::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION,
+ circle::BuiltinOptions_LocalResponseNormalizationOptions,
+ CreateLocalResponseNormalizationOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleLog *node)
+{
+ export_simple(node, circle::BuiltinOperator_LOG);
+}
+
+void OperationExporter::visit(luci::CircleLogicalAnd *node)
+{
+ export_simple(node, circle::BuiltinOperator_LOGICAL_AND, circle::BuiltinOptions_LogicalAndOptions,
+ CreateLogicalAndOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleLogicalNot *node)
+{
+ export_simple(node, circle::BuiltinOperator_LOGICAL_NOT, circle::BuiltinOptions_LogicalNotOptions,
+ CreateLogicalNotOptions(builder).Union());
+}
+
void OperationExporter::visit(luci::CircleLogicalOr *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_LOGICAL_OR);
+ export_simple(node, circle::BuiltinOperator_LOGICAL_OR, circle::BuiltinOptions_LogicalOrOptions,
+ CreateLogicalOrOptions(builder).Union());
+}
- // Make input, output and options for operator
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateLogicalOrOptions(builder);
+void OperationExporter::visit(luci::CircleLogistic *node)
+{
+ export_simple(node, circle::BuiltinOperator_LOGISTIC);
+}
- // Make LOGICAL_OR operator
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_LogicalOrOptions, options.Union());
- gd._operators.push_back(op_offset);
+void OperationExporter::visit(luci::CircleLogSoftmax *node)
+{
+ export_simple(node, circle::BuiltinOperator_LOG_SOFTMAX, circle::BuiltinOptions_LogSoftmaxOptions,
+ CreateLogSoftmaxOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleMatrixDiag *node)
+{
+ export_simple(node, circle::BuiltinOperator_MATRIX_DIAG, circle::BuiltinOptions_MatrixDiagOptions,
+ CreateMatrixDiagOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleMatrixSetDiag *node)
+{
+ export_simple(node, circle::BuiltinOperator_MATRIX_SET_DIAG,
+ circle::BuiltinOptions_MatrixSetDiagOptions,
+ CreateMatrixSetDiagOptions(builder).Union());
}
void OperationExporter::visit(luci::CircleMaximum *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_MAXIMUM);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateMaximumMinimumOptions(builder);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_MaximumMinimumOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_MAXIMUM, circle::BuiltinOptions_MaximumMinimumOptions,
+ CreateMaximumMinimumOptions(builder).Union());
}
void OperationExporter::visit(luci::CircleMaxPool2D *node)
@@ -362,259 +662,568 @@ void OperationExporter::visit(luci::CircleMaxPool2D *node)
void OperationExporter::visit(luci::CircleMean *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_MEAN);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
- get_tensor_index(node->reduction_indices())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateReducerOptions(builder, node->keep_dims());
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_ReducerOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_MEAN, circle::BuiltinOptions_ReducerOptions,
+ CreateReducerOptions(builder, node->keep_dims()).Union());
+}
+
+void OperationExporter::visit(luci::CircleMinimum *node)
+{
+ export_simple(node, circle::BuiltinOperator_MINIMUM, circle::BuiltinOptions_MaximumMinimumOptions,
+ CreateMaximumMinimumOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleMirrorPad *node)
+{
+ export_simple(node, circle::BuiltinOperator_MIRROR_PAD, circle::BuiltinOptions_MirrorPadOptions,
+ CreateMirrorPadOptions(builder, to_circle_mirrorpadmode(node->mode())).Union());
}
void OperationExporter::visit(luci::CircleMul *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_MUL);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateMulOptions(builder, to_circle_actfunc(node->fusedActivationFunction()));
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_MulOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(
+ node, circle::BuiltinOperator_MUL, circle::BuiltinOptions_MulOptions,
+ CreateMulOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
}
-void OperationExporter::visit(luci::CirclePack *node)
+void OperationExporter::visit(luci::CircleNeg *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_PACK);
- std::vector<int32_t> inputs_vec;
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
+ export_simple(node, circle::BuiltinOperator_NEG, circle::BuiltinOptions_NegOptions,
+ CreateNegOptions(builder).Union());
+}
- for (uint32_t i = 0; i < node->values_count(); ++i)
- inputs_vec.push_back(get_tensor_index(node->values(i)));
+void OperationExporter::visit(luci::CircleNotEqual *node)
+{
+ export_simple(node, circle::BuiltinOperator_NOT_EQUAL, circle::BuiltinOptions_NotEqualOptions,
+ CreateNotEqualOptions(builder).Union());
+}
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreatePackOptions(builder, node->values_count(), node->axis());
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_PackOptions, options.Union());
- gd._operators.push_back(op_offset);
+void OperationExporter::visit(luci::CircleOneHot *node)
+{
+ export_simple(node, circle::BuiltinOperator_ONE_HOT, circle::BuiltinOptions_OneHotOptions,
+ CreateOneHotOptions(builder, node->axis()).Union());
+}
+
+void OperationExporter::visit(luci::CirclePack *node)
+{
+ export_simple(node, circle::BuiltinOperator_PACK, circle::BuiltinOptions_PackOptions,
+ CreatePackOptions(builder, node->values_count(), node->axis()).Union());
}
void OperationExporter::visit(luci::CirclePad *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_PAD);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
- get_tensor_index(node->paddings())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreatePadOptions(builder);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_PadOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_PAD, circle::BuiltinOptions_PadOptions,
+ CreatePadOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CirclePow *node)
+{
+ export_simple(node, circle::BuiltinOperator_POW, circle::BuiltinOptions_PowOptions,
+ CreatePowOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CirclePRelu *node)
+{
+ export_simple(node, circle::BuiltinOperator_PRELU);
+}
+
+void OperationExporter::visit(luci::CircleRange *node)
+{
+ export_simple(node, circle::BuiltinOperator_RANGE, circle::BuiltinOptions_RangeOptions,
+ CreateRangeOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleRank *node)
+{
+ export_simple(node, circle::BuiltinOperator_RANK, circle::BuiltinOptions_RankOptions,
+ CreateRankOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleReduceAny *node)
+{
+ export_simple(node, circle::BuiltinOperator_REDUCE_ANY, circle::BuiltinOptions_ReducerOptions,
+ CreateReducerOptions(builder, node->keep_dims()).Union());
+}
+
+void OperationExporter::visit(luci::CircleReduceMax *node)
+{
+ export_simple(node, circle::BuiltinOperator_REDUCE_MAX, circle::BuiltinOptions_ReducerOptions,
+ CreateReducerOptions(builder, node->keep_dims()).Union());
+}
+
+void OperationExporter::visit(luci::CircleReduceMin *node)
+{
+ export_simple(node, circle::BuiltinOperator_REDUCE_MIN, circle::BuiltinOptions_ReducerOptions,
+ CreateReducerOptions(builder, node->keep_dims()).Union());
+}
+
+void OperationExporter::visit(luci::CircleReduceProd *node)
+{
+ export_simple(node, circle::BuiltinOperator_REDUCE_PROD, circle::BuiltinOptions_ReducerOptions,
+ CreateReducerOptions(builder, node->keep_dims()).Union());
}
void OperationExporter::visit(luci::CircleRelu *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_RELU);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->features())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs);
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_RELU);
}
void OperationExporter::visit(luci::CircleRelu6 *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_RELU6);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->features())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs);
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_RELU6);
}
-void OperationExporter::visit(luci::CircleReshape *node)
+void OperationExporter::visit(luci::CircleReluN1To1 *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_RESHAPE);
-
- // Create inputs and outputs.
- std::vector<int32_t> inputs_vec{get_tensor_index(node->tensor()),
- get_tensor_index(node->shape())};
- std::vector<int32_t> outputs_vec{get_tensor_index(node)};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
+ export_simple(node, circle::BuiltinOperator_RELU_N1_TO_1);
+}
- // Create options.
+void OperationExporter::visit(luci::CircleReshape *node)
+{
auto new_shape = builder.CreateVector<int32_t>(
node->newShape()->rank(), [node](size_t i) { return node->newShape()->dim(i); });
- auto options = CreateReshapeOptions(builder, new_shape);
- // Create the operator.
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_ReshapeOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_RESHAPE, circle::BuiltinOptions_ReshapeOptions,
+ CreateReshapeOptions(builder, new_shape).Union());
}
-void OperationExporter::visit(luci::CircleRsqrt *node)
+void OperationExporter::visit(luci::CircleResizeBilinear *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_RSQRT);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
+ export_simple(
+ node, circle::BuiltinOperator_RESIZE_BILINEAR, circle::BuiltinOptions_ResizeBilinearOptions,
+ CreateResizeBilinearOptions(builder, node->align_corners(), node->half_pixel_centers())
+ .Union());
+}
+
+void OperationExporter::visit(luci::CircleResizeNearestNeighbor *node)
+{
+ export_simple(node, circle::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
+ circle::BuiltinOptions_ResizeNearestNeighborOptions,
+ CreateResizeNearestNeighborOptions(builder, node->align_corners()).Union());
+}
+
+void OperationExporter::visit(luci::CircleReverseSequence *node)
+{
+ export_simple(
+ node, circle::BuiltinOperator_REVERSE_SEQUENCE, circle::BuiltinOptions_ReverseSequenceOptions,
+ CreateReverseSequenceOptions(builder, node->seq_axis(), node->batch_axis()).Union());
+}
+
+void OperationExporter::visit(luci::CircleReverseV2 *node)
+{
+ uint32_t op_idx =
+ md.registerBuiltinOpcode(circle::BuiltinOperator_REVERSE_V2, node->op_version());
+ std::vector<int32_t> inputs_vec{get_tensor_index(node->tensor()), get_tensor_index(node->axis())};
std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs);
+ auto options = CreateReverseV2Options(builder);
+ auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
+ circle::BuiltinOptions_ReverseSequenceOptions, options.Union());
gd._operators.push_back(op_offset);
}
+void OperationExporter::visit(luci::CircleRound *node)
+{
+ export_simple(node, circle::BuiltinOperator_ROUND);
+}
+
+void OperationExporter::visit(luci::CircleRsqrt *node)
+{
+ export_simple(node, circle::BuiltinOperator_RSQRT);
+}
+
+void OperationExporter::visit(luci::CircleScatterNd *node)
+{
+ export_simple(node, circle::BuiltinOperator_SCATTER_ND, circle::BuiltinOptions_ScatterNdOptions,
+ CreateScatterNdOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleSegmentSum *node)
+{
+ export_simple(node, circle::BuiltinOperator_SEGMENT_SUM, circle::BuiltinOptions_SegmentSumOptions,
+ CreateSegmentSumOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleSelect *node)
+{
+ export_simple(node, circle::BuiltinOperator_SELECT, circle::BuiltinOptions_SelectOptions,
+ CreateSelectOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleSelectV2 *node)
+{
+ export_simple(node, circle::BuiltinOperator_SELECT_V2, circle::BuiltinOptions_SelectV2Options,
+ CreateSelectV2Options(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleShape *node)
+{
+ export_simple(node, circle::BuiltinOperator_SHAPE, circle::BuiltinOptions_ShapeOptions,
+ CreateShapeOptions(builder, to_circle_tensortype(node->out_type())).Union());
+}
+
+void OperationExporter::visit(luci::CircleSin *node)
+{
+ export_simple(node, circle::BuiltinOperator_SIN);
+}
+
+void OperationExporter::visit(luci::CircleSlice *node)
+{
+ export_simple(node, circle::BuiltinOperator_SLICE, circle::BuiltinOptions_SliceOptions,
+ CreateSliceOptions(builder).Union());
+}
+
void OperationExporter::visit(luci::CircleSoftmax *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SOFTMAX);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->logits())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
+ export_simple(node, circle::BuiltinOperator_SOFTMAX, circle::BuiltinOptions_SoftmaxOptions,
+ CreateSoftmaxOptions(builder, node->beta()).Union());
+}
+
+void OperationExporter::visit(luci::CircleSpaceToBatchND *node)
+{
+ export_simple(node, circle::BuiltinOperator_SPACE_TO_BATCH_ND,
+ circle::BuiltinOptions_SpaceToBatchNDOptions,
+ CreateSpaceToBatchNDOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleSpaceToDepth *node)
+{
+ export_simple(node, circle::BuiltinOperator_SPACE_TO_DEPTH,
+ circle::BuiltinOptions_SpaceToDepthOptions,
+ CreateSpaceToDepthOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleSparseToDense *node)
+{
+ export_simple(node, circle::BuiltinOperator_SPARSE_TO_DENSE,
+ circle::BuiltinOptions_SparseToDenseOptions,
+ CreateSparseToDenseOptions(builder, node->validate_indices()).Union());
+}
+
+void OperationExporter::visit(luci::CircleSplit *node)
+{
+ auto split_outs = loco::succs(node);
+ assert(int32_t(split_outs.size()) == node->num_split());
+
+ uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT, node->op_version());
+ // NOTE BuiltinOperator_SPLIT input is placed at second position
+ std::vector<int32_t> inputs_vec{get_tensor_index(node->split_dim()),
+ get_tensor_index(node->input())};
+ std::vector<int32_t> outputs_vec;
+
+ for (int32_t index = 0; index < node->num_split(); index++)
+ {
+ // store in order of index
+ bool found = false;
+ for (auto out : split_outs)
+ {
+ auto split_out = loco::must_cast<luci::CircleSplitOut *>(out);
+ if (split_out->index() == index)
+ {
+ outputs_vec.push_back(get_tensor_index(split_out));
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ INTERNAL_EXN("Invalid Split output");
+ }
+ }
+
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateSoftmaxOptions(builder, node->beta());
+ auto options = CreateSplitOptions(builder, node->num_split());
auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_SoftmaxOptions, options.Union());
+ circle::BuiltinOptions_SplitOptions, options.Union());
gd._operators.push_back(op_offset);
}
-void OperationExporter::visit(luci::CircleSqrt *node)
+void OperationExporter::visit(luci::CircleSplitV *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SQRT);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
+ auto split_outs = loco::succs(node);
+ assert(int32_t(split_outs.size()) == node->num_split());
+
+ uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT_V, node->op_version());
+ std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
+ get_tensor_index(node->size_splits()),
+ get_tensor_index(node->split_dim())};
+ std::vector<int32_t> outputs_vec;
+
+ for (int32_t index = 0; index < node->num_split(); index++)
+ {
+ // store in order of index
+ bool found = false;
+ for (auto out : split_outs)
+ {
+ auto split_out = loco::must_cast<luci::CircleSplitVOut *>(out);
+ if (split_out->index() == index)
+ {
+ outputs_vec.push_back(get_tensor_index(split_out));
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ INTERNAL_EXN("Invalid SplitV output");
+ }
+ }
+
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs);
+ auto options = CreateSplitVOptions(builder, node->num_split());
+ auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
+ circle::BuiltinOptions_SplitVOptions, options.Union());
gd._operators.push_back(op_offset);
}
+void OperationExporter::visit(luci::CircleSqrt *node)
+{
+ export_simple(node, circle::BuiltinOperator_SQRT);
+}
+
+void OperationExporter::visit(luci::CircleSquare *node)
+{
+ export_simple(node, circle::BuiltinOperator_SQUARE, circle::BuiltinOptions_SquareOptions,
+ CreateSquareOptions(builder).Union());
+}
+
void OperationExporter::visit(luci::CircleSquaredDifference *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SQUARED_DIFFERENCE);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateSquaredDifferenceOptions(builder);
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_SquaredDifferenceOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(node, circle::BuiltinOperator_SQUARED_DIFFERENCE,
+ circle::BuiltinOptions_SquaredDifferenceOptions,
+ CreateSquaredDifferenceOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleSqueeze *node)
+{
+ auto squeeze_dims = builder.CreateVector<int32_t>(node->squeeze_dims());
+ export_simple(node, circle::BuiltinOperator_SQUEEZE, circle::BuiltinOptions_SqueezeOptions,
+ CreateSqueezeOptions(builder, squeeze_dims).Union());
+}
+
+void OperationExporter::visit(luci::CircleStridedSlice *node)
+{
+ export_simple(node, circle::BuiltinOperator_STRIDED_SLICE,
+ circle::BuiltinOptions_StridedSliceOptions,
+ CreateStridedSliceOptions(builder, node->begin_mask(), node->end_mask(),
+ node->ellipsis_mask(), node->new_axis_mask(),
+ node->shrink_axis_mask())
+ .Union());
}
void OperationExporter::visit(luci::CircleSub *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SUB);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
- auto inputs = builder.CreateVector(inputs_vec);
- auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateSubOptions(builder, to_circle_actfunc(node->fusedActivationFunction()));
- auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_SubOptions, options.Union());
- gd._operators.push_back(op_offset);
+ export_simple(
+ node, circle::BuiltinOperator_SUB, circle::BuiltinOptions_SubOptions,
+ CreateSubOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
}
-// TODO CircleTanh
+void OperationExporter::visit(luci::CircleSum *node)
+{
+ export_simple(node, circle::BuiltinOperator_SUM, circle::BuiltinOptions_ReducerOptions,
+ CreateReducerOptions(builder, node->keep_dims()).Union());
+}
-void OperationExporter::visit(luci::CircleTranspose *node)
+void OperationExporter::visit(luci::CircleTanh *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_TRANSPOSE);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->arg(0)), get_tensor_index(node->arg(1))};
- std::vector<int32_t> outputs_vec{get_tensor_index(node)};
+ export_simple(node, circle::BuiltinOperator_TANH);
+}
+
+void OperationExporter::visit(luci::CircleTile *node)
+{
+ export_simple(node, circle::BuiltinOperator_TILE, circle::BuiltinOptions_TileOptions,
+ CreateTileOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleTopKV2 *node)
+{
+ auto topkv2_outs = loco::succs(node);
+ int outs_count = int32_t(topkv2_outs.size());
+ assert(outs_count == 2);
+
+ uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_TOPK_V2, node->op_version());
+ std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->k())};
+ std::vector<int32_t> outputs_vec;
+
+ for (int32_t index = 0; index < outs_count; index++)
+ {
+ // store in order of index
+ bool found = false;
+ for (auto out : topkv2_outs)
+ {
+ auto topkv2_out = loco::must_cast<luci::CircleTopKV2Out *>(out);
+ if (topkv2_out->index() == index)
+ {
+ outputs_vec.push_back(get_tensor_index(topkv2_out));
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ INTERNAL_EXN("Invalid TopKV2 output");
+ }
+ }
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateTransposeOptions(builder);
-
- auto op_offset =
- CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions::BuiltinOptions_TransposeOptions, options.Union());
+ auto options = CreateTopKV2Options(builder);
+ auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
+ circle::BuiltinOptions_TopKV2Options, options.Union());
gd._operators.push_back(op_offset);
}
+void OperationExporter::visit(luci::CircleTranspose *node)
+{
+ export_simple(node, circle::BuiltinOperator_TRANSPOSE, circle::BuiltinOptions_TransposeOptions,
+ CreateTransposeOptions(builder).Union());
+}
+
void OperationExporter::visit(luci::CircleTransposeConv *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_TRANSPOSE_CONV);
+ export_simple(node, circle::BuiltinOperator_TRANSPOSE_CONV,
+ circle::BuiltinOptions_TransposeConvOptions,
+ CreateTransposeConvOptions(builder, getOpPadding(node->padding()),
+ node->stride()->w(), node->stride()->h())
+ .Union());
+}
+
+void OperationExporter::visit(luci::CircleUnpack *node)
+{
+ LOGGER(l);
+ auto settings = luci::UserSettings::settings();
+
+ auto unpack_outs = loco::succs(node);
+ // NOTE real models may not use all of the outputs
+ if (static_cast<int32_t>(unpack_outs.size()) != node->num())
+ {
+ if (settings->get(luci::UserSettings::Key::DisableValidation))
+ {
+ WARN(l) << "Warning: export Unpack(" << node->name() << ") 'num' not same as outputs";
+ }
+ else
+ assert(false);
+ }
+
+ uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_UNPACK, node->op_version());
+ std::vector<int32_t> inputs_vec{get_tensor_index(node->value())};
+ std::vector<int32_t> outputs_vec;
+
+ for (int32_t index = 0; index < node->num(); index++)
+ {
+ // store in order of index
+ bool found = false;
+ for (auto out : unpack_outs)
+ {
+ auto unpack_out = loco::must_cast<luci::CircleUnpackOut *>(out);
+ if (unpack_out->index() == index)
+ {
+ outputs_vec.push_back(get_tensor_index(unpack_out));
+ found = true;
+ break;
+ }
+ }
+ // NOTE real models may not use all of the outputs
+ if (!found)
+ {
+ if (settings->get(luci::UserSettings::Key::DisableValidation))
+ {
+ WARN(l) << "Warning: export Unpack(" << node->name() << ") output " << index << " not used";
+ }
+ else
+ assert(false);
+ }
+ }
- // Make input, output and options for operator
- std::vector<int32_t> inputs_vec{get_tensor_index(node->inputSizes()),
- get_tensor_index(node->filter()),
- get_tensor_index(node->outBackprop())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- circle::Padding padding = getOpPadding(node->padding());
- auto options =
- CreateTransposeConvOptions(builder, padding, node->stride()->w(), node->stride()->h());
-
- // Make TRANSPOSE_CONV operator
+ auto options = CreateUnpackOptions(builder, node->num(), node->axis());
auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_TransposeConvOptions, options.Union());
+ circle::BuiltinOptions_UnpackOptions, options.Union());
gd._operators.push_back(op_offset);
}
-void OperationExporter::visit(luci::CircleInstanceNorm *node)
+void OperationExporter::visit(luci::CircleWhere *node)
{
- uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_INSTANCE_NORM);
- std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->gamma()),
- get_tensor_index(node->beta())};
- std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
+ export_simple(node, circle::BuiltinOperator_WHERE, circle::BuiltinOptions_WhereOptions,
+ CreateWhereOptions(builder).Union());
+}
+
+void OperationExporter::visit(luci::CircleWhile *node)
+{
+ auto while_outs = loco::succs(node);
+ assert(while_outs.size() == node->output_count());
+
+ uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_WHILE, node->op_version());
+ std::vector<int32_t> inputs_vec;
+ std::vector<int32_t> outputs_vec;
+
+ for (uint32_t idx = 0; idx < node->input_count(); ++idx)
+ inputs_vec.push_back(get_tensor_index(node->input(idx)));
+
+ for (uint32_t idx = 0; idx < node->output_count(); ++idx)
+ {
+ // store in order of index
+ bool found = false;
+ for (auto out : while_outs)
+ {
+ auto while_out = loco::must_cast<luci::CircleWhileOut *>(out);
+ if (while_out->index() == static_cast<int32_t>(idx))
+ {
+ outputs_vec.push_back(get_tensor_index(while_out));
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ INTERNAL_EXN("Invalid CircleWhile output");
+ }
+ }
+
auto inputs = builder.CreateVector(inputs_vec);
auto outputs = builder.CreateVector(outputs_vec);
- auto options = CreateInstanceNormOptions(builder, node->epsilon(),
- to_circle_actfunc(node->fusedActivationFunction()));
+ auto options = CreateWhileOptions(builder, node->cond_branch(), node->body_branch());
auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
- circle::BuiltinOptions_InstanceNormOptions, options.Union());
+ circle::BuiltinOptions_WhileOptions, options.Union());
gd._operators.push_back(op_offset);
}
-void OperationExporter::visit(luci::CircleEqual *node)
+void OperationExporter::visit(luci::CircleZerosLike *node)
{
- uint32_t opcode_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_EQUAL);
- std::vector<int32_t> inputs{get_tensor_index(node->x()), get_tensor_index(node->y())};
- std::vector<int32_t> outputs{get_tensor_index(node)};
-
- auto fb_inputs = builder.CreateVector(inputs);
- auto fb_outputs = builder.CreateVector(outputs);
+ export_simple(node, circle::BuiltinOperator_ZEROS_LIKE, circle::BuiltinOptions_ZerosLikeOptions,
+ CreateZerosLikeOptions(builder).Union());
+}
- auto options = CreateEqualOptions(builder);
+void OperationExporter::visit(luci::CircleBCQFullyConnected *node)
+{
+ export_simple(node, circle::BuiltinOperator_BCQ_FULLY_CONNECTED,
+ circle::BuiltinOptions_BCQFullyConnectedOptions,
+ CreateBCQFullyConnectedOptions(builder, node->weights_hidden_size(),
+ to_circle_actfunc(node->fusedActivationFunction()))
+ .Union());
+}
- auto op_offset = CreateOperator(builder, opcode_idx, fb_inputs, fb_outputs,
- circle::BuiltinOptions_EqualOptions, options.Union());
+void OperationExporter::visit(luci::CircleBCQGather *node)
+{
+ export_simple(node, circle::BuiltinOperator_BCQ_GATHER, circle::BuiltinOptions_BCQGatherOptions,
+ CreateBCQGatherOptions(builder, node->input_hidden_size(), node->axis()).Union());
+}
- gd._operators.push_back(op_offset);
+void OperationExporter::visit(luci::CircleInstanceNorm *node)
+{
+ export_simple(node, circle::BuiltinOperator_INSTANCE_NORM,
+ circle::BuiltinOptions_InstanceNormOptions,
+ CreateInstanceNormOptions(builder, node->epsilon(),
+ to_circle_actfunc(node->fusedActivationFunction()))
+ .Union());
}
void exportNode(loco::Node *node, flatbuffers::FlatBufferBuilder &builder, SerializedModelData &md,
SerializedGraphData &gd)
{
- // TODO Use explicit tagging to prevent possible mistake
- auto isNoOp = [](loco::Node *node) {
- // If there is only one input and the TensorIndex for the input is same
- // as the TensorIndex of the output then this node is just a dummy node
- if (node->arity() == 1)
- {
- assert(node->arg(0) != nullptr);
- return get_tensor_index(node) == get_tensor_index(node->arg(0));
- }
- return false;
- };
-
- if (isNoOp(node))
- {
- // Skip if a given node is marked as NoOp (op with no effect) before
- return;
- }
-
if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
{
OperationExporter exporter{builder, md, gd};
diff --git a/compiler/luci/export/src/CircleTensorExporter.cpp b/compiler/luci/export/src/CircleTensorExporter.cpp
index ef9b9d7d9..5cad3920b 100644
--- a/compiler/luci/export/src/CircleTensorExporter.cpp
+++ b/compiler/luci/export/src/CircleTensorExporter.cpp
@@ -15,6 +15,7 @@
*/
#include "CircleTensorExporter.h"
+#include "TypeBridge.h"
#include <luci/IR/CircleNodes.h>
#include <luci/IR/CircleNodeVisitor.h>
@@ -52,6 +53,9 @@ public:
const ShapeDescription &shape(void) const { return _shape; }
void shape(const ShapeDescription &shape) { _shape = shape; }
+ luci::ShapeStatus shape_status(void) const { return _shape_status; }
+ void shape_status(luci::ShapeStatus ss) { _shape_status = ss; }
+
public:
luci::CircleConst *content(void) const { return _content; }
void content(luci::CircleConst *c) { _content = c; }
@@ -62,8 +66,9 @@ public:
private:
std::string _name;
- circle::TensorType _dtype;
- ShapeDescription _shape;
+ circle::TensorType _dtype{circle::TensorType_FLOAT32};
+ ShapeDescription _shape{};
+ luci::ShapeStatus _shape_status{luci::ShapeStatus::UNDEFINED};
luci::CircleConst *_content = nullptr;
luci::CircleQuantParam *_quantparam = nullptr;
@@ -76,30 +81,16 @@ struct NoOpDetector final : public luci::CircleNodeMutableVisitor<bool>
// Input is Virtual but does produce a Tensor
// Output is Virtual that does not produce any Tensor
bool visit(luci::CircleOutput *) final { return true; }
+ bool visit(luci::CircleOutputExclude *) final { return true; }
// Return false by default
bool visit(luci::CircleNode *) final { return false; }
};
-void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx)
+void allocateCircleTensorInfo(CircleNode *node, CircleTensorContext &ctx)
{
LOGGER(l);
- auto isNoOp = [](loco::Node *node) {
- if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
- {
- NoOpDetector d;
- return circle_node->accept(&d);
- }
- return false;
- };
-
- if (isNoOp(node))
- {
- set_tensor_index(node, get_tensor_index(node->arg(0)));
- return;
- }
-
auto tensor_index = static_cast<CircleTensorIndex>(ctx.size());
// TODO Use Graph-level metadata for Input & Output
// auto tensor_name = "t_" + std::to_string(tensor_index);
@@ -111,8 +102,10 @@ void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx)
CircleTensoInfo tensor_info;
tensor_info.name(tensor_name);
- tensor_info.dtype(TypeInference::get(node));
- tensor_info.shape(ShapeInference::get(node));
+ tensor_info.dtype(to_circle_tensortype(luci::node_dtype(node)));
+ if (node->shape_status() == ShapeStatus::VALID)
+ tensor_info.shape(to_shape_description(luci::node_shape(node)));
+ tensor_info.shape_status(node->shape_status());
tensor_info.content(dynamic_cast<luci::CircleConst *>(node));
tensor_info.quantparam(node->quantparam());
@@ -122,6 +115,108 @@ void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx)
ctx.emplace_back(tensor_info);
}
+class MultiOutputDetector final : public luci::CircleNodeMutableVisitor<bool>
+{
+public:
+ MultiOutputDetector(CircleTensorContext &ctx) : _ctx(ctx) {}
+
+private:
+ void store_outputs(luci::CircleNode *node, uint32_t count)
+ {
+ auto outs = loco::succs(node);
+ assert(outs.size() == count);
+ (void)count; // for unused variable error in release build
+ for (auto out : outs)
+ {
+ auto circle_out = loco::must_cast<luci::CircleNode *>(out);
+ allocateCircleTensorInfo(circle_out, _ctx);
+ }
+ set_tensor_index(node, -1);
+ }
+
+public:
+ bool visit(luci::CircleIfOut *) final { return true; }
+ bool visit(luci::CircleSplitOut *) final { return true; }
+ bool visit(luci::CircleSplitVOut *) final { return true; }
+ bool visit(luci::CircleTopKV2Out *) final { return true; }
+ bool visit(luci::CircleUnpackOut *) final { return true; }
+ bool visit(luci::CircleWhileOut *) final { return true; }
+
+ bool visit(luci::CircleIf *node) final
+ {
+ store_outputs(node, node->output_count());
+ return true;
+ }
+
+ bool visit(luci::CircleSplit *node) final
+ {
+ store_outputs(node, uint32_t(node->num_split()));
+ return true;
+ }
+
+ bool visit(luci::CircleSplitV *node) final
+ {
+ store_outputs(node, uint32_t(node->num_split()));
+ return true;
+ }
+
+ bool visit(luci::CircleTopKV2 *node) final
+ {
+ store_outputs(node, 2);
+ return true;
+ }
+
+ bool visit(luci::CircleUnpack *node) final
+ {
+ store_outputs(node, node->num());
+ return true;
+ }
+
+ bool visit(luci::CircleWhile *node) final
+ {
+ store_outputs(node, node->output_count());
+ return true;
+ }
+
+ // Return false by default
+ bool visit(luci::CircleNode *) final { return false; }
+
+private:
+ CircleTensorContext &_ctx;
+};
+
+void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx)
+{
+ if (node == nullptr)
+ throw std::runtime_error("allocateCIrcleTensor Failed : node is nullptr");
+
+ auto isNoOp = [](loco::Node *node) {
+ if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
+ {
+ NoOpDetector d;
+ return circle_node->accept(&d);
+ }
+ return false;
+ };
+
+ if (isNoOp(node))
+ {
+ set_tensor_index(node, -1);
+ return;
+ }
+
+ // TODO revise this when loco supports multiple outputs
+ // NOTE this will store all virtual output tensors and skip for the real node
+ if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
+ {
+ MultiOutputDetector d(ctx);
+ if (circle_node->accept(&d))
+ return;
+ }
+
+ allocateCircleTensorInfo(node, ctx);
+}
+
} // namespace
namespace
@@ -166,18 +261,22 @@ flatbuffers::Offset<circle::Buffer> encodeOpBufferByDType(FlatBufferBuilder &bui
template <>
flatbuffers::Offset<circle::Buffer> encodeOpBuffer(FlatBufferBuilder &builder, luci::CircleConst *c)
{
- // TODO use switch
- if (c->dtype() == loco::DataType::FLOAT32)
+ switch (c->dtype())
{
- return encodeOpBufferByDType<loco::DataType::FLOAT32>(builder, c);
- }
- else if (c->dtype() == loco::DataType::S32)
- {
- return encodeOpBufferByDType<loco::DataType::S32>(builder, c);
- }
- else if (c->dtype() == loco::DataType::U8)
- {
- return encodeOpBufferByDType<loco::DataType::U8>(builder, c);
+ case loco::DataType::FLOAT32:
+ return encodeOpBufferByDType<loco::DataType::FLOAT32>(builder, c);
+ case loco::DataType::S16:
+ return encodeOpBufferByDType<loco::DataType::S16>(builder, c);
+ case loco::DataType::S32:
+ return encodeOpBufferByDType<loco::DataType::S32>(builder, c);
+ case loco::DataType::S64:
+ return encodeOpBufferByDType<loco::DataType::S64>(builder, c);
+ case loco::DataType::U8:
+ return encodeOpBufferByDType<loco::DataType::U8>(builder, c);
+ case loco::DataType::BOOL:
+ return encodeOpBufferByDType<loco::DataType::BOOL>(builder, c);
+ default:
+ break;
}
INTERNAL_EXN_V("Unsupported datatype", oops::to_uint32(c->dtype()));
@@ -210,7 +309,9 @@ void exportOpDefinedTensor(const CircleTensoInfo &info, FlatBufferBuilder &build
SerializedModelData &md, SerializedGraphData &gd)
{
// Create and register output tensor shape
- auto shape_offset = encodeShape(builder, info.shape());
+ flatbuffers::Offset<Vector<int32_t>> shape_offset;
+ if (info.shape_status() == ShapeStatus::VALID)
+ shape_offset = encodeShape(builder, info.shape());
// encode and register output tensor buffer
auto buffer =
@@ -249,9 +350,21 @@ void exportOpDefinedTensors(loco::Graph *g, FlatBufferBuilder &builder, Serializ
{
CircleTensorContext tensor_ctx;
+ // NOTE There may exist dangle CircleInput that is not visited with postorder_traversal()
+ // All dangle CircleOutput should be visited by postorder_traversal()
+ auto nodes = g->nodes();
+ for (uint32_t n = 0; n < nodes->size(); ++n)
+ {
+ auto node = dynamic_cast<luci::CircleInput *>(nodes->at(n));
+ if (node != nullptr)
+ allocateCircleTensor(node, tensor_ctx);
+ }
+
for (auto node : loco::postorder_traversal(loco::output_nodes(g)))
{
- CircleNode *circle_node = dynamic_cast<luci::CircleNode *>(node);
+ CircleNode *circle_node = loco::must_cast<luci::CircleNode *>(node);
+ if (dynamic_cast<const luci::CircleInput *>(circle_node) != nullptr)
+ continue;
allocateCircleTensor(circle_node, tensor_ctx);
}
diff --git a/compiler/luci/export/src/ProgressReporter.cpp b/compiler/luci/export/src/ProgressReporter.cpp
index ac9c3d9a8..216bd3f2a 100644
--- a/compiler/luci/export/src/ProgressReporter.cpp
+++ b/compiler/luci/export/src/ProgressReporter.cpp
@@ -49,36 +49,36 @@ namespace luci
void ProgressReporter::notify(const logo::PhaseEventInfo<logo::PhaseEvent::PhaseBegin> *)
{
- LOGGER(prime);
+ LOGGER(l);
- INFO(prime) << "==============================================================";
- INFO(prime) << "luci::PhaseRunner<" << to_str(strategy()) << ">";
- INFO(prime) << "Initial graph";
- INFO(prime) << fmt(graph());
+ VERBOSE(l, 4) << "==============================================================";
+ VERBOSE(l, 4) << "luci::PhaseRunner<" << to_str(strategy()) << ">";
+ VERBOSE(l, 4) << "Initial graph";
+ VERBOSE(l, 4) << fmt(graph());
}
void ProgressReporter::notify(const logo::PhaseEventInfo<logo::PhaseEvent::PhaseEnd> *)
{
- LOGGER(prime);
+ LOGGER(l);
- INFO(prime) << "luci::PhaseRunner<" << to_str(strategy()) << "> - done";
+ VERBOSE(l, 4) << "luci::PhaseRunner<" << to_str(strategy()) << "> - done";
}
void ProgressReporter::notify(const logo::PhaseEventInfo<logo::PhaseEvent::PassBegin> *info)
{
- LOGGER(prime);
+ LOGGER(l);
- INFO(prime) << "--------------------------------------------------------------";
- INFO(prime) << "Before " << logo::pass_name(info->pass());
+ VERBOSE(l, 4) << "--------------------------------------------------------------";
+ VERBOSE(l, 4) << "Before " << logo::pass_name(info->pass());
}
void ProgressReporter::notify(const logo::PhaseEventInfo<logo::PhaseEvent::PassEnd> *info)
{
- LOGGER(prime);
+ LOGGER(l);
- INFO(prime) << "After " << logo::pass_name(info->pass())
- << " (changed: " << to_char(info->changed()) << ")";
- INFO(prime) << fmt(graph());
+ VERBOSE(l, 4) << "After " << logo::pass_name(info->pass())
+ << " (changed: " << to_char(info->changed()) << ")";
+ VERBOSE(l, 4) << fmt(graph());
}
} // namespace luci
diff --git a/compiler/luci/export/src/SerializedData.h b/compiler/luci/export/src/SerializedData.h
index 84249653c..251daa0ea 100644
--- a/compiler/luci/export/src/SerializedData.h
+++ b/compiler/luci/export/src/SerializedData.h
@@ -29,8 +29,20 @@ namespace luci
struct OpCode
{
circle::BuiltinOperator opcode;
-
- bool operator==(const OpCode &rhs) const { return opcode == rhs.opcode; }
+ std::string custom_code{""};
+ int32_t version = 1;
+
+ bool operator==(const OpCode &rhs) const
+ {
+ if (opcode == circle::BuiltinOperator_CUSTOM)
+ {
+ return custom_code == rhs.custom_code;
+ }
+ else
+ {
+ return opcode == rhs.opcode;
+ }
+ }
};
} // namespace luci
@@ -53,11 +65,13 @@ namespace luci
*/
struct SubGraphContext
{
+ /// @brief SubGraph name
+ std::string _name;
/// @brief SubGraph input tensor id
std::vector<int32_t> _inputs;
/// @brief SubGraph output tensor id
std::vector<int32_t> _outputs;
- /// @DataFormat for SubGraph
+ /// @brief DataFormat for SubGraph
circle::DataFormat _data_format{circle::DataFormat::DataFormat_CHANNELS_LAST};
};
@@ -68,7 +82,6 @@ struct SerializedModelData final
SerializedModelData(const SerializedModelData &) = delete;
std::unordered_map<OpCode, uint32_t> _operator_codes;
- std::unordered_map<OpCode, std::string> _custom_operator_codes;
std::vector<flatbuffers::Offset<circle::Buffer>> _buffers;
/**
@@ -76,7 +89,7 @@ struct SerializedModelData final
* @param builtin_code
* @return idx of opcode in table of opcodes (see schema)
*/
- uint32_t registerBuiltinOpcode(circle::BuiltinOperator builtin_code);
+ uint32_t registerBuiltinOpcode(circle::BuiltinOperator builtin_code, const int32_t op_version);
uint32_t registerCustomOpcode(const std::string &custom_op);
};
diff --git a/compiler/luci/export/src/TypeBridge.cpp b/compiler/luci/export/src/TypeBridge.cpp
new file mode 100644
index 000000000..9ccd52376
--- /dev/null
+++ b/compiler/luci/export/src/TypeBridge.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TypeBridge.h"
+
+#include "CircleExporterUtils.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/IR/CircleNodeVisitor.h>
+#include <luci/Service/CircleTypeInference.h>
+#include <luci/Service/CircleShapeInference.h>
+
+#include <loco/Service/TypeInference.h>
+#include <loco/Service/ShapeInference.h>
+
+namespace
+{
+
+/**
+ * @brief CopySelector will return condition of copy shape/type inference to node
+ */
+struct CopySelector final : public luci::CircleNodeVisitor<bool>
+{
+ // return false(don't copy) for nodes that provides shape/type from nature
+ bool visit(const luci::CircleInput *) final { return false; }
+ bool visit(const luci::CircleConst *) final { return false; }
+
+ // default is copy attributes
+ bool visit(const luci::CircleNode *) { return true; }
+};
+
+} // namespace
+
+namespace luci
+{
+
+loco::TensorShape node_shape(CircleNode *node)
+{
+ loco::TensorShape shape;
+
+ shape.rank(node->rank());
+ for (uint32_t r = 0; r < node->rank(); ++r)
+ {
+ shape.dim(r) = loco::Dimension(node->dim(r).value());
+ }
+ return shape;
+}
+
+loco::DataType node_dtype(CircleNode *node) { return node->dtype(); }
+
+void copy_shape_dtype(loco::Graph *graph)
+{
+ /**
+ * @note We will iterate all the nodes in the graph to include dangle nodes
+ */
+ auto nodes = graph->nodes();
+ for (uint32_t n = 0; n < nodes->size(); ++n)
+ {
+ auto node = loco::must_cast<luci::CircleNode *>(nodes->at(n));
+
+ CopySelector cs;
+ if (node->accept(&cs))
+ {
+ // NOTE not all nodes have infered shape/dtype: multiple outs may not be
+ // visited when outputs are not used
+ // TODO fix shape inference traversal
+ // NOTE when loco supports multiple outputs in nature this issue should be
+ // resolved also
+
+ if (loco::dtype_known(node))
+ {
+ node->dtype(loco::dtype_get(node));
+ }
+
+ if (loco::shape_known(node))
+ {
+ auto shape = loco::shape_get(node).as<loco::TensorShape>();
+ node->rank(shape.rank());
+ for (uint32_t r = 0; r < shape.rank(); ++r)
+ {
+ node->dim(r) = loco::Dimension(shape.dim(r).value());
+ }
+
+ // ShapeStatus should be update only when the status was UNDEFINED
+ if (node->shape_status() == ShapeStatus::UNDEFINED)
+ node->shape_status(ShapeStatus::VALID);
+ }
+ }
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/export/src/TypeBridge.h b/compiler/luci/export/src/TypeBridge.h
new file mode 100644
index 000000000..a63fbce54
--- /dev/null
+++ b/compiler/luci/export/src/TypeBridge.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TYPE_BRIDGE_H__
+#define __TYPE_BRIDGE_H__
+
+#include <luci/IR/CircleNode.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+/**
+ * @brief node_shape() will return loco::TensorShape of CircleNode
+ */
+loco::TensorShape node_shape(CircleNode *node);
+
+/**
+ * @brief node_dtype() will return loco::DataType of CircleNode
+ */
+loco::DataType node_dtype(CircleNode *node);
+
+/**
+ * @brief copy_shape_dtype() will copy shape and dtype inference data to CircleNode
+ */
+void copy_shape_dtype(loco::Graph *graph);
+
+} // namespace luci
+
+#endif // __TYPE_BRIDGE_H__
diff --git a/compiler/luci/import/CMakeLists.txt b/compiler/luci/import/CMakeLists.txt
index bc9a9152a..2ae00b837 100644
--- a/compiler/luci/import/CMakeLists.txt
+++ b/compiler/luci/import/CMakeLists.txt
@@ -7,6 +7,7 @@ target_include_directories(luci_import PRIVATE src)
target_include_directories(luci_import PUBLIC include)
target_link_libraries(luci_import PUBLIC luci_lang)
target_link_libraries(luci_import PUBLIC mio_circle)
+target_link_libraries(luci_import PRIVATE luci_env)
target_link_libraries(luci_import PRIVATE luci_log)
target_link_libraries(luci_import PRIVATE luci_logex)
target_link_libraries(luci_import PRIVATE nncc_common)
diff --git a/compiler/luci/import/include/luci/Import/CircleReader.h b/compiler/luci/import/include/luci/Import/CircleReader.h
index fcbe09ceb..3d85b9e35 100644
--- a/compiler/luci/import/include/luci/Import/CircleReader.h
+++ b/compiler/luci/import/include/luci/Import/CircleReader.h
@@ -21,6 +21,7 @@
#include <luci/IR/AttrFusedActFunc.h>
#include <luci/IR/AttrPadding.h>
+#include <luci/IR/CircleNode.h>
#include <luci/IR/CircleQuantParam.h>
#include <loco.h>
@@ -42,9 +43,13 @@ const circle::QuantizationParametersT *tensor_quantization(const circle::TensorT
loco::DataType luci_datatype(circle::TensorType type);
FusedActFunc luci_actfunc(const circle::ActivationFunctionType type);
Padding luci_padding(const circle::Padding padding);
+MirrorPadMode luci_mirrorpad_mode(const circle::MirrorPadMode mode);
std::unique_ptr<CircleQuantParam>
luci_quantparam(const circle::QuantizationParametersT *quantization);
+/// @brief Copy common tensor attributes such as name, type, etc. to node.
+void copy_tensor_attributes(const circle::TensorT &tensor, CircleNode *node);
+
/**
* @brief Loads Circle file and provides helpers to access attributes
*/
@@ -56,6 +61,9 @@ private:
using CircleOperators_t = std::vector<std::unique_ptr<circle::OperatorT>>;
using CircleOperatorCodes_t = std::vector<std::unique_ptr<circle::OperatorCodeT>>;
+ using CircleSubGraphsPtr_t = flatbuffers::Vector<flatbuffers::Offset<circle::SubGraph>>;
+ using CircleTensorsPtr_t = flatbuffers::Vector<flatbuffers::Offset<circle::Tensor>>;
+
public:
CircleReader() = default;
@@ -68,6 +76,8 @@ public:
const std::vector<int32_t> &outputs() const { return _current_subgraph->outputs; }
const std::string &name() const { return _current_subgraph->name; }
+ const CircleTensorsPtr_t *tensors_ptr() const { return _tensors_ptr; }
+
uint32_t num_subgraph() const { return _model->subgraphs.size(); }
circle::BuiltinOperator builtin_code(const circle::OperatorT &op) const;
@@ -80,6 +90,9 @@ public:
private:
std::unique_ptr<const circle::ModelT> _model;
const circle::SubGraphT *_current_subgraph{nullptr};
+
+ const circle::Model *_model_ptr{nullptr};
+ const CircleTensorsPtr_t *_tensors_ptr{nullptr};
};
} // namespace luci
diff --git a/compiler/luci/import/include/luci/Import/GraphBuilder.h b/compiler/luci/import/include/luci/Import/GraphBuilder.h
index 61f673fb6..548264dac 100644
--- a/compiler/luci/import/include/luci/Import/GraphBuilder.h
+++ b/compiler/luci/import/include/luci/Import/GraphBuilder.h
@@ -18,6 +18,7 @@
#define __LUCI_IMPORT_GRAPH_BUILDER_H__
#include "GraphBuilderContext.h"
+#include "GraphBuilderBase.h"
#include <mio/circle/schema_generated.h>
@@ -25,25 +26,14 @@ namespace luci
{
/**
- * @brief Interface of convert circle:: NodeDef to loco::Node (e.g., Conv2DGraphBuilder)
+ * @brief Base of general single output graph builder(e.g., Conv2DGraphBuilder)
*/
-class GraphBuilder
+class GraphBuilder : public GraphBuilderBase
{
public:
- struct ValidateArgs
- {
- ValidateArgs(const circle::OperatorT &o, const CircleReader &r) : op(o), reader(r) {}
-
- const circle::OperatorT &op;
- const CircleReader &reader;
- };
-
-public:
virtual ~GraphBuilder() = default;
- virtual bool validate(const ValidateArgs &) const = 0;
-
- void build(const circle::OperatorT &op, GraphBuilderContext *context) const;
+ void build(const circle::OperatorT &op, GraphBuilderContext *context) const final;
private:
virtual CircleNode *build_node(const circle::OperatorT &op,
diff --git a/compiler/luci/import/include/luci/Import/GraphBuilderBase.h b/compiler/luci/import/include/luci/Import/GraphBuilderBase.h
new file mode 100644
index 000000000..a0cd008e0
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/GraphBuilderBase.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_GRAPH_BUILDER_BASE_H__
+#define __LUCI_IMPORT_GRAPH_BUILDER_BASE_H__
+
+#include "GraphBuilderContext.h"
+
+#include <mio/circle/schema_generated.h>
+
+namespace luci
+{
+
+/**
+ * @brief Interface of convert circle::OperatorT to CircleNode
+ */
+struct GraphBuilderBase
+{
+ struct ValidateArgs
+ {
+ ValidateArgs(const circle::OperatorT &o, const CircleReader &r) : op(o), reader(r) {}
+
+ const circle::OperatorT &op;
+ const CircleReader &reader;
+ };
+
+ virtual bool validate(const ValidateArgs &) const = 0;
+ virtual void build(const circle::OperatorT &op, GraphBuilderContext *context) const = 0;
+
+ virtual ~GraphBuilderBase() = default;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_GRAPH_BUILDER_BASE_H__
diff --git a/compiler/luci/import/include/luci/Import/GraphBuilderContext.h b/compiler/luci/import/include/luci/Import/GraphBuilderContext.h
index 8d464181d..72e237abc 100644
--- a/compiler/luci/import/include/luci/Import/GraphBuilderContext.h
+++ b/compiler/luci/import/include/luci/Import/GraphBuilderContext.h
@@ -24,6 +24,7 @@
#include <loco.h>
#include <map>
+#include <set>
namespace luci
{
@@ -48,13 +49,29 @@ private:
};
/**
+ * @brief Set of Tensor Index of outputs of operators
+ * including graph input nodes
+ */
+class IndexTensorOutputs
+{
+public:
+ void enroll(TensorIndex idx);
+
+ bool find(TensorIndex idx);
+
+private:
+ std::set<TensorIndex> _set;
+};
+
+/**
* @brief Class to store context to build loco graph IR from TensorFlow
*/
class GraphBuilderContext
{
public:
- GraphBuilderContext(loco::Graph *g, CircleReader *reader, IndexNodeFinder *nodefinder)
- : _g(g), _reader(reader), _indexnodefinder(nodefinder)
+ GraphBuilderContext(loco::Graph *g, CircleReader *reader, IndexNodeFinder *nodefinder,
+ IndexTensorOutputs *tensoroutputs)
+ : _g(g), _reader(reader), _indexnodefinder(nodefinder), _indextensoroutputs(tensoroutputs)
{
// DO NOTHING
}
@@ -67,11 +84,13 @@ public:
CircleReader *reader() { return _reader; }
IndexNodeFinder *nodefinder() { return _indexnodefinder; }
+ IndexTensorOutputs *tensoroutputs() { return _indextensoroutputs; }
private:
loco::Graph *_g;
CircleReader *_reader;
IndexNodeFinder *_indexnodefinder;
+ IndexTensorOutputs *_indextensoroutputs;
};
} // namespace luci
diff --git a/compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h b/compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h
index 99054e7b6..b8dc22fdd 100644
--- a/compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h
+++ b/compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h
@@ -17,7 +17,7 @@
#ifndef __LUCI_IMPORT_GRAPH_BUILDER_REGISTRY_H__
#define __LUCI_IMPORT_GRAPH_BUILDER_REGISTRY_H__
-#include "GraphBuilder.h"
+#include "GraphBuilderBase.h"
#include <map>
@@ -31,11 +31,11 @@ struct GraphBuilderSource
/**
* @brief Returns registered GraphBuilder pointer for operator (nullptr if not present)
*/
- virtual const GraphBuilder *lookup(const circle::BuiltinOperator &op) const = 0;
+ virtual const GraphBuilderBase *lookup(const circle::BuiltinOperator &op) const = 0;
};
/**
- * @brief Class to return graph builder for TF nodes
+ * @brief Class to return graph builder for Circle nodes
*/
class GraphBuilderRegistry final : public GraphBuilderSource
{
@@ -53,7 +53,7 @@ public:
* @brief Returns registered GraphBuilder pointer for operator or
* nullptr if not registered
*/
- const GraphBuilder *lookup(const circle::BuiltinOperator &op) const final
+ const GraphBuilderBase *lookup(const circle::BuiltinOperator &op) const final
{
if (_builder_map.find(op) == _builder_map.end())
return (_parent == nullptr) ? nullptr : _parent->lookup(op);
@@ -68,7 +68,7 @@ public:
}
public:
- void add(const circle::BuiltinOperator op, std::unique_ptr<GraphBuilder> &&builder)
+ void add(const circle::BuiltinOperator op, std::unique_ptr<GraphBuilderBase> &&builder)
{
_builder_map[op] = std::move(builder);
}
@@ -77,7 +77,7 @@ private:
const GraphBuilderSource *_parent = nullptr;
private:
- std::map<const circle::BuiltinOperator, std::unique_ptr<GraphBuilder>> _builder_map;
+ std::map<const circle::BuiltinOperator, std::unique_ptr<GraphBuilderBase>> _builder_map;
};
} // namespace luci
diff --git a/compiler/luci/import/include/luci/Import/Nodes.h b/compiler/luci/import/include/luci/Import/Nodes.h
index 381d02b97..2719a5aec 100644
--- a/compiler/luci/import/include/luci/Import/Nodes.h
+++ b/compiler/luci/import/include/luci/Import/Nodes.h
@@ -19,30 +19,110 @@
#include "Nodes/CircleAbs.h"
#include "Nodes/CircleAdd.h"
+#include "Nodes/CircleAddN.h"
#include "Nodes/CircleArgMax.h"
+#include "Nodes/CircleArgMin.h"
#include "Nodes/CircleAveragePool2D.h"
+#include "Nodes/CircleBatchMatMul.h"
#include "Nodes/CircleBatchToSpaceND.h"
+#include "Nodes/CircleBCQFullyConnected.h"
+#include "Nodes/CircleBCQGather.h"
+#include "Nodes/CircleCast.h"
+#include "Nodes/CircleCeil.h"
#include "Nodes/CircleConcatenation.h"
#include "Nodes/CircleConst.h"
#include "Nodes/CircleConv2D.h"
#include "Nodes/CircleCos.h"
+#include "Nodes/CircleCustom.h"
+#include "Nodes/CircleDepthToSpace.h"
#include "Nodes/CircleDepthwiseConv2D.h"
#include "Nodes/CircleDiv.h"
+#include "Nodes/CircleElu.h"
#include "Nodes/CircleEqual.h"
#include "Nodes/CircleExp.h"
+#include "Nodes/CircleExpandDims.h"
+#include "Nodes/CircleFill.h"
+#include "Nodes/CircleFloor.h"
+#include "Nodes/CircleFloorDiv.h"
+#include "Nodes/CircleFloorMod.h"
#include "Nodes/CircleFullyConnected.h"
+#include "Nodes/CircleGather.h"
+#include "Nodes/CircleGatherNd.h"
+#include "Nodes/CircleGreater.h"
+#include "Nodes/CircleGreaterEqual.h"
+#include "Nodes/CircleIf.h"
+#include "Nodes/CircleInstanceNorm.h"
+#include "Nodes/CircleL2Normalize.h"
+#include "Nodes/CircleL2Pool2D.h"
+#include "Nodes/CircleLeakyRelu.h"
+#include "Nodes/CircleLess.h"
+#include "Nodes/CircleLessEqual.h"
+#include "Nodes/CircleLocalResponseNormalization.h"
+#include "Nodes/CircleLog.h"
+#include "Nodes/CircleLogicalAnd.h"
#include "Nodes/CircleLogicalNot.h"
#include "Nodes/CircleLogicalOr.h"
+#include "Nodes/CircleLogistic.h"
+#include "Nodes/CircleLogSoftmax.h"
+#include "Nodes/CircleMatrixSetDiag.h"
+#include "Nodes/CircleMaximum.h"
#include "Nodes/CircleMaxPool2D.h"
+#include "Nodes/CircleMatrixDiag.h"
#include "Nodes/CircleMean.h"
+#include "Nodes/CircleMinimum.h"
+#include "Nodes/CircleMirrorPad.h"
#include "Nodes/CircleMul.h"
+#include "Nodes/CircleNeg.h"
+#include "Nodes/CircleNotEqual.h"
+#include "Nodes/CircleOneHot.h"
#include "Nodes/CirclePack.h"
#include "Nodes/CirclePad.h"
+#include "Nodes/CirclePow.h"
+#include "Nodes/CirclePRelu.h"
+#include "Nodes/CircleRange.h"
+#include "Nodes/CircleRank.h"
+#include "Nodes/CircleReduceAny.h"
+#include "Nodes/CircleReduceMax.h"
+#include "Nodes/CircleReduceMin.h"
+#include "Nodes/CircleReduceProd.h"
#include "Nodes/CircleRelu.h"
+#include "Nodes/CircleRelu6.h"
+#include "Nodes/CircleReluN1To1.h"
#include "Nodes/CircleReshape.h"
+#include "Nodes/CircleResizeBilinear.h"
+#include "Nodes/CircleResizeNearestNeighbor.h"
+#include "Nodes/CircleReverseSequence.h"
+#include "Nodes/CircleReverseV2.h"
+#include "Nodes/CircleRound.h"
#include "Nodes/CircleRsqrt.h"
+#include "Nodes/CircleScatterNd.h"
+#include "Nodes/CircleSegmentSum.h"
+#include "Nodes/CircleSelect.h"
+#include "Nodes/CircleSelectV2.h"
+#include "Nodes/CircleShape.h"
+#include "Nodes/CircleSin.h"
+#include "Nodes/CircleSlice.h"
#include "Nodes/CircleSoftmax.h"
+#include "Nodes/CircleSpaceToBatchND.h"
+#include "Nodes/CircleSpaceToDepth.h"
+#include "Nodes/CircleSparseToDense.h"
+#include "Nodes/CircleSplit.h"
+#include "Nodes/CircleSplitV.h"
+#include "Nodes/CircleSqrt.h"
+#include "Nodes/CircleSquare.h"
+#include "Nodes/CircleSquaredDifference.h"
+#include "Nodes/CircleSqueeze.h"
+#include "Nodes/CircleStridedSlice.h"
#include "Nodes/CircleSub.h"
+#include "Nodes/CircleSum.h"
+#include "Nodes/CircleTanh.h"
+#include "Nodes/CircleTile.h"
+#include "Nodes/CircleTopKV2.h"
#include "Nodes/CircleTranspose.h"
+#include "Nodes/CircleTransposeConv.h"
+#include "Nodes/CircleUnpack.h"
+#include "Nodes/CircleWhere.h"
+#include "Nodes/CircleWhile.h"
+#include "Nodes/CircleZerosLike.h"
#endif // __LUCI_IMPORT_NODES_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleAddN.h b/compiler/luci/import/include/luci/Import/Nodes/CircleAddN.h
new file mode 100644
index 000000000..3ec6b2a45
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleAddN.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 __LUCI_IMPORT_OP_CIRCLE_ADD_N_H__
+#define __LUCI_IMPORT_OP_CIRCLE_ADD_N_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleAddNGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_ADD_N_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleArgMin.h b/compiler/luci/import/include/luci/Import/Nodes/CircleArgMin.h
new file mode 100644
index 000000000..746f52837
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleArgMin.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 __LUCI_IMPORT_OP_CIRCLE_ARGMIN_H__
+#define __LUCI_IMPORT_OP_CIRCLE_ARGMIN_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleArgMinGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_ARGMIN_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleBCQFullyConnected.h b/compiler/luci/import/include/luci/Import/Nodes/CircleBCQFullyConnected.h
new file mode 100644
index 000000000..be58acd8d
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleBCQFullyConnected.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 __LUCI_IMPORT_OP_CIRCLE_BCQFULLYCONNECTED_H__
+#define __LUCI_IMPORT_OP_CIRCLE_BCQFULLYCONNECTED_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleBCQFullyConnectedGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_BCQFULLYCONNECTED_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleBCQGather.h b/compiler/luci/import/include/luci/Import/Nodes/CircleBCQGather.h
new file mode 100644
index 000000000..ff1c1f7e9
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleBCQGather.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 __LUCI_IMPORT_OP_CIRCLE_BCQGATHER_H__
+#define __LUCI_IMPORT_OP_CIRCLE_BCQGATHER_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleBCQGatherGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_BCQGATHER_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleBatchMatMul.h b/compiler/luci/import/include/luci/Import/Nodes/CircleBatchMatMul.h
new file mode 100644
index 000000000..b46a8715c
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleBatchMatMul.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 __LUCI_IMPORT_OP_CIRCLE_BATCHMATMUL_H__
+#define __LUCI_IMPORT_OP_CIRCLE_BATCHMATMUL_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleBatchMatMulGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_BATCHMATMUL_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleCast.h b/compiler/luci/import/include/luci/Import/Nodes/CircleCast.h
new file mode 100644
index 000000000..1cd850bc7
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleCast.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 __LUCI_IMPORT_OP_CIRCLE_CAST_H__
+#define __LUCI_IMPORT_OP_CIRCLE_CAST_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleCastGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_CAST_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleCeil.h b/compiler/luci/import/include/luci/Import/Nodes/CircleCeil.h
new file mode 100644
index 000000000..f1bdf2397
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleCeil.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 __LUCI_IMPORT_OP_CIRCLE_CEIL_H__
+#define __LUCI_IMPORT_OP_CIRCLE_CEIL_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleCeilGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_CEIL_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleCustom.h b/compiler/luci/import/include/luci/Import/Nodes/CircleCustom.h
new file mode 100644
index 000000000..65745be4b
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleCustom.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_OP_CIRCLE_CUSTOM_H__
+#define __LUCI_IMPORT_OP_CIRCLE_CUSTOM_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleCustomGraphBuilder : public GraphBuilderBase
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+ void build(const circle::OperatorT &op, GraphBuilderContext *context) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_CUSTOM_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleDepthToSpace.h b/compiler/luci/import/include/luci/Import/Nodes/CircleDepthToSpace.h
new file mode 100644
index 000000000..a479cbd20
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleDepthToSpace.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 __LUCI_IMPORT_OP_CIRCLE_DEPTHTOSPACE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_DEPTHTOSPACE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleDepthToSpaceGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_DEPTHTOSPACE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleElu.h b/compiler/luci/import/include/luci/Import/Nodes/CircleElu.h
new file mode 100644
index 000000000..2ec5642ce
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleElu.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 __LUCI_IMPORT_OP_CIRCLE_ELU_H__
+#define __LUCI_IMPORT_OP_CIRCLE_ELU_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleEluGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_ELU_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleExpandDims.h b/compiler/luci/import/include/luci/Import/Nodes/CircleExpandDims.h
new file mode 100644
index 000000000..acbfe7aea
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleExpandDims.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 __LUCI_IMPORT_OP_CIRCLE_EXPAND_DIMS_H__
+#define __LUCI_IMPORT_OP_CIRCLE_EXPAND_DIMS_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleExpandDimsGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_EXPAND_DIMS_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleFill.h b/compiler/luci/import/include/luci/Import/Nodes/CircleFill.h
new file mode 100644
index 000000000..3539dcd56
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleFill.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 __LUCI_IMPORT_OP_CIRCLE_FILL_H__
+#define __LUCI_IMPORT_OP_CIRCLE_FILL_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleFillGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_FILL_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleFloor.h b/compiler/luci/import/include/luci/Import/Nodes/CircleFloor.h
new file mode 100644
index 000000000..057800865
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleFloor.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 __LUCI_IMPORT_OP_CIRCLE_FLOOR_H__
+#define __LUCI_IMPORT_OP_CIRCLE_FLOOR_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleFloorGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_FLOOR_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleFloorDiv.h b/compiler/luci/import/include/luci/Import/Nodes/CircleFloorDiv.h
new file mode 100644
index 000000000..ddc2ab2ff
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleFloorDiv.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 __LUCI_IMPORT_OP_CIRCLE_FLOOR_DIV_H__
+#define __LUCI_IMPORT_OP_CIRCLE_FLOOR_DIV_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleFloorDivGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_FLOOR_DIV_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleFloorMod.h b/compiler/luci/import/include/luci/Import/Nodes/CircleFloorMod.h
new file mode 100644
index 000000000..1d6aa87c2
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleFloorMod.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 __LUCI_IMPORT_OP_CIRCLE_FLOOR_MOD_H__
+#define __LUCI_IMPORT_OP_CIRCLE_FLOOR_MOD_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleFloorModGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_FLOOR_MOD_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleGather.h b/compiler/luci/import/include/luci/Import/Nodes/CircleGather.h
new file mode 100644
index 000000000..0680c9451
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleGather.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 __LUCI_IMPORT_OP_CIRCLE_GATHER_H__
+#define __LUCI_IMPORT_OP_CIRCLE_GATHER_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleGatherGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_GATHER_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleGatherNd.h b/compiler/luci/import/include/luci/Import/Nodes/CircleGatherNd.h
new file mode 100644
index 000000000..be96b7dbe
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleGatherNd.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 __LUCI_IMPORT_OP_CIRCLE_GATHER_ND_H__
+#define __LUCI_IMPORT_OP_CIRCLE_GATHER_ND_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleGatherNdGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_GATHER_ND_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleGreater.h b/compiler/luci/import/include/luci/Import/Nodes/CircleGreater.h
new file mode 100644
index 000000000..87f0a8d83
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleGreater.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 __LUCI_IMPORT_OP_CIRCLE_GREATER_H__
+#define __LUCI_IMPORT_OP_CIRCLE_GREATER_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleGreaterGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_GREATER_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleGreaterEqual.h b/compiler/luci/import/include/luci/Import/Nodes/CircleGreaterEqual.h
new file mode 100644
index 000000000..4d24314e9
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleGreaterEqual.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 __LUCI_IMPORT_OP_CIRCLE_GREATEREQUAL_H__
+#define __LUCI_IMPORT_OP_CIRCLE_GREATEREQUAL_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleGreaterEqualGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_GREATEREQUAL_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleIf.h b/compiler/luci/import/include/luci/Import/Nodes/CircleIf.h
new file mode 100644
index 000000000..8faf09cae
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleIf.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_OP_CIRCLE_IF_H__
+#define __LUCI_IMPORT_OP_CIRCLE_IF_H__
+
+#include "luci/Import/GraphBuilderBase.h"
+
+namespace luci
+{
+
+class CircleIfGraphBuilder : public GraphBuilderBase
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+ void build(const circle::OperatorT &op, GraphBuilderContext *context) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_IF_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleInstanceNorm.h b/compiler/luci/import/include/luci/Import/Nodes/CircleInstanceNorm.h
new file mode 100644
index 000000000..5fd8f148a
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleInstanceNorm.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 __LUCI_IMPORT_OP_CIRCLE_INSTANCE_NORM_H__
+#define __LUCI_IMPORT_OP_CIRCLE_INSTANCE_NORM_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleInstanceNormGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_INSTANCE_NORM_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleL2Normalize.h b/compiler/luci/import/include/luci/Import/Nodes/CircleL2Normalize.h
new file mode 100644
index 000000000..116605f09
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleL2Normalize.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 __LUCI_IMPORT_OP_CIRCLE_L2_NORMALIZE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_L2_NORMALIZE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleL2NormalizeGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_L2_NORMALIZE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleL2Pool2D.h b/compiler/luci/import/include/luci/Import/Nodes/CircleL2Pool2D.h
new file mode 100644
index 000000000..2211c4751
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleL2Pool2D.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 __LUCI_IMPORT_OP_CIRCLE_L2_POOL2D_H__
+#define __LUCI_IMPORT_OP_CIRCLE_L2_POOL2D_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleL2Pool2DGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_L2_POOL2D_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLeakyRelu.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLeakyRelu.h
new file mode 100644
index 000000000..b7fa41f25
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLeakyRelu.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 __LUCI_IMPORT_OP_CIRCLE_LEAKY_RELU_H__
+#define __LUCI_IMPORT_OP_CIRCLE_LEAKY_RELU_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleLeakyReluGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_LEAKY_RELU_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLess.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLess.h
new file mode 100644
index 000000000..b93155bc4
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLess.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 __LUCI_IMPORT_OP_CIRCLE_LESS_H__
+#define __LUCI_IMPORT_OP_CIRCLE_LESS_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleLessGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_LESS_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLessEqual.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLessEqual.h
new file mode 100644
index 000000000..e54a4cb8c
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLessEqual.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 __LUCI_IMPORT_OP_CIRCLE_LESS_EQUAL_H__
+#define __LUCI_IMPORT_OP_CIRCLE_LESS_EQUAL_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleLessEqualGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_LESS_EQUAL_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLocalResponseNormalization.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLocalResponseNormalization.h
new file mode 100644
index 000000000..95e6ea880
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLocalResponseNormalization.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 __LUCI_IMPORT_OP_CIRCLE_LOCAL_RESPONSE_NORMALIZATION_H__
+#define __LUCI_IMPORT_OP_CIRCLE_LOCAL_RESPONSE_NORMALIZATION_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleLocalResponseNormalizationGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_LOCAL_RESPONSE_NORMALIZATION_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLog.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLog.h
new file mode 100644
index 000000000..5b3321014
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLog.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 __LUCI_IMPORT_OP_CIRCLE_LOG_H__
+#define __LUCI_IMPORT_OP_CIRCLE_LOG_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleLogGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_LOG_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLogSoftmax.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLogSoftmax.h
new file mode 100644
index 000000000..ef29833f5
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLogSoftmax.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 __LUCI_IMPORT_OP_CIRCLE_LOG_SOFTMAX_H__
+#define __LUCI_IMPORT_OP_CIRCLE_LOG_SOFTMAX_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleLogSoftmaxGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_LOG_SOFTMAX_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLogicalAnd.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLogicalAnd.h
new file mode 100644
index 000000000..9336f4ac8
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLogicalAnd.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 __LUCI_IMPORT_OP_CIRCLE_LOGICALAND_H__
+#define __LUCI_IMPORT_OP_CIRCLE_LOGICALAND_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleLogicalAndGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_LOGICALAND_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLogistic.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLogistic.h
new file mode 100644
index 000000000..67c6c1f1f
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLogistic.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 __LUCI_IMPORT_OP_CIRCLE_LOGISTIC_H__
+#define __LUCI_IMPORT_OP_CIRCLE_LOGISTIC_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleLogisticGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_LOGISTIC_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixDiag.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixDiag.h
new file mode 100644
index 000000000..e038c3e0a
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixDiag.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 __LUCI_IMPORT_OP_CIRCLE_MATRIX_DIAG_H__
+#define __LUCI_IMPORT_OP_CIRCLE_MATRIX_DIAG_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleMatrixDiagGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_MATRIX_DIAG_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixSetDiag.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixSetDiag.h
new file mode 100644
index 000000000..a9ea0ac3d
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixSetDiag.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 __LUCI_IMPORT_OP_CIRCLE_MATRIX_SET_DIAG_H__
+#define __LUCI_IMPORT_OP_CIRCLE_MATRIX_SET_DIAG_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleMatrixSetDiagGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_MATRIX_SET_DIAG_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMaximum.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMaximum.h
new file mode 100644
index 000000000..9705d3a36
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMaximum.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 __LUCI_IMPORT_OP_CIRCLE_MAXIMUM_H__
+#define __LUCI_IMPORT_OP_CIRCLE_MAXIMUM_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleMaximumGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_MAXIMUM_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMinimum.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMinimum.h
new file mode 100644
index 000000000..d9546ecf8
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMinimum.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 __LUCI_IMPORT_OP_CIRCLE_MINIMUM_H__
+#define __LUCI_IMPORT_OP_CIRCLE_MINIMUM_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleMinimumGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_MINIMUM_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMirrorPad.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMirrorPad.h
new file mode 100644
index 000000000..7f512cda7
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMirrorPad.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 __LUCI_IMPORT_OP_CIRCLE_MIRROR_PAD_H__
+#define __LUCI_IMPORT_OP_CIRCLE_MIRROR_PAD_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleMirrorPadGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_MIRROR_PAD_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleNeg.h b/compiler/luci/import/include/luci/Import/Nodes/CircleNeg.h
new file mode 100644
index 000000000..3d0bac19f
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleNeg.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 __LUCI_IMPORT_OP_CIRCLE_NEG_H__
+#define __LUCI_IMPORT_OP_CIRCLE_NEG_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleNegGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_NEG_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleNotEqual.h b/compiler/luci/import/include/luci/Import/Nodes/CircleNotEqual.h
new file mode 100644
index 000000000..10c79b75e
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleNotEqual.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 __LUCI_IMPORT_OP_CIRCLE_NOTEQUAL_H__
+#define __LUCI_IMPORT_OP_CIRCLE_NOTEQUAL_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleNotEqualGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_NOTEQUAL_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleOneHot.h b/compiler/luci/import/include/luci/Import/Nodes/CircleOneHot.h
new file mode 100644
index 000000000..8d9526d0e
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleOneHot.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 __LUCI_IMPORT_OP_CIRCLE_ONEHOT_H__
+#define __LUCI_IMPORT_OP_CIRCLE_ONEHOT_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleOneHotGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_ONEHOT_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CirclePRelu.h b/compiler/luci/import/include/luci/Import/Nodes/CirclePRelu.h
new file mode 100644
index 000000000..822862cfd
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CirclePRelu.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 __LUCI_IMPORT_OP_CIRCLE_PRELU_H__
+#define __LUCI_IMPORT_OP_CIRCLE_PRELU_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CirclePReluGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_PRELU_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CirclePow.h b/compiler/luci/import/include/luci/Import/Nodes/CirclePow.h
new file mode 100644
index 000000000..284aa9b89
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CirclePow.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 __LUCI_IMPORT_OP_CIRCLE_POW_H__
+#define __LUCI_IMPORT_OP_CIRCLE_POW_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CirclePowGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_POW_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleRange.h b/compiler/luci/import/include/luci/Import/Nodes/CircleRange.h
new file mode 100644
index 000000000..bc63286b2
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleRange.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 __LUCI_IMPORT_OP_CIRCLE_RANGE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_RANGE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleRangeGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_RANGE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleRank.h b/compiler/luci/import/include/luci/Import/Nodes/CircleRank.h
new file mode 100644
index 000000000..43a7fdb7b
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleRank.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 __LUCI_IMPORT_OP_CIRCLE_RANK_H__
+#define __LUCI_IMPORT_OP_CIRCLE_RANK_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleRankGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_RANK_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReduceAny.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceAny.h
new file mode 100644
index 000000000..5ee517999
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceAny.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 __LUCI_IMPORT_OP_CIRCLE_REDUCE_ANY_H__
+#define __LUCI_IMPORT_OP_CIRCLE_REDUCE_ANY_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleReduceAnyGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_REDUCE_ANY_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMax.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMax.h
new file mode 100644
index 000000000..0bc7021c1
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMax.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 __LUCI_IMPORT_OP_CIRCLE_REDUCE_MAX_H__
+#define __LUCI_IMPORT_OP_CIRCLE_REDUCE_MAX_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleReduceMaxGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_REDUCE_MAX_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMin.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMin.h
new file mode 100644
index 000000000..0c05457f0
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMin.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 __LUCI_IMPORT_OP_CIRCLE_REDUCE_MIN_H__
+#define __LUCI_IMPORT_OP_CIRCLE_REDUCE_MIN_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleReduceMinGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_REDUCE_MIN_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReduceProd.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceProd.h
new file mode 100644
index 000000000..446bc7866
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceProd.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 __LUCI_IMPORT_OP_CIRCLE_REDUCE_PROD_H__
+#define __LUCI_IMPORT_OP_CIRCLE_REDUCE_PROD_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleReduceProdGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_REDUCE_PROD_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleRelu6.h b/compiler/luci/import/include/luci/Import/Nodes/CircleRelu6.h
new file mode 100644
index 000000000..d17b4e200
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleRelu6.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 __LUCI_IMPORT_OP_CIRCLE_RELU6_H__
+#define __LUCI_IMPORT_OP_CIRCLE_RELU6_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleRelu6GraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_RELU6_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReluN1To1.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReluN1To1.h
new file mode 100644
index 000000000..059431565
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReluN1To1.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 __LUCI_IMPORT_OP_CIRCLE_RELU_N1_TO_1_H__
+#define __LUCI_IMPORT_OP_CIRCLE_RELU_N1_TO_1_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleReluN1To1GraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_RELU_N1_TO_1_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleResizeBilinear.h b/compiler/luci/import/include/luci/Import/Nodes/CircleResizeBilinear.h
new file mode 100644
index 000000000..8c20ecc24
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleResizeBilinear.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 __LUCI_IMPORT_OP_CIRCLE_RESIZE_BILINEAR_H__
+#define __LUCI_IMPORT_OP_CIRCLE_RESIZE_BILINEAR_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleResizeBilinearGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_RESIZE_BILINEAR_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleResizeNearestNeighbor.h b/compiler/luci/import/include/luci/Import/Nodes/CircleResizeNearestNeighbor.h
new file mode 100644
index 000000000..5b0647163
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleResizeNearestNeighbor.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 __LUCI_IMPORT_OP_CIRCLE_RESIZE_NEAREST_NEIGHBOR_H__
+#define __LUCI_IMPORT_OP_CIRCLE_RESIZE_NEAREST_NEIGHBOR_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleResizeNearestNeighborGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_RESIZE_NEAREST_NEIGHBOR_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReverseSequence.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReverseSequence.h
new file mode 100644
index 000000000..cbeed3013
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReverseSequence.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 __LUCI_IMPORT_OP_CIRCLE_REVERSE_SEQUENCE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_REVERSE_SEQUENCE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleReverseSequenceGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_REVERSE_SEQUENCE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReverseV2.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReverseV2.h
new file mode 100644
index 000000000..f354298dd
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReverseV2.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 __LUCI_IMPORT_OP_CIRCLE_REVERSE_V2_H__
+#define __LUCI_IMPORT_OP_CIRCLE_REVERSE_V2_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleReverseV2GraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_REVERSE_V2_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleRound.h b/compiler/luci/import/include/luci/Import/Nodes/CircleRound.h
new file mode 100644
index 000000000..8b027d7ef
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleRound.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 __LUCI_IMPORT_OP_CIRCLE_ROUND_H__
+#define __LUCI_IMPORT_OP_CIRCLE_ROUND_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleRoundGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_ROUND_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleScatterNd.h b/compiler/luci/import/include/luci/Import/Nodes/CircleScatterNd.h
new file mode 100644
index 000000000..8fa7a2f91
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleScatterNd.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 __LUCI_IMPORT_OP_CIRCLE_SCATTER_ND_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SCATTER_ND_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleScatterNdGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SCATTER_ND_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSegmentSum.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSegmentSum.h
new file mode 100644
index 000000000..7c33dee41
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSegmentSum.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 __LUCI_IMPORT_OP_CIRCLE_SEGMENT_SUM_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SEGMENT_SUM_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSegmentSumGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SEGMENT_SUM_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSelect.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSelect.h
new file mode 100644
index 000000000..87bd1a7fe
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSelect.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 __LUCI_IMPORT_OP_CIRCLE_SELECT_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SELECT_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSelectGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SELECT_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSelectV2.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSelectV2.h
new file mode 100644
index 000000000..28c73b087
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSelectV2.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 __LUCI_IMPORT_OP_CIRCLE_SELECT_V2_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SELECT_V2_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSelectV2GraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SELECT_V2_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleShape.h b/compiler/luci/import/include/luci/Import/Nodes/CircleShape.h
new file mode 100644
index 000000000..3002084a5
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleShape.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 __LUCI_IMPORT_OP_CIRCLE_SHAPE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SHAPE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleShapeGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SHAPE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSin.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSin.h
new file mode 100644
index 000000000..605f5a5a0
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSin.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 __LUCI_IMPORT_OP_CIRCLE_SIN_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SIN_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSinGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SIN_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSlice.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSlice.h
new file mode 100644
index 000000000..3bb4c51b7
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSlice.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 __LUCI_IMPORT_OP_CIRCLE_SLICE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SLICE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSliceGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SLICE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToBatchND.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToBatchND.h
new file mode 100644
index 000000000..b8723098d
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToBatchND.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 __LUCI_IMPORT_OP_CIRCLE_SPACETOBATCHND_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SPACETOBATCHND_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSpaceToBatchNDGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SPACETOBATCHND_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToDepth.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToDepth.h
new file mode 100644
index 000000000..75a54dd26
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToDepth.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 __LUCI_IMPORT_OP_CIRCLE_SPACETODEPTH_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SPACETODEPTH_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSpaceToDepthGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SPACETODEPTH_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSparseToDense.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSparseToDense.h
new file mode 100644
index 000000000..baf240919
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSparseToDense.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 __LUCI_IMPORT_OP_CIRCLE_SPARSETODENSE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SPARSETODENSE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSparseToDenseGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SPARSETODENSE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSplit.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSplit.h
new file mode 100644
index 000000000..3395e40fd
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSplit.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_OP_CIRCLE_SPLIT_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SPLIT_H__
+
+#include "luci/Import/GraphBuilderBase.h"
+
+namespace luci
+{
+
+class CircleSplitGraphBuilder : public GraphBuilderBase
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+ void build(const circle::OperatorT &op, GraphBuilderContext *context) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SPLIT_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSplitV.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSplitV.h
new file mode 100644
index 000000000..3e53df362
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSplitV.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_OP_CIRCLE_SPLIT_V_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SPLIT_V_H__
+
+#include "luci/Import/GraphBuilderBase.h"
+
+namespace luci
+{
+
+class CircleSplitVGraphBuilder : public GraphBuilderBase
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+ void build(const circle::OperatorT &op, GraphBuilderContext *context) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SPLIT_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSqrt.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSqrt.h
new file mode 100644
index 000000000..4fd79951c
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSqrt.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 __LUCI_IMPORT_OP_CIRCLE_SQRT_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SQRT_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSqrtGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SQRT_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSquare.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSquare.h
new file mode 100644
index 000000000..3a1299102
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSquare.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 __LUCI_IMPORT_OP_CIRCLE_SQUARE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SQUARE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSquareGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SQUARE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSquaredDifference.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSquaredDifference.h
new file mode 100644
index 000000000..95f08412b
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSquaredDifference.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 __LUCI_IMPORT_OP_CIRCLE_SQUAREDDIFFERENCE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SQUAREDDIFFERENCE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSquaredDifferenceGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SQUAREDDIFFERENCE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSqueeze.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSqueeze.h
new file mode 100644
index 000000000..4f0dfb5ef
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSqueeze.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 __LUCI_IMPORT_OP_CIRCLE_SQUEEZE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SQUEEZE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSqueezeGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SQUEEZE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleStridedSlice.h b/compiler/luci/import/include/luci/Import/Nodes/CircleStridedSlice.h
new file mode 100644
index 000000000..f535c3a61
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleStridedSlice.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 __LUCI_IMPORT_OP_CIRCLE_STRIDED_SLICE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_STRIDED_SLICE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleStridedSliceGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_STRIDED_SLICE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSum.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSum.h
new file mode 100644
index 000000000..e65dd46ad
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSum.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 __LUCI_IMPORT_OP_CIRCLE_SUM_H__
+#define __LUCI_IMPORT_OP_CIRCLE_SUM_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleSumGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_SUM_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleTanh.h b/compiler/luci/import/include/luci/Import/Nodes/CircleTanh.h
new file mode 100644
index 000000000..b3795acba
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleTanh.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 __LUCI_IMPORT_OP_CIRCLE_TANH_H__
+#define __LUCI_IMPORT_OP_CIRCLE_TANH_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleTanhGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_TANH_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleTile.h b/compiler/luci/import/include/luci/Import/Nodes/CircleTile.h
new file mode 100644
index 000000000..1da6cdbde
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleTile.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 __LUCI_IMPORT_OP_CIRCLE_TILE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_TILE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleTileGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_TILE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleTopKV2.h b/compiler/luci/import/include/luci/Import/Nodes/CircleTopKV2.h
new file mode 100644
index 000000000..8ec3f3311
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleTopKV2.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_OP_CIRCLE_TOPK_V2_H__
+#define __LUCI_IMPORT_OP_CIRCLE_TOPK_V2_H__
+
+#include "luci/Import/GraphBuilderBase.h"
+
+namespace luci
+{
+
+class CircleTopKV2GraphBuilder : public GraphBuilderBase
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+ void build(const circle::OperatorT &op, GraphBuilderContext *context) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_TOPK_V2_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleTransposeConv.h b/compiler/luci/import/include/luci/Import/Nodes/CircleTransposeConv.h
new file mode 100644
index 000000000..2614d0d0d
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleTransposeConv.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 __LUCI_IMPORT_OP_CIRCLE_TRANSPOSE_CONV_H__
+#define __LUCI_IMPORT_OP_CIRCLE_TRANSPOSE_CONV_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleTransposeConvGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_TRANSPOSE_CONV_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleUnpack.h b/compiler/luci/import/include/luci/Import/Nodes/CircleUnpack.h
new file mode 100644
index 000000000..f1a21de22
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleUnpack.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_OP_CIRCLE_UNPACK_H__
+#define __LUCI_IMPORT_OP_CIRCLE_UNPACK_H__
+
+#include "luci/Import/GraphBuilderBase.h"
+
+namespace luci
+{
+
+class CircleUnpackGraphBuilder : public GraphBuilderBase
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+ void build(const circle::OperatorT &op, GraphBuilderContext *context) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_UNPACK_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleWhere.h b/compiler/luci/import/include/luci/Import/Nodes/CircleWhere.h
new file mode 100644
index 000000000..72f98ef92
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleWhere.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_OP_CIRCLE_WHERE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_WHERE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleWhereGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const override;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_WHERE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleWhile.h b/compiler/luci/import/include/luci/Import/Nodes/CircleWhile.h
new file mode 100644
index 000000000..68c56b3c6
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleWhile.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IMPORT_OP_CIRCLE_WHILE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_WHILE_H__
+
+#include "luci/Import/GraphBuilderBase.h"
+
+namespace luci
+{
+
+class CircleWhileGraphBuilder : public GraphBuilderBase
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+ void build(const circle::OperatorT &op, GraphBuilderContext *context) const final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_WHILE_H__
diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleZerosLike.h b/compiler/luci/import/include/luci/Import/Nodes/CircleZerosLike.h
new file mode 100644
index 000000000..2a3410379
--- /dev/null
+++ b/compiler/luci/import/include/luci/Import/Nodes/CircleZerosLike.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 __LUCI_IMPORT_OP_CIRCLE_ZEROS_LIKE_H__
+#define __LUCI_IMPORT_OP_CIRCLE_ZEROS_LIKE_H__
+
+#include "luci/Import/GraphBuilder.h"
+
+namespace luci
+{
+
+class CircleZerosLikeGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const ValidateArgs &args) const final;
+
+private:
+ CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const override;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IMPORT_OP_CIRCLE_ZEROS_LIKE_H__
diff --git a/compiler/luci/import/include/luci/Importer.h b/compiler/luci/import/include/luci/Importer.h
index 246df9f27..f08ddcda7 100644
--- a/compiler/luci/import/include/luci/Importer.h
+++ b/compiler/luci/import/include/luci/Importer.h
@@ -51,4 +51,4 @@ private:
} // namespace luci
-#endif // __MOCO_IMPORTER_H__
+#endif // __LUCI_IMPORTER_H__
diff --git a/compiler/luci/import/src/CircleReader.cpp b/compiler/luci/import/src/CircleReader.cpp
index ead0093b8..81e945dd1 100644
--- a/compiler/luci/import/src/CircleReader.cpp
+++ b/compiler/luci/import/src/CircleReader.cpp
@@ -136,6 +136,19 @@ Padding luci_padding(const circle::Padding padding)
return Padding::UNDEFINED;
}
+MirrorPadMode luci_mirrorpad_mode(const circle::MirrorPadMode mode)
+{
+ switch (mode)
+ {
+ case circle::MirrorPadMode::MirrorPadMode_REFLECT:
+ return MirrorPadMode::REFLECT;
+ case circle::MirrorPadMode::MirrorPadMode_SYMMETRIC:
+ return MirrorPadMode::SYMMETRIC;
+ }
+ assert(false);
+ return MirrorPadMode::UNDEFINED;
+}
+
std::unique_ptr<CircleQuantParam>
luci_quantparam(const circle::QuantizationParametersT *quantization)
{
@@ -159,6 +172,27 @@ luci_quantparam(const circle::QuantizationParametersT *quantization)
return nullptr;
}
+void copy_tensor_attributes(const circle::TensorT &tensor, CircleNode *node)
+{
+ node->name(tensor_name(tensor));
+ node->dtype(luci_datatype(tensor.type));
+
+ std::vector<int32_t> dims = tensor.shape; // in NHWC
+ node->rank(dims.size());
+ for (uint32_t r = 0; r < dims.size(); ++r)
+ {
+ node->dim(r) = loco::Dimension(dims[r]);
+ }
+
+ const auto *quantization = tensor.quantization.get();
+ if (quantization != nullptr)
+ {
+ auto quantparam = luci_quantparam(quantization);
+ if (quantparam)
+ node->quantparam(std::move(quantparam));
+ }
+}
+
circle::BuiltinOperator CircleReader::builtin_code(const circle::OperatorT &op) const
{
const auto &op_codes = opcodes();
@@ -192,6 +226,9 @@ bool CircleReader::parse(const circle::Model *model)
_model.reset(model->UnPack());
+ // for direct pointer access
+ _model_ptr = model;
+
return true;
}
@@ -205,6 +242,12 @@ bool CircleReader::select_subgraph(uint32_t sgindex)
_current_subgraph = _model->subgraphs[sgindex].get();
+ // for direct pointer access
+ auto subgraphs = _model_ptr->subgraphs();
+ const circle::SubGraph *subgraph = (*subgraphs)[sgindex];
+
+ _tensors_ptr = subgraph->tensors();
+
return true;
}
diff --git a/compiler/luci/import/src/GraphBuilder.cpp b/compiler/luci/import/src/GraphBuilder.cpp
index e0ec9ded5..80a9f986a 100644
--- a/compiler/luci/import/src/GraphBuilder.cpp
+++ b/compiler/luci/import/src/GraphBuilder.cpp
@@ -16,21 +16,39 @@
#include "luci/Import/GraphBuilder.h"
+#include <luci/Log.h>
+
namespace luci
{
void GraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *context) const
{
+ LOGGER(l);
+
assert(context != nullptr);
const std::vector<int32_t> &inputs = op.inputs;
const std::vector<int32_t> &outputs = op.outputs;
const auto &tensors = context->reader()->tensors();
+ const auto &opcodes = context->reader()->opcodes();
+ auto tensors_ptr = context->reader()->tensors_ptr();
+ assert(tensors_ptr != nullptr);
std::vector<CircleNode *> input_nodes;
for (const int32_t input_tensor_index : inputs)
{
- input_nodes.push_back(context->nodefinder()->node(input_tensor_index));
+ if (input_tensor_index >= 0)
+ {
+ auto input = context->nodefinder()->node(input_tensor_index);
+ if (input == nullptr)
+ INFO(l) << "[luci] Warning: input node is null " << input_tensor_index << std::endl;
+ input_nodes.push_back(input);
+ }
+ else
+ {
+ // If there is no tensor, insert CircleOutputExclude.
+ input_nodes.push_back(context->graph()->nodes()->create<luci::CircleOutputExclude>());
+ }
}
CircleNode *node = build_node(op, input_nodes, context->graph());
@@ -39,16 +57,15 @@ void GraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *conte
assert(outputs.size() == 1);
{
const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ copy_tensor_attributes(output_tensor, node);
+ // mark shape_status
+ if (tensors_ptr->Get(outputs[0])->shape() == nullptr)
+ node->shape_status(ShapeStatus::NOSHAPE);
+ else
+ node->shape_status(ShapeStatus::VALID);
- node->name(tensor_name(output_tensor));
-
- auto quantization = tensor_quantization(output_tensor);
- if (quantization)
- {
- auto quantparam = luci_quantparam(quantization);
- if (quantparam)
- node->quantparam(std::move(quantparam));
- }
+ // mark operator version
+ node->op_version(opcodes[op.opcode_index].get()->version);
}
// Register node's only output.
diff --git a/compiler/luci/import/src/GraphBuilderContext.cpp b/compiler/luci/import/src/GraphBuilderContext.cpp
index a5162ce83..21adfa7e2 100644
--- a/compiler/luci/import/src/GraphBuilderContext.cpp
+++ b/compiler/luci/import/src/GraphBuilderContext.cpp
@@ -25,10 +25,12 @@ namespace luci
void IndexNodeFinder::enroll(TensorIndex idx, CircleNode *node)
{
- if (_table.find(idx) != _table.end())
+ auto iter = _table.find(idx);
+ if (iter != _table.end())
{
LOGGER(l);
- INFO(l) << "[luci] NodeFinder SKIP (" << idx << ") " << node << std::endl;
+ INFO(l) << "[luci] NodeFinder SKIP (" << idx << ") " << node << ":" << node->name()
+ << " existing: " << iter->second << ":" << iter->second->name() << std::endl;
return;
}
@@ -39,9 +41,22 @@ CircleNode *IndexNodeFinder::node(TensorIndex idx) const
{
MapIndexNode_t::const_iterator iter = _table.find(idx);
- assert(iter != _table.end() && iter->second != nullptr);
+ // dangle output node may exist that are not enrolled
+ return (iter != _table.end()) ? iter->second : nullptr;
+}
- return iter->second;
+void IndexTensorOutputs::enroll(TensorIndex idx)
+{
+ auto iter = _set.find(idx);
+ if (iter != _set.end())
+ {
+ LOGGER(l);
+ INFO(l) << "[luci] TensorOutputs SKIP (" << idx << ") existing" << std::endl;
+ return;
+ }
+ _set.insert(idx);
}
+bool IndexTensorOutputs::find(TensorIndex idx) { return (_set.find(idx) != _set.end()); }
+
} // namespace luci
diff --git a/compiler/luci/import/src/GraphBuilderRegistry.cpp b/compiler/luci/import/src/GraphBuilderRegistry.cpp
index 929b71a7d..d29557f74 100644
--- a/compiler/luci/import/src/GraphBuilderRegistry.cpp
+++ b/compiler/luci/import/src/GraphBuilderRegistry.cpp
@@ -27,137 +27,140 @@ GraphBuilderRegistry::GraphBuilderRegistry()
{
#define CIRCLE_NODE(OPCODE, CLASS) add(circle::BuiltinOperator_##OPCODE, std::make_unique<CLASS>());
- CIRCLE_NODE(ABS, CircleAbsGraphBuilder); // 101
- CIRCLE_NODE(ADD, CircleAddGraphBuilder); // 0
- CIRCLE_NODE(ARG_MAX, CircleArgMaxGraphBuilder); // 56
- CIRCLE_NODE(AVERAGE_POOL_2D, CircleAveragePool2DGraphBuilder); // 1
- CIRCLE_NODE(BATCH_TO_SPACE_ND, CircleBatchToSpaceNDGraphBuilder); // 37
- CIRCLE_NODE(CONCATENATION, CircleConcatenationGraphBuilder); // 2
- CIRCLE_NODE(CONV_2D, CircleConv2DGraphBuilder); // 3
- CIRCLE_NODE(COS, CircleCosGraphBuilder); // 108
- CIRCLE_NODE(DEPTHWISE_CONV_2D, CircleDepthwiseConv2DGraphBuilder); // 4
- CIRCLE_NODE(DIV, CircleDivGraphBuilder); // 42
- CIRCLE_NODE(EQUAL, CircleEqualGraphBuilder); // 71
- CIRCLE_NODE(EXP, CircleExpGraphBuilder); // 47
- CIRCLE_NODE(FULLY_CONNECTED, CircleFullyConnectedGraphBuilder); // 9
- CIRCLE_NODE(LOGICAL_NOT, CircleLogicalNotGraphBuilder); // 87
- CIRCLE_NODE(LOGICAL_OR, CircleLogicalOrGraphBuilder); // 84
- CIRCLE_NODE(MAX_POOL_2D, CircleMaxPool2DGraphBuilder); // 17
- CIRCLE_NODE(MEAN, CircleMeanGraphBuilder); // 40
- CIRCLE_NODE(MUL, CircleMulGraphBuilder); // 18
- CIRCLE_NODE(PACK, CirclePackGraphBuilder); // 83
- CIRCLE_NODE(PAD, CirclePadGraphBuilder); // 34
- CIRCLE_NODE(RELU, CircleReluGraphBuilder); // 19
- CIRCLE_NODE(RESHAPE, CircleReshapeGraphBuilder); // 22
- CIRCLE_NODE(RSQRT, CircleRsqrtGraphBuilder); // 76
- CIRCLE_NODE(SOFTMAX, CircleSoftmaxGraphBuilder); // 25
- CIRCLE_NODE(SUB, CircleSubGraphBuilder); // 41
- CIRCLE_NODE(TRANSPOSE, CircleTransposeGraphBuilder); // 39
+ CIRCLE_NODE(ABS, CircleAbsGraphBuilder); // 101
+ CIRCLE_NODE(ADD, CircleAddGraphBuilder); // 0
+ CIRCLE_NODE(ADD_N, CircleAddNGraphBuilder); // 106
+ CIRCLE_NODE(ARG_MAX, CircleArgMaxGraphBuilder); // 56
+ CIRCLE_NODE(ARG_MIN, CircleArgMinGraphBuilder); // 79
+ CIRCLE_NODE(AVERAGE_POOL_2D, CircleAveragePool2DGraphBuilder); // 1
+ CIRCLE_NODE(BATCH_MATMUL, CircleBatchMatMulGraphBuilder); // 126
+ CIRCLE_NODE(BATCH_TO_SPACE_ND, CircleBatchToSpaceNDGraphBuilder); // 37
+ CIRCLE_NODE(BCQ_FULLY_CONNECTED, CircleBCQFullyConnectedGraphBuilder); // 253
+ CIRCLE_NODE(BCQ_GATHER, CircleBCQGatherGraphBuilder); // 252
+ CIRCLE_NODE(CAST, CircleCastGraphBuilder); // 53
+ CIRCLE_NODE(CEIL, CircleCeilGraphBuilder); // 104
+ CIRCLE_NODE(CUSTOM, CircleCustomGraphBuilder); // 32
+ CIRCLE_NODE(CONCATENATION, CircleConcatenationGraphBuilder); // 2
+ CIRCLE_NODE(CONV_2D, CircleConv2DGraphBuilder); // 3
+ CIRCLE_NODE(COS, CircleCosGraphBuilder); // 108
+ CIRCLE_NODE(DEPTH_TO_SPACE, CircleDepthToSpaceGraphBuilder); // 5
+ CIRCLE_NODE(DEPTHWISE_CONV_2D, CircleDepthwiseConv2DGraphBuilder); // 4
+ CIRCLE_NODE(DIV, CircleDivGraphBuilder); // 42
+ CIRCLE_NODE(ELU, CircleEluGraphBuilder); // 111
+ CIRCLE_NODE(EQUAL, CircleEqualGraphBuilder); // 71
+ CIRCLE_NODE(EXP, CircleExpGraphBuilder); // 47
+ CIRCLE_NODE(EXPAND_DIMS, CircleExpandDimsGraphBuilder); // 70
+ CIRCLE_NODE(FILL, CircleFillGraphBuilder); // 94
+ CIRCLE_NODE(FLOOR, CircleFloorGraphBuilder); // 8
+ CIRCLE_NODE(FLOOR_DIV, CircleFloorDivGraphBuilder); // 90
+ CIRCLE_NODE(FLOOR_MOD, CircleFloorModGraphBuilder); // 95
+ CIRCLE_NODE(FULLY_CONNECTED, CircleFullyConnectedGraphBuilder); // 9
+ CIRCLE_NODE(GATHER, CircleGatherGraphBuilder); // 36
+ CIRCLE_NODE(GATHER_ND, CircleGatherNdGraphBuilder); // 107
+ CIRCLE_NODE(GREATER, CircleGreaterGraphBuilder); // 61
+ CIRCLE_NODE(GREATER_EQUAL, CircleGreaterEqualGraphBuilder); // 62
+ CIRCLE_NODE(IF, CircleIfGraphBuilder); // 118
+ CIRCLE_NODE(INSTANCE_NORM, CircleInstanceNormGraphBuilder); // 254
+ CIRCLE_NODE(L2_NORMALIZATION, CircleL2NormalizeGraphBuilder); // 11
+ CIRCLE_NODE(L2_POOL_2D, CircleL2Pool2DGraphBuilder); // 12
+ CIRCLE_NODE(LEAKY_RELU, CircleLeakyReluGraphBuilder); // 98,
+ CIRCLE_NODE(LESS, CircleLessGraphBuilder); // 58
+ CIRCLE_NODE(LESS_EQUAL, CircleLessEqualGraphBuilder); // 63
+ CIRCLE_NODE(LOCAL_RESPONSE_NORMALIZATION, CircleLocalResponseNormalizationGraphBuilder); // 13
+ CIRCLE_NODE(LOG, CircleLogGraphBuilder); // 73
+ CIRCLE_NODE(LOGICAL_AND, CircleLogicalAndGraphBuilder); // 86
+ CIRCLE_NODE(LOGICAL_NOT, CircleLogicalNotGraphBuilder); // 87
+ CIRCLE_NODE(LOGICAL_OR, CircleLogicalOrGraphBuilder); // 84
+ CIRCLE_NODE(LOGISTIC, CircleLogisticGraphBuilder); // 14
+ CIRCLE_NODE(LOG_SOFTMAX, CircleLogSoftmaxGraphBuilder); // 50
+ CIRCLE_NODE(MATRIX_DIAG, CircleMatrixDiagGraphBuilder); // 113
+ CIRCLE_NODE(MATRIX_SET_DIAG, CircleMatrixSetDiagGraphBuilder); // 115
+ CIRCLE_NODE(MAXIMUM, CircleMaximumGraphBuilder); // 55
+ CIRCLE_NODE(MAX_POOL_2D, CircleMaxPool2DGraphBuilder); // 17
+ CIRCLE_NODE(MEAN, CircleMeanGraphBuilder); // 40
+ CIRCLE_NODE(MINIMUM, CircleMinimumGraphBuilder); // 57
+ CIRCLE_NODE(MIRROR_PAD, CircleMirrorPadGraphBuilder); // 100
+ CIRCLE_NODE(MUL, CircleMulGraphBuilder); // 18
+ CIRCLE_NODE(NEG, CircleNegGraphBuilder); // 59
+ CIRCLE_NODE(NOT_EQUAL, CircleNotEqualGraphBuilder); // 72
+ CIRCLE_NODE(ONE_HOT, CircleOneHotGraphBuilder); // 85
+ CIRCLE_NODE(PACK, CirclePackGraphBuilder); // 83
+ CIRCLE_NODE(PAD, CirclePadGraphBuilder); // 34
+ CIRCLE_NODE(POW, CirclePowGraphBuilder); // 78
+ CIRCLE_NODE(PRELU, CirclePReluGraphBuilder); // 54,
+ CIRCLE_NODE(RANGE, CircleRangeGraphBuilder); // 96
+ CIRCLE_NODE(RANK, CircleRankGraphBuilder); // 110
+ CIRCLE_NODE(REDUCE_ANY, CircleReduceAnyGraphBuilder); // 91
+ CIRCLE_NODE(REDUCE_MAX, CircleReduceMaxGraphBuilder); // 82
+ CIRCLE_NODE(REDUCE_MIN, CircleReduceMinGraphBuilder); // 89
+ CIRCLE_NODE(REDUCE_PROD, CircleReduceProdGraphBuilder); // 81
+ CIRCLE_NODE(RELU, CircleReluGraphBuilder); // 19
+ CIRCLE_NODE(RELU6, CircleRelu6GraphBuilder); // 21
+ CIRCLE_NODE(RELU_N1_TO_1, CircleReluN1To1GraphBuilder); // 20
+ CIRCLE_NODE(RESHAPE, CircleReshapeGraphBuilder); // 22
+ CIRCLE_NODE(RESIZE_BILINEAR, CircleResizeBilinearGraphBuilder); // 23
+ CIRCLE_NODE(RESIZE_NEAREST_NEIGHBOR, CircleResizeNearestNeighborGraphBuilder); // 97
+ CIRCLE_NODE(REVERSE_SEQUENCE, CircleReverseSequenceGraphBuilder); // 112
+ CIRCLE_NODE(REVERSE_V2, CircleReverseV2GraphBuilder); // 105
+ CIRCLE_NODE(ROUND, CircleRoundGraphBuilder); // 116
+ CIRCLE_NODE(RSQRT, CircleRsqrtGraphBuilder); // 76
+ CIRCLE_NODE(SCATTER_ND, CircleScatterNdGraphBuilder); // 122
+ CIRCLE_NODE(SEGMENT_SUM, CircleSegmentSumGraphBuilder); // 125
+ CIRCLE_NODE(SELECT, CircleSelectGraphBuilder); // 64
+ CIRCLE_NODE(SELECT_V2, CircleSelectV2GraphBuilder); // 123
+ CIRCLE_NODE(SHAPE, CircleShapeGraphBuilder); // 77
+ CIRCLE_NODE(SIN, CircleSinGraphBuilder); // 66
+ CIRCLE_NODE(SLICE, CircleSliceGraphBuilder); // 65
+ CIRCLE_NODE(SOFTMAX, CircleSoftmaxGraphBuilder); // 25
+ CIRCLE_NODE(SPACE_TO_BATCH_ND, CircleSpaceToBatchNDGraphBuilder); // 38
+ CIRCLE_NODE(SPACE_TO_DEPTH, CircleSpaceToDepthGraphBuilder); // 26
+ CIRCLE_NODE(SPARSE_TO_DENSE, CircleSparseToDenseGraphBuilder); // 68
+ CIRCLE_NODE(SPLIT, CircleSplitGraphBuilder); // 49
+ CIRCLE_NODE(SPLIT_V, CircleSplitVGraphBuilder); // 102
+ CIRCLE_NODE(SQRT, CircleSqrtGraphBuilder); // 75
+ CIRCLE_NODE(SQUARE, CircleSquareGraphBuilder); // 92
+ CIRCLE_NODE(SQUARED_DIFFERENCE, CircleSquaredDifferenceGraphBuilder); // 99
+ CIRCLE_NODE(SQUEEZE, CircleSqueezeGraphBuilder); // 43
+ CIRCLE_NODE(STRIDED_SLICE, CircleStridedSliceGraphBuilder); // 45
+ CIRCLE_NODE(SUB, CircleSubGraphBuilder); // 41
+ CIRCLE_NODE(SUM, CircleSumGraphBuilder); // 74
+ CIRCLE_NODE(TANH, CircleTanhGraphBuilder); // 28
+ CIRCLE_NODE(TILE, CircleTileGraphBuilder); // 69
+ CIRCLE_NODE(TOPK_V2, CircleTopKV2GraphBuilder); // 48
+ CIRCLE_NODE(TRANSPOSE, CircleTransposeGraphBuilder); // 39
+ CIRCLE_NODE(TRANSPOSE_CONV, CircleTransposeConvGraphBuilder); // 67
+ CIRCLE_NODE(UNPACK, CircleUnpackGraphBuilder); // 88
+ CIRCLE_NODE(WHERE, CircleWhereGraphBuilder); // 109
+ CIRCLE_NODE(WHILE, CircleWhileGraphBuilder); // 119
+ CIRCLE_NODE(ZEROS_LIKE, CircleZerosLikeGraphBuilder); // 93
#undef CIRCLE_NODE
// BuiltinOperator_DEQUANTIZE = 6,
// BuiltinOperator_EMBEDDING_LOOKUP = 7,
- // BuiltinOperator_FLOOR = 8,
// BuiltinOperator_HASHTABLE_LOOKUP = 10,
- // BuiltinOperator_L2_NORMALIZATION = 11,
- // BuiltinOperator_L2_POOL_2D = 12,
- // BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION = 13,
- // BuiltinOperator_LOGISTIC = 14,
// BuiltinOperator_LSH_PROJECTION = 15,
// BuiltinOperator_LSTM = 16,
- // BuiltinOperator_RELU_N1_TO_1 = 20,
- // BuiltinOperator_RELU6 = 21,
- // BuiltinOperator_RESIZE_BILINEAR = 23,
// BuiltinOperator_RNN = 24,
- // BuiltinOperator_SPACE_TO_DEPTH = 26,
// BuiltinOperator_SVDF = 27,
- // BuiltinOperator_TANH = 28,
// BuiltinOperator_CONCAT_EMBEDDINGS = 29,
// BuiltinOperator_SKIP_GRAM = 30,
// BuiltinOperator_CALL = 31,
- // BuiltinOperator_CUSTOM = 32,
// BuiltinOperator_EMBEDDING_LOOKUP_SPARSE = 33,
// BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN = 35,
- // BuiltinOperator_GATHER = 36,
- // BuiltinOperator_SPACE_TO_BATCH_ND = 38,
- // BuiltinOperator_SQUEEZE = 43,
// BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44,
- // BuiltinOperator_STRIDED_SLICE = 45,
// BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN = 46,
- // BuiltinOperator_TOPK_V2 = 48,
- // BuiltinOperator_SPLIT = 49,
- // BuiltinOperator_LOG_SOFTMAX = 50,
// BuiltinOperator_DELEGATE = 51,
// BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM = 52,
- // BuiltinOperator_CAST = 53,
- // BuiltinOperator_PRELU = 54,
- // BuiltinOperator_MAXIMUM = 55,
// BuiltinOperator_ARG_MAX = 56,
- // BuiltinOperator_MINIMUM = 57,
- // BuiltinOperator_LESS = 58,
- // BuiltinOperator_NEG = 59,
// BuiltinOperator_PADV2 = 60,
- // BuiltinOperator_GREATER = 61,
- // BuiltinOperator_GREATER_EQUAL = 62,
- // BuiltinOperator_LESS_EQUAL = 63,
- // BuiltinOperator_SELECT = 64,
- // BuiltinOperator_SLICE = 65,
- // BuiltinOperator_SIN = 66,
- // BuiltinOperator_TRANSPOSE_CONV = 67,
- // BuiltinOperator_SPARSE_TO_DENSE = 68,
- // BuiltinOperator_TILE = 69,
- // BuiltinOperator_EXPAND_DIMS = 70,
- // BuiltinOperator_NOT_EQUAL = 72,
- // BuiltinOperator_LOG = 73,
- // BuiltinOperator_SUM = 74,
- // BuiltinOperator_SQRT = 75,
- // BuiltinOperator_SHAPE = 77,
- // BuiltinOperator_POW = 78,
- // BuiltinOperator_ARG_MIN = 79,
// BuiltinOperator_FAKE_QUANT = 80,
- // BuiltinOperator_REDUCE_PROD = 81,
- // BuiltinOperator_REDUCE_MAX = 82,
- // BuiltinOperator_ONE_HOT = 85,
- // BuiltinOperator_LOGICAL_AND = 86,
- // BuiltinOperator_UNPACK = 88,
- // BuiltinOperator_REDUCE_MIN = 89,
- // BuiltinOperator_FLOOR_DIV = 90,
- // BuiltinOperator_REDUCE_ANY = 91,
- // BuiltinOperator_SQUARE = 92,
- // BuiltinOperator_ZEROS_LIKE = 93,
- // BuiltinOperator_FILL = 94,
- // BuiltinOperator_FLOOR_MOD = 95,
- // BuiltinOperator_RANGE = 96,
- // BuiltinOperator_RESIZE_NEAREST_NEIGHBOR = 97,
- // BuiltinOperator_LEAKY_RELU = 98,
- // BuiltinOperator_SQUARED_DIFFERENCE = 99,
- // BuiltinOperator_MIRROR_PAD = 100,
- // BuiltinOperator_SPLIT_V = 102,
// BuiltinOperator_UNIQUE = 103,
- // BuiltinOperator_CEIL = 104,
- // BuiltinOperator_REVERSE_V2 = 105,
- // BuiltinOperator_ADD_N = 106,
- // BuiltinOperator_GATHER_ND = 107,
- // BuiltinOperator_WHERE = 109,
- // BuiltinOperator_RANK = 110,
- // BuiltinOperator_ELU = 111,
- // BuiltinOperator_REVERSE_SEQUENCE = 112,
- // BuiltinOperator_MATRIX_DIAG = 113,
// BuiltinOperator_QUANTIZE = 114,
- // BuiltinOperator_MATRIX_SET_DIAG = 115,
- // BuiltinOperator_ROUND = 116,
// BuiltinOperator_HARD_SWISH = 117,
- // BuiltinOperator_IF = 118,
- // BuiltinOperator_WHILE = 119,
// BuiltinOperator_NON_MAX_SUPPRESSION_V4 = 120,
// BuiltinOperator_NON_MAX_SUPPRESSION_V5 = 121,
- // BuiltinOperator_SCATTER_ND = 122,
- // BuiltinOperator_SELECT_V2 = 123,
// BuiltinOperator_DENSIFY = 124,
- // BuiltinOperator_SEGMENT_SUM = 125,
- // BuiltinOperator_BATCH_MATMUL = 126,
- // BuiltinOperator_INSTANCE_NORM = 254,
}
} // namespace luci
diff --git a/compiler/luci/import/src/Importer.cpp b/compiler/luci/import/src/Importer.cpp
index 964c47633..ab89f3587 100644
--- a/compiler/luci/import/src/Importer.cpp
+++ b/compiler/luci/import/src/Importer.cpp
@@ -15,6 +15,7 @@
*/
#include "luci/Importer.h"
+#include "PostImport.h"
#include "luci/Import/GraphBuilder.h"
#include "luci/Import/GraphBuilderContext.h"
@@ -27,6 +28,7 @@
#include <luci/Log.h>
#include <luci/LogHelper.h>
+#include <oops/InternalExn.h>
#include <oops/UserExn.h>
#include <memory>
@@ -40,11 +42,28 @@ void convert_graph(const luci::GraphBuilderSource &source, luci::CircleReader &r
LOGGER(l);
auto nodefinder = std::make_unique<luci::IndexNodeFinder>();
+ auto tensoroutputs = std::make_unique<luci::IndexTensorOutputs>();
- luci::GraphBuilderContext gb_context(graph, &reader, nodefinder.get());
+ luci::GraphBuilderContext gb_context(graph, &reader, nodefinder.get(), tensoroutputs.get());
const auto &operators = reader.operators();
const auto &tensors = reader.tensors();
+ auto tensors_ptr = reader.tensors_ptr();
+ assert(tensors_ptr != nullptr);
+
+ // build a cache to identify if a tensor is output of an operator
+ // if this is set, we should not create a CircleConst for this tensor
+ for (uint32_t i = 0; i < operators.size(); ++i)
+ {
+ const circle::OperatorT &op = *operators[i];
+ const auto &outputs = op.outputs;
+
+ for (uint32_t j = 0; j < outputs.size(); ++j)
+ {
+ auto tidx = outputs[j];
+ tensoroutputs->enroll(tidx);
+ }
+ }
// graph inputs; there are no input nodes in TFlite but just Tensors
// creating virtual input nodes will make possible to connect nodes that uses them
@@ -55,51 +74,43 @@ void convert_graph(const luci::GraphBuilderSource &source, luci::CircleReader &r
assert(input_node != nullptr);
const circle::TensorT &tensor = *tensors[input];
- auto tname = luci::tensor_name(tensor);
- input_node->name(tname);
- auto quantization = luci::tensor_quantization(tensor);
- if (quantization)
- {
- auto quantparam = luci::luci_quantparam(quantization);
- if (quantparam.get())
- input_node->quantparam(std::move(quantparam));
- }
+ luci::copy_tensor_attributes(tensor, input_node);
+ if (tensors_ptr->Get(input)->shape() == nullptr)
+ input_node->shape_status(luci::ShapeStatus::NOSHAPE);
+ else
+ input_node->shape_status(luci::ShapeStatus::VALID);
INFO(l) << "[luci] NodeFinder INPUT(" << input << ") = " << input_node << std::endl;
nodefinder->enroll(input, input_node);
- // Shape of Input
- const std::vector<int32_t> &input_dims = tensor.shape; // in NHWC
- input_node->rank(input_dims.size());
- for (uint32_t r = 0; r < input_dims.size(); ++r)
- input_node->dim(r) = loco::Dimension(input_dims[r]);
-
- // Data type of Input
- auto dtype = luci::luci_datatype(tensor.type);
- input_node->dtype(dtype);
+ // input_node is also an output to a tensor
+ tensoroutputs->enroll(input);
// Name
auto graph_input = graph->inputs()->create();
- graph_input->name(tname);
+ graph_input->name(input_node->name());
// Set GraphInputOutputIndex for graph
input_node->index(graph_input->index());
// Data type
- graph_input->dtype(dtype);
+ graph_input->dtype(input_node->dtype());
+
+ // Shape of GraphInput
+ auto input_shape = std::make_unique<loco::TensorShape>();
+ const std::vector<int32_t> &input_dims = tensor.shape; // in NHWC
+ input_shape->rank(input_dims.size());
+ for (uint32_t r = 0; r < input_dims.size(); ++r)
+ input_shape->dim(r) = loco::Dimension(input_dims[r]);
+ graph_input->shape(std::move(input_shape));
}
// Create CircleConst nodes for constant tensors.
- const auto &buffers = reader.buffers();
for (uint32_t i = 0; i < tensors.size(); ++i)
{
- const circle::TensorT &tensor = *tensors[i];
- const std::vector<uint8_t> &buffer = buffers[tensor.buffer]->data;
- if (!buffer.empty())
- {
- luci::CircleConst *const_node = luci::create_circleconst(&gb_context, i);
+ luci::CircleConst *const_node = luci::create_circleconst(&gb_context, i);
+ if (const_node != nullptr)
nodefinder->enroll(i, const_node);
- }
}
// Import the operators.
@@ -130,18 +141,38 @@ void convert_graph(const luci::GraphBuilderSource &source, luci::CircleReader &r
// graph outputs
for (auto output : reader.outputs())
{
+ const circle::TensorT &tensor = *tensors[output];
+
auto output_node = graph->nodes()->create<luci::CircleOutput>();
assert(output_node != nullptr);
- output_node->from(nodefinder->node(output));
+ auto output_from = nodefinder->node(output);
+ if (output_from != nullptr)
+ output_node->from(output_from);
+ else
+ {
+ // NOTE loco::Graph requires all input node(s) to a node should exist.
+ // Here, CircleOutput needs an input node.
+ // We add a dummy node to make it happy.
+ auto output_dummy = graph->nodes()->create<luci::CircleOutputDummy>();
+ assert(output_dummy != nullptr);
+ output_node->from(output_dummy);
+
+ luci::copy_tensor_attributes(tensor, output_dummy);
+ if (tensors_ptr->Get(output)->shape() == nullptr)
+ output_dummy->shape_status(luci::ShapeStatus::NOSHAPE);
+ else
+ output_dummy->shape_status(luci::ShapeStatus::VALID);
+ }
INFO(l) << "[luci] NodeFinder OUTPUT(" << output << ") = " << output_node << std::endl;
// set the graph output name and node object
- const circle::TensorT &tensor = *tensors[output];
auto graph_output = graph->outputs()->create();
std::string tname = luci::tensor_name(tensor);
graph_output->name("output_" + tname);
+ luci::copy_tensor_attributes(tensor, output_node);
+
// Set GraphInputOutputIndex for graph
output_node->index(graph_output->index());
@@ -195,8 +226,10 @@ std::unique_ptr<loco::Graph> Importer::import(const circle::Model *model) const
if (!reader.parse(model))
return nullptr;
- // TODO support multiple subgraph when Circle supports
- assert(reader.num_subgraph() == 1);
+ if (reader.num_subgraph() != 1)
+ {
+ INTERNAL_EXN("Use 'importModule()' for multiple subgraphs");
+ }
if (!reader.select_subgraph(0))
return nullptr;
@@ -204,11 +237,14 @@ std::unique_ptr<loco::Graph> Importer::import(const circle::Model *model) const
convert_graph(*source_ptr, reader, graph.get());
LOGGER(l);
- INFO(l) << fmt(graph.get());
+ VERBOSE(l, 3) << "--- graph dump begin -------------------------------------------";
+ VERBOSE(l, 3) << "Name: " << graph->name();
+ VERBOSE(l, 3) << fmt(graph.get());
+ VERBOSE(l, 3) << "--- graph dump end ---------------------------------------------";
assert(loco::valid(graph.get(), std::make_unique<ValidateCollector>()));
- return std::move(graph);
+ return graph;
}
std::unique_ptr<Module> Importer::importModule(const circle::Model *model) const
@@ -240,14 +276,19 @@ std::unique_ptr<Module> Importer::importModule(const circle::Model *model) const
convert_graph(*source_ptr, reader, graph.get());
LOGGER(l);
- INFO(l) << fmt(graph.get());
+ VERBOSE(l, 3) << "--- graph dump begin -------------------------------------------";
+ VERBOSE(l, 3) << "Name: " << graph->name();
+ VERBOSE(l, 3) << fmt(graph.get());
+ VERBOSE(l, 3) << "--- graph dump end ---------------------------------------------";
assert(loco::valid(graph.get(), std::make_unique<ValidateCollector>()));
module->add(std::move(graph));
}
- return std::move(module);
+ post_import_graph(module.get(), reader);
+
+ return module;
}
} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleAddN.cpp b/compiler/luci/import/src/Nodes/CircleAddN.cpp
new file mode 100644
index 000000000..2f1716e62
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleAddN.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleAddN.h"
+
+#include <luci/IR/Nodes/CircleAdd.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleAddNGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() < 1)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleAddNGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleAddN>(inputs.size());
+ for (uint32_t i = 0; i < inputs.size(); ++i)
+ {
+ node->inputs(i, inputs[i]);
+ }
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleArgMin.cpp b/compiler/luci/import/src/Nodes/CircleArgMin.cpp
new file mode 100644
index 000000000..4d85bbff0
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleArgMin.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleArgMin.h"
+
+#include <luci/IR/Nodes/CircleArgMin.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleArgMinGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleArgMinGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleArgMin>();
+ node->input(inputs[0]);
+ node->dimension(inputs[1]);
+
+ const auto *options = op.builtin_options.AsArgMinOptions();
+ node->output_type(luci_datatype(options->output_type));
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp b/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp
new file mode 100644
index 000000000..7cc077ed6
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp
@@ -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.
+ */
+
+#include "luci/Import/Nodes/CircleBCQFullyConnected.h"
+
+#include <luci/IR/Nodes/CircleBCQFullyConnected.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleBCQFullyConnectedGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 5)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleBCQFullyConnectedGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleBCQFullyConnected>();
+
+ node->input(inputs[0]);
+ node->weights_scales(inputs[1]);
+ node->weights_binary(inputs[2]);
+ node->bias(inputs[3]);
+ node->weights_clusters(inputs[4]);
+
+ // TODO Find and move to appropriate place for setting optional input
+ if (auto bias = dynamic_cast<luci::CircleOutputExclude *>(node->bias()))
+ {
+ // bias is not used for type inference, but node itself should have a type
+ bias->dtype(loco::DataType::FLOAT32);
+
+ // bias is not used for shape inference
+ }
+
+ const auto *options = op.builtin_options.AsBCQFullyConnectedOptions();
+ node->weights_hidden_size(options->weights_hidden_size);
+ node->fusedActivationFunction(luci_actfunc(options->fused_activation_function));
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleBCQGather.cpp b/compiler/luci/import/src/Nodes/CircleBCQGather.cpp
new file mode 100644
index 000000000..c6d2ab559
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleBCQGather.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleBCQGather.h"
+
+#include <luci/IR/Nodes/CircleBCQGather.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleBCQGatherGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 4)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleBCQGatherGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleBCQGather>();
+
+ node->input_scales(inputs[0]);
+ node->input_binary(inputs[1]);
+ node->indices(inputs[2]);
+ node->input_clusters(inputs[3]);
+
+ const auto *options = op.builtin_options.AsBCQGatherOptions();
+ node->input_hidden_size(options->input_hidden_size);
+ node->axis(options->axis);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp b/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp
new file mode 100644
index 000000000..6026b2a72
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleBatchMatMul.h"
+
+#include <luci/IR/Nodes/CircleBatchMatMul.h>
+
+namespace luci
+{
+
+bool CircleBatchMatMulGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleBatchMatMulGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleBatchMatMul>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ const auto *options = op.builtin_options.AsBatchMatMulOptions();
+ node->adj_x(options->adjoint_lhs);
+ node->adj_y(options->adjoint_rhs);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleCast.cpp b/compiler/luci/import/src/Nodes/CircleCast.cpp
new file mode 100644
index 000000000..a4d09b505
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleCast.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleCast.h"
+
+#include <luci/IR/Nodes/CircleCast.h>
+
+#include <luci/UserSettings.h>
+#include <luci/Log.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleCastGraphBuilder::validate(const ValidateArgs &args) const
+{
+ LOGGER(l);
+
+ auto settings = luci::UserSettings::settings();
+
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 1)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ // NOTE real models do have type mismatch
+ const auto *options = args.op.builtin_options.AsCastOptions();
+ if (options != nullptr)
+ {
+ const auto &tensors = args.reader.tensors();
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ auto name = tensor_name(output_tensor);
+
+ const auto &tensor_in = tensors.at(inputs[0]);
+ if (tensor_in->type != options->in_data_type)
+ {
+ if (settings->get(luci::UserSettings::Key::DisableValidation))
+ {
+ WARN(l) << "Warning: import Cast(" << name << ") dtype mismatch";
+ }
+ else
+ return false;
+ }
+ const auto &tensor_out = tensors.at(outputs[0]);
+ if (tensor_out->type != options->out_data_type)
+ {
+ if (settings->get(luci::UserSettings::Key::DisableValidation))
+ {
+ WARN(l) << "Warning: import Cast(" << name << ") dtype mismatch";
+ }
+ else
+ return false;
+ }
+ }
+
+ return true;
+}
+
+CircleNode *CircleCastGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleCast>();
+ node->x(inputs[0]);
+
+ const auto *options = op.builtin_options.AsCastOptions();
+ if (options != nullptr)
+ {
+ node->in_data_type(luci_datatype(options->in_data_type));
+ node->out_data_type(luci_datatype(options->out_data_type));
+ }
+ else
+ {
+ node->in_data_type(inputs[0]->dtype());
+ node->out_data_type(loco::DataType::Unknown);
+ // type inference should use node->dtype() for Unknown
+ // export should use BuiltinOptions_NONE for Unknown
+ }
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleCeil.cpp b/compiler/luci/import/src/Nodes/CircleCeil.cpp
new file mode 100644
index 000000000..d3d6cd945
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleCeil.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleCeil.h"
+
+#include <luci/IR/Nodes/CircleCeil.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleCeilGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 1)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ // TODO dtype check
+
+ return true;
+}
+
+CircleNode *CircleCeilGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleCeil>();
+ node->x(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleConst.cpp b/compiler/luci/import/src/Nodes/CircleConst.cpp
index 1d798983b..7131dc115 100644
--- a/compiler/luci/import/src/Nodes/CircleConst.cpp
+++ b/compiler/luci/import/src/Nodes/CircleConst.cpp
@@ -24,6 +24,24 @@
#include <cassert>
+namespace
+{
+
+std::ostream &operator<<(std::ostream &os, const std::vector<int32_t> &vect)
+{
+ uint32_t seq = 0;
+ for (auto &v : vect)
+ {
+ if (seq)
+ os << ", ";
+ os << v;
+ seq++;
+ }
+ return os;
+}
+
+} // namespace
+
namespace luci
{
@@ -53,55 +71,73 @@ CircleConst *create_circleconst(GraphBuilderContext *context, int32_t tensor_ind
auto graph = context->graph();
auto reader = context->reader();
const auto &tensors = reader->tensors();
-
- // (1) create CircleConst
- auto const_node = graph->nodes()->create<CircleConst>();
const circle::TensorT &const_tensor = *tensors[tensor_index];
- const_node->name(tensor_name(const_tensor));
- auto quantization = luci::tensor_quantization(const_tensor);
- if (quantization)
+
+ const std::vector<uint8_t> &buffer = reader->buffers()[const_tensor.buffer]->data;
+ std::vector<int32_t> const_dims = const_tensor.shape; // in NHWC
+ if (const_dims.size() == 0 && buffer.empty())
{
- auto quantparam = luci::luci_quantparam(quantization);
- if (quantparam.get())
- const_node->quantparam(std::move(quantparam));
+ // unknown shape tensor
+ return nullptr;
}
- INFO(l) << "[luci] NodeFinder const_node(" << tensor_index << ") -> " << const_node << std::endl;
-
- // (2) set data_type to CircleConst
- const_node->dtype(luci_datatype(const_tensor.type));
+ // if tensor_index is used as output to some other operator, this is not a constant
+ auto tensoroutputs = context->tensoroutputs();
+ if (tensoroutputs->find(tensor_index))
+ {
+ // other operator output tensor
+ return nullptr;
+ }
- // (3) set shape to CicleConst
- std::vector<int32_t> const_dims = const_tensor.shape; // in NHWC
- const_node->rank(const_dims.size());
uint32_t num_elements = 1;
for (uint32_t r = 0; r < const_dims.size(); ++r)
{
- const_node->dim(r) = loco::Dimension(const_dims[r]);
num_elements = num_elements * const_dims[r];
}
- // (4) constant values from circle buffer
- const std::vector<uint8_t> &buffer = reader->buffers()[const_tensor.buffer]->data;
- if (buffer.empty())
- throw oops::UserExn("Empty buffer");
-
- switch (luci_datatype(const_tensor.type))
+ if (buffer.empty() && num_elements > 0)
{
- case loco::DataType::FLOAT32:
- copy_data<loco::DataType::FLOAT32>(buffer, num_elements, const_node);
- break;
-
- case loco::DataType::U8:
- copy_data<loco::DataType::U8>(buffer, num_elements, const_node);
- break;
-
- case loco::DataType::S32:
- copy_data<loco::DataType::S32>(buffer, num_elements, const_node);
- break;
+ // normal empty tensor
+ return nullptr;
+ }
- default:
- throw oops::UserExn("Unsupported tensor type", circle::EnumNameTensorType(const_tensor.type));
+ auto const_node = graph->nodes()->create<CircleConst>();
+ copy_tensor_attributes(const_tensor, const_node);
+ const_node->shape_status(luci::ShapeStatus::VALID);
+ INFO(l) << "[luci] NodeFinder const_node(" << tensor_index << ") -> " << const_node << " "
+ << const_dims << std::endl;
+ if (num_elements > 0)
+ {
+ switch (luci_datatype(const_tensor.type))
+ {
+ case loco::DataType::FLOAT32:
+ copy_data<loco::DataType::FLOAT32>(buffer, num_elements, const_node);
+ break;
+
+ case loco::DataType::U8:
+ copy_data<loco::DataType::U8>(buffer, num_elements, const_node);
+ break;
+
+ case loco::DataType::S16:
+ copy_data<loco::DataType::S16>(buffer, num_elements, const_node);
+ break;
+
+ case loco::DataType::S32:
+ copy_data<loco::DataType::S32>(buffer, num_elements, const_node);
+ break;
+
+ case loco::DataType::S64:
+ copy_data<loco::DataType::S64>(buffer, num_elements, const_node);
+ break;
+
+ case loco::DataType::BOOL:
+ copy_data<loco::DataType::BOOL>(buffer, num_elements, const_node);
+ break;
+
+ default:
+ throw oops::UserExn("Unsupported tensor type",
+ circle::EnumNameTensorType(const_tensor.type));
+ }
}
return const_node;
diff --git a/compiler/luci/import/src/Nodes/CircleConv2D.cpp b/compiler/luci/import/src/Nodes/CircleConv2D.cpp
index ec9dce0d2..42c5c265a 100644
--- a/compiler/luci/import/src/Nodes/CircleConv2D.cpp
+++ b/compiler/luci/import/src/Nodes/CircleConv2D.cpp
@@ -50,7 +50,8 @@ CircleNode *CircleConv2DGraphBuilder::build_node(const circle::OperatorT &op,
node->stride()->w(options->stride_w);
node->stride()->h(options->stride_h);
node->fusedActivationFunction(luci_actfunc(options->fused_activation_function));
- // FIXME Check dilation_w_factor, dilation_h_factor.
+ node->dilation()->w(options->dilation_w_factor);
+ node->dilation()->h(options->dilation_h_factor);
return node;
}
diff --git a/compiler/luci/import/src/Nodes/CircleCustom.cpp b/compiler/luci/import/src/Nodes/CircleCustom.cpp
new file mode 100644
index 000000000..d541ee87b
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleCustom.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleCustom.h"
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleCustomGraphBuilder::validate(const ValidateArgs &) const
+{
+ // DO NOTHING
+ return true;
+}
+
+void CircleCustomGraphBuilder::build(const circle::OperatorT &op,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+
+ const std::vector<int32_t> &inputs = op.inputs;
+ const std::vector<int32_t> &outputs = op.outputs;
+ const auto &tensors = context->reader()->tensors();
+ auto tensors_ptr = context->reader()->tensors_ptr();
+ assert(tensors_ptr != nullptr);
+
+ // Create CircleCustom
+ const auto &opcodes = context->reader()->opcodes();
+ const uint32_t opcode_index = op.opcode_index;
+ const circle::OperatorCodeT &opcode = *opcodes[opcode_index];
+
+ auto *node = graph->nodes()->create<CircleCustom>(inputs.size());
+ uint32_t input_idx = 0;
+ for (const int32_t input_tensor_index : inputs)
+ {
+ node->inputs(input_idx++, context->nodefinder()->node(input_tensor_index));
+ }
+ node->custom_options(std::vector<uint8_t>{op.custom_options.begin(), op.custom_options.end()});
+ node->custom_code(opcode.custom_code);
+ // Operator version of custom is always 1, so do nothing
+
+ uint32_t output_count = outputs.size();
+
+ assert(output_count > 0);
+ {
+ // Let's use attributes from output 0 for this node
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ node->name(tensor_name(output_tensor));
+ node->dtype(luci_datatype(output_tensor.type));
+ }
+
+ // Create virtual outputs of Custom
+ for (uint32_t n = 0; n < output_count; ++n)
+ {
+ const circle::TensorT &output_tensor = *tensors[outputs[n]];
+
+ auto *nodeout = graph->nodes()->create<CircleCustomOut>();
+ copy_tensor_attributes(output_tensor, nodeout);
+ // mark shape_status
+ if (tensors_ptr->Get(outputs[n])->shape() == nullptr)
+ nodeout->shape_status(ShapeStatus::NOSHAPE);
+ else
+ nodeout->shape_status(ShapeStatus::VALID);
+
+ nodeout->input(node);
+ nodeout->index(n);
+
+ context->nodefinder()->enroll(outputs[n], nodeout);
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp b/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp
new file mode 100644
index 000000000..827b63468
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleDepthToSpace.h"
+
+#include <luci/IR/Nodes/CircleDepthToSpace.h>
+
+#include <loco.h>
+
+#include <cassert>
+
+namespace luci
+{
+
+bool CircleDepthToSpaceGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ const auto *options = args.op.builtin_options.AsDepthToSpaceOptions();
+
+ if (inputs.size() != 1)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+
+ if (tensors[outputs[0]]->type != tensors[inputs[0]]->type)
+ {
+ return false;
+ }
+
+ if (options->block_size < 2)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleDepthToSpaceGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleDepthToSpace>();
+ node->input(inputs[0]);
+
+ const auto *options = op.builtin_options.AsDepthToSpaceOptions();
+ node->block_size(options->block_size);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp b/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp
index c6d3b1f1e..2b13f9ebb 100644
--- a/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp
+++ b/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp
@@ -52,7 +52,8 @@ CircleNode *CircleDepthwiseConv2DGraphBuilder::build_node(const circle::Operator
node->stride()->h(options->stride_h);
node->depthMultiplier(options->depth_multiplier);
node->fusedActivationFunction(luci_actfunc(options->fused_activation_function));
- // FIXME Check dilation_w_factor, dilation_h_factor.
+ node->dilation()->w(options->dilation_w_factor);
+ node->dilation()->h(options->dilation_h_factor);
return node;
}
diff --git a/compiler/luci/import/src/Nodes/CircleElu.cpp b/compiler/luci/import/src/Nodes/CircleElu.cpp
new file mode 100644
index 000000000..37a290cb1
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleElu.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleElu.h"
+
+#include <luci/IR/Nodes/CircleElu.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleEluGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 1)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT32:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensors[outputs[0]]->type != tensor->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleEluGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleElu>();
+ node->features(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleExp.cpp b/compiler/luci/import/src/Nodes/CircleExp.cpp
index 44fc93d09..a32851458 100644
--- a/compiler/luci/import/src/Nodes/CircleExp.cpp
+++ b/compiler/luci/import/src/Nodes/CircleExp.cpp
@@ -16,7 +16,7 @@
#include "luci/Import/Nodes/CircleExp.h"
-#include <luci/IR/Nodes/CircleAbs.h>
+#include <luci/IR/Nodes/CircleExp.h>
#include <loco.h>
@@ -50,7 +50,7 @@ CircleNode *CircleExpGraphBuilder::build_node(const circle::OperatorT &,
const std::vector<CircleNode *> &inputs,
loco::Graph *graph) const
{
- auto *node = graph->nodes()->create<CircleAbs>();
+ auto *node = graph->nodes()->create<CircleExp>();
node->x(inputs[0]);
return node;
diff --git a/compiler/luci/import/src/Nodes/CircleExpandDims.cpp b/compiler/luci/import/src/Nodes/CircleExpandDims.cpp
new file mode 100644
index 000000000..1cef67a83
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleExpandDims.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleExpandDims.h"
+
+#include <luci/IR/Nodes/CircleExpandDims.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleExpandDimsGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+
+ if (inputs.size() != 2)
+ {
+ return false;
+ }
+
+ const auto &tensors = args.reader.tensors();
+
+ return tensors[inputs[1]]->type == circle::TensorType_INT32;
+}
+
+CircleNode *CircleExpandDimsGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleExpandDims>();
+ node->input(inputs[0]);
+ node->axis(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleFill.cpp b/compiler/luci/import/src/Nodes/CircleFill.cpp
new file mode 100644
index 000000000..6c3d3a247
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleFill.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleFill.h"
+
+#include <luci/IR/Nodes/CircleFill.h>
+
+namespace luci
+{
+
+bool CircleFillGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleFillGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleFill>();
+ node->dims(inputs[0]);
+ node->value(inputs[1]);
+
+ const auto *options = op.builtin_options.AsFillOptions();
+ (void)options;
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleFloor.cpp b/compiler/luci/import/src/Nodes/CircleFloor.cpp
new file mode 100644
index 000000000..302a9eae3
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleFloor.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleFloor.h"
+
+#include <luci/IR/Nodes/CircleFloor.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleFloorGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 1)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ // TODO dtype check
+
+ return true;
+}
+
+CircleNode *CircleFloorGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleFloor>();
+ node->x(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp b/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp
new file mode 100644
index 000000000..875197890
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleFloorDiv.h"
+
+#include <luci/IR/Nodes/CircleFloorDiv.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleFloorDivGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ {
+ return false;
+ }
+
+ if (outputs.size() != 1)
+ {
+ return false;
+ }
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_in_0 = tensors.at(inputs[0]);
+ const auto &tensor_in_1 = tensors.at(inputs[1]);
+ const auto &tensor_out = tensors.at(outputs[0]);
+
+ if (tensor_in_0->type != tensor_in_1->type)
+ return false;
+
+ if (tensor_out->type != tensor_in_1->type)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleFloorDivGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleFloorDiv>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleFloorMod.cpp b/compiler/luci/import/src/Nodes/CircleFloorMod.cpp
new file mode 100644
index 000000000..3ccdce0cd
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleFloorMod.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleFloorMod.h"
+
+#include <luci/IR/Nodes/CircleFloorMod.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleFloorModGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 2)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_in_0 = tensors.at(inputs[0]);
+ const auto &tensor_in_1 = tensors.at(inputs[1]);
+ if (tensor_in_0->type != tensor_in_1->type)
+ return false;
+
+ // TODO dtype check
+
+ return true;
+}
+
+CircleNode *CircleFloorModGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleFloorMod>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp b/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp
index 8f74fe9ce..8937e78f1 100644
--- a/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp
+++ b/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp
@@ -17,6 +17,7 @@
#include "luci/Import/Nodes/CircleFullyConnected.h"
#include <luci/IR/Nodes/CircleFullyConnected.h>
+#include <luci/IR/Nodes/CircleOutput.h>
#include <loco.h>
#include <oops/UserExn.h>
@@ -39,7 +40,16 @@ CircleNode *CircleFullyConnectedGraphBuilder::build_node(const circle::OperatorT
auto *node = graph->nodes()->create<CircleFullyConnected>();
node->input(inputs[0]);
node->weights(inputs[1]);
- node->bias(inputs[2]);
+ node->bias(inputs[2]); // bias is optional
+
+ // TODO Find and move to appropriate place for setting optional input
+ if (auto bias = dynamic_cast<luci::CircleOutputExclude *>(node->bias()))
+ {
+ // bias is not used for type inference, but node itself should have a type
+ bias->dtype(loco::DataType::FLOAT32);
+
+ // bias is not used for shape inference
+ }
const auto *options = op.builtin_options.AsFullyConnectedOptions();
node->fusedActivationFunction(luci_actfunc(options->fused_activation_function));
diff --git a/compiler/luci/import/src/Nodes/CircleGather.cpp b/compiler/luci/import/src/Nodes/CircleGather.cpp
new file mode 100644
index 000000000..1caa05ec2
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleGather.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleGather.h"
+
+#include <luci/IR/Nodes/CircleGather.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+bool CircleGatherGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ const auto *options = args.op.builtin_options.AsGatherOptions();
+
+ int32_t axis = options->axis;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ if (axis < 0)
+ axis += inputs.size();
+
+ if (axis < 0)
+ return false;
+
+ // TODO do indices type check
+ // TODO do axis check when shape information is given
+
+ return true;
+}
+
+CircleNode *CircleGatherGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleGather>();
+
+ node->params(inputs[0]);
+ node->indices(inputs[1]);
+
+ const auto *options = op.builtin_options.AsGatherOptions();
+ node->axis(options->axis);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleGatherNd.cpp b/compiler/luci/import/src/Nodes/CircleGatherNd.cpp
new file mode 100644
index 000000000..621d4ae92
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleGatherNd.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleGatherNd.h"
+
+#include <luci/IR/Nodes/CircleGatherNd.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+#include <mio/circle/schema_generated.h>
+
+namespace luci
+{
+
+bool CircleGatherNdGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ auto &indices_tensor = args.reader.tensors()[inputs[1]];
+
+ if (!(indices_tensor->type == circle::TensorType::TensorType_INT32 ||
+ indices_tensor->type == circle::TensorType::TensorType_INT64))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleGatherNdGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleGatherNd>();
+
+ node->params(inputs[0]);
+ node->indices(inputs[1]);
+
+ // GatherNd options empty
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleGreater.cpp b/compiler/luci/import/src/Nodes/CircleGreater.cpp
new file mode 100644
index 000000000..88107589c
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleGreater.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleGreater.h"
+
+#include <luci/IR/Nodes/CircleGreater.h>
+
+#include <luci/UserSettings.h>
+#include <luci/Log.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleGreaterGraphBuilder::validate(const ValidateArgs &args) const
+{
+ LOGGER(l);
+
+ auto settings = luci::UserSettings::settings();
+
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+
+ if (tensors[inputs[0]]->type != tensors[inputs[1]]->type)
+ return false;
+
+ // NOTE: real models do have output dtype NOT BOOL
+ if (tensors[outputs[0]]->type != circle::TensorType_BOOL)
+ {
+ if (settings->get(luci::UserSettings::Key::DisableValidation))
+ {
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ auto name = tensor_name(output_tensor);
+ WARN(l) << "Warning: import Greater(" << name << ") output dtype is not boolean";
+ }
+ else
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleGreaterGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleGreater>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp b/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp
new file mode 100644
index 000000000..dff1510c5
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp
@@ -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.
+ */
+
+#include "luci/Import/Nodes/CircleGreaterEqual.h"
+
+#include <luci/IR/Nodes/CircleGreaterEqual.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleGreaterEqualGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ {
+ return false;
+ }
+
+ if (outputs.size() != 1)
+ {
+ return false;
+ }
+
+ const auto &tensors = args.reader.tensors();
+
+ if (tensors[inputs[0]]->type != tensors[inputs[1]]->type)
+ {
+ return false;
+ }
+
+ return tensors[outputs[0]]->type == circle::TensorType::TensorType_BOOL;
+}
+
+CircleNode *CircleGreaterEqualGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleGreaterEqual>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleIf.cpp b/compiler/luci/import/src/Nodes/CircleIf.cpp
new file mode 100644
index 000000000..d6090640d
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleIf.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleIf.h"
+
+#include <luci/IR/Nodes/CircleIf.h>
+#include <luci/IR/Nodes/CircleIfOut.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+bool CircleIfGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto *options = args.op.builtin_options.AsIfOptions();
+
+ if (inputs.size() < 2) // cond + input
+ return false;
+ if (args.op.outputs.size() < 1) // output
+ return false;
+
+ auto num_graphs = static_cast<int32_t>(args.reader.num_subgraph());
+ if (options->then_subgraph_index >= num_graphs)
+ return false;
+ if (options->else_subgraph_index >= num_graphs)
+ return false;
+
+ // input 0 should be BOOL type
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ if (tensor->type != circle::TensorType_BOOL)
+ return false;
+
+ const auto &shape = tensor->shape;
+ if (shape.size() != 1 && shape.size() != 0)
+ return false;
+
+ return true;
+}
+
+/**
+ * @brief If Node builder
+ *
+ * @note Current loco does not provide multiple outputs
+ * We will create multiple CircleIfOut nodes to emulate this
+ * For two outputs that may look like this
+ *
+ * --- CircleIf --- Node ---
+ * \- Node ---
+ *
+ * will be created like this
+ *
+ * --- CircleIf --- CircleIfOut --- Node ---
+ * \- CircleIfOut --- Node ---
+ */
+
+void CircleIfGraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+
+ const std::vector<int32_t> &inputs = op.inputs;
+ const std::vector<int32_t> &outputs = op.outputs;
+ const auto &tensors = context->reader()->tensors();
+ const auto &opcodes = context->reader()->opcodes();
+ auto tensors_ptr = context->reader()->tensors_ptr();
+ assert(tensors_ptr != nullptr);
+
+ std::vector<CircleNode *> input_nodes;
+ for (const int32_t input_tensor_index : inputs)
+ {
+ input_nodes.push_back(context->nodefinder()->node(input_tensor_index));
+ }
+
+ uint32_t input_count = inputs.size() - 1;
+ uint32_t output_count = outputs.size();
+
+ // Create CircleIf
+ CircleIf *node = graph->nodes()->create<CircleIf>(input_count, output_count);
+
+ node->cond(input_nodes[0]);
+ for (uint32_t idx = 0; idx < input_count; ++idx)
+ {
+ node->input(idx, input_nodes[idx + 1]);
+ }
+
+ const auto *options = op.builtin_options.AsIfOptions();
+ node->then_branch(options->then_subgraph_index);
+ node->else_branch(options->else_subgraph_index);
+
+ assert(outputs.size() > 0);
+ {
+ // Lets use name of output 0 as If name
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ node->name(tensor_name(output_tensor));
+ node->op_version(opcodes[op.opcode_index].get()->version);
+
+ // NOTE We don't set quantization for If itself but to virtual outputs
+ }
+
+ // Create virtual outputs of If
+ for (uint32_t n = 0; n < output_count; ++n)
+ {
+ const circle::TensorT &output_tensor = *tensors[outputs[n]];
+
+ auto *nodeout = graph->nodes()->create<CircleIfOut>();
+ copy_tensor_attributes(output_tensor, nodeout);
+ // mark shape_status
+ if (tensors_ptr->Get(outputs[n])->shape() == nullptr)
+ nodeout->shape_status(ShapeStatus::NOSHAPE);
+ else
+ nodeout->shape_status(ShapeStatus::VALID);
+
+ nodeout->input(node);
+ nodeout->index(n);
+
+ context->nodefinder()->enroll(outputs[n], nodeout);
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp b/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp
new file mode 100644
index 000000000..b95c54c89
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleInstanceNorm.h"
+
+#include <luci/IR/Nodes/CircleInstanceNorm.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleInstanceNormGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 3)
+ return false;
+
+ // TODO check dtypes
+
+ return true;
+}
+
+CircleNode *CircleInstanceNormGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleInstanceNorm>();
+ node->input(inputs[0]);
+ node->gamma(inputs[1]);
+ node->beta(inputs[2]);
+
+ const auto *options = op.builtin_options.AsInstanceNormOptions();
+ node->epsilon(options->epsilon);
+ node->fusedActivationFunction(luci_actfunc(options->fused_activation_function));
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp b/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp
new file mode 100644
index 000000000..fe10a8572
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleL2Normalize.h"
+
+#include <luci/IR/Nodes/CircleL2Normalize.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleL2NormalizeGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 1)
+ {
+ return false;
+ }
+
+ if (outputs.size() != 1)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleL2NormalizeGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleL2Normalize>();
+ node->x(inputs[0]);
+ const auto *options = op.builtin_options.AsL2NormOptions();
+ node->fusedActivationFunction(luci_actfunc(options->fused_activation_function));
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp b/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp
new file mode 100644
index 000000000..023206695
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleL2Pool2D.h"
+
+#include <luci/IR/Nodes/CircleL2Pool2D.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleL2Pool2DGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ // TODO check dtypes
+
+ return true;
+}
+
+CircleNode *CircleL2Pool2DGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleL2Pool2D>();
+ node->value(inputs[0]);
+
+ const auto *options = op.builtin_options.AsPool2DOptions();
+ node->padding(luci_padding(options->padding));
+ node->stride()->w(options->stride_w);
+ node->stride()->h(options->stride_h);
+ node->filter()->w(options->filter_width);
+ node->filter()->h(options->filter_height);
+ node->fusedActivationFunction(luci_actfunc(options->fused_activation_function));
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp b/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp
new file mode 100644
index 000000000..4957ceae0
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleLeakyRelu.h"
+
+#include <luci/IR/Nodes/CircleLeakyRelu.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleLeakyReluGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleLeakyReluGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleLeakyRelu>();
+ node->features(inputs[0]);
+
+ const auto *options = op.builtin_options.AsLeakyReluOptions();
+ node->alpha(options->alpha);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleLess.cpp b/compiler/luci/import/src/Nodes/CircleLess.cpp
new file mode 100644
index 000000000..40ad28c6e
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleLess.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleLess.h"
+
+#include <luci/IR/Nodes/CircleLess.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleLessGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ {
+ return false;
+ }
+
+ if (outputs.size() != 1)
+ {
+ return false;
+ }
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ case circle::TensorType_INT32:
+ case circle::TensorType_UINT8:
+ case circle::TensorType_INT16:
+ case circle::TensorType_INT8:
+ case circle::TensorType_INT64:
+ case circle::TensorType_FLOAT16:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensors[inputs[1]]->type != tensor->type)
+ {
+ return false;
+ }
+
+ return tensors[outputs[0]]->type == circle::TensorType_BOOL;
+}
+
+CircleNode *CircleLessGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleLess>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleLessEqual.cpp b/compiler/luci/import/src/Nodes/CircleLessEqual.cpp
new file mode 100644
index 000000000..13e995069
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleLessEqual.cpp
@@ -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.
+ */
+
+#include "luci/Import/Nodes/CircleLessEqual.h"
+
+#include <luci/IR/Nodes/CircleLessEqual.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleLessEqualGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ {
+ return false;
+ }
+
+ if (outputs.size() != 1)
+ {
+ return false;
+ }
+
+ const auto &tensors = args.reader.tensors();
+
+ if (tensors[inputs[0]]->type != tensors[inputs[1]]->type)
+ {
+ return false;
+ }
+
+ return tensors[outputs[0]]->type == circle::TensorType::TensorType_BOOL;
+}
+
+CircleNode *CircleLessEqualGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleLessEqual>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp b/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp
new file mode 100644
index 000000000..7b1f0db56
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleLocalResponseNormalization.h"
+
+#include <luci/IR/Nodes/CircleLocalResponseNormalization.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleLocalResponseNormalizationGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ // TODO do attribute checks
+
+ return true;
+}
+
+CircleNode *CircleLocalResponseNormalizationGraphBuilder::build_node(
+ const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleLocalResponseNormalization>();
+ node->input(inputs[0]);
+
+ const auto *options = op.builtin_options.AsLocalResponseNormalizationOptions();
+ node->radius(options->radius);
+ node->bias(options->bias);
+ node->alpha(options->alpha);
+ node->beta(options->beta);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleLog.cpp b/compiler/luci/import/src/Nodes/CircleLog.cpp
new file mode 100644
index 000000000..21408327d
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleLog.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleLog.h"
+
+#include <luci/IR/Nodes/CircleLog.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleLogGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 1)
+ return false;
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ // input type check
+ // Must be one of bfloat16, half, float32, float64, complex64, complex128.
+ // Currently circle supports half(float16), float32, float64, complex64.
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ case circle::TensorType_COMPLEX64:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleLogGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleLog>();
+ node->x(inputs[0]);
+
+ // No options for Log
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp b/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp
new file mode 100644
index 000000000..e738c4a0c
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleLogSoftmax.h"
+
+#include <luci/IR/Nodes/CircleLogSoftmax.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleLogSoftmaxGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ // TODO do attribute checks
+
+ return true;
+}
+
+CircleNode *CircleLogSoftmaxGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleLogSoftmax>();
+ node->logits(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp b/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp
new file mode 100644
index 000000000..8509dbaf3
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleLogicalAnd.h"
+
+#include <luci/IR/Nodes/CircleLogicalAnd.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleLogicalAndGraphBuilder::validate(const ValidateArgs &args) const
+{
+ // Only BOOL type is allowed for inputs
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 2)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ for (auto input : inputs)
+ {
+ const auto &tensor = tensors.at(input);
+ if (tensor->type != circle::TensorType::TensorType_BOOL)
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleLogicalAndGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleLogicalAnd>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleLogistic.cpp b/compiler/luci/import/src/Nodes/CircleLogistic.cpp
new file mode 100644
index 000000000..85e7e55b2
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleLogistic.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleLogistic.h"
+
+#include <luci/IR/Nodes/CircleLogistic.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleLogisticGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 1)
+ return false;
+ const auto &outputs = args.op.outputs;
+ if (outputs.size() != 1)
+ return false;
+
+ // Must be one of the following types
+ // float16, float32, float64, complex64, or complex128
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ case circle::TensorType_COMPLEX64:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleLogisticGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleLogistic>();
+ node->x(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp b/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp
new file mode 100644
index 000000000..f4ae03c58
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleMatrixDiag.h"
+
+#include <luci/IR/Nodes/CircleMatrixDiag.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleMatrixDiagGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 1)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+
+ if (tensors[outputs[0]]->type != tensor->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleMatrixDiagGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleMatrixDiag>();
+ node->diagonal(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp b/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp
new file mode 100644
index 000000000..d6f6aee33
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleMatrixSetDiag.h"
+
+#include <luci/IR/Nodes/CircleMatrixSetDiag.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleMatrixSetDiagGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+
+ if (tensors[outputs[0]]->type != tensor->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleMatrixSetDiagGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleMatrixSetDiag>();
+ node->input(inputs[0]);
+ node->diagonal(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleMaximum.cpp b/compiler/luci/import/src/Nodes/CircleMaximum.cpp
new file mode 100644
index 000000000..6ca7e4079
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleMaximum.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleMaximum.h"
+
+#include <luci/IR/Nodes/CircleMaximum.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleMaximumGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensors[inputs[1]]->type != tensor->type)
+ return false;
+
+ if (tensors[outputs[0]]->type != tensor->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleMaximumGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleMaximum>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleMinimum.cpp b/compiler/luci/import/src/Nodes/CircleMinimum.cpp
new file mode 100644
index 000000000..b770f365f
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleMinimum.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleMinimum.h"
+
+#include <luci/IR/Nodes/CircleMinimum.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleMinimumGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensors[inputs[1]]->type != tensor->type)
+ return false;
+
+ if (tensors[outputs[0]]->type != tensor->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleMinimumGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleMinimum>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp b/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp
new file mode 100644
index 000000000..41b5e5d80
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleMirrorPad.h"
+
+#include <luci/IR/Nodes/CircleMirrorPad.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleMirrorPadGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ // TODO check others
+
+ return true;
+}
+
+CircleNode *CircleMirrorPadGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleMirrorPad>();
+ node->input(inputs[0]);
+ node->paddings(inputs[1]);
+
+ const auto *options = op.builtin_options.AsMirrorPadOptions();
+ node->mode(luci_mirrorpad_mode(options->mode));
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleNeg.cpp b/compiler/luci/import/src/Nodes/CircleNeg.cpp
new file mode 100644
index 000000000..3d3079ca2
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleNeg.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleNeg.h"
+
+#include <luci/IR/Nodes/CircleNeg.h>
+
+#include <loco.h>
+
+namespace luci
+{
+bool CircleNegGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ // TODO Support type check
+ return true;
+}
+
+CircleNode *CircleNegGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleNeg>();
+ node->x(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleNotEqual.cpp b/compiler/luci/import/src/Nodes/CircleNotEqual.cpp
new file mode 100644
index 000000000..5b04856db
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleNotEqual.cpp
@@ -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.
+ */
+
+#include "luci/Import/Nodes/CircleNotEqual.h"
+
+#include <luci/IR/Nodes/CircleNotEqual.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleNotEqualGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ {
+ return false;
+ }
+
+ if (outputs.size() != 1)
+ {
+ return false;
+ }
+
+ const auto &tensors = args.reader.tensors();
+
+ if (tensors[inputs[0]]->type != tensors[inputs[1]]->type)
+ {
+ return false;
+ }
+
+ return tensors[outputs[0]]->type == circle::TensorType::TensorType_BOOL;
+}
+
+CircleNode *CircleNotEqualGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleNotEqual>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleOneHot.cpp b/compiler/luci/import/src/Nodes/CircleOneHot.cpp
new file mode 100644
index 000000000..9fdbfa84d
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleOneHot.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleOneHot.h"
+
+#include <luci/IR/Nodes/CircleOneHot.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+bool CircleOneHotGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ const auto *options = args.op.builtin_options.AsOneHotOptions();
+
+ // Only 4 Input come refered from
+ if (inputs.size() != 4)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &indices = tensors.at(inputs[0]);
+ const auto &depth = tensors.at(inputs[1]);
+ const auto &on_value = tensors.at(inputs[2]);
+ const auto &off_value = tensors.at(inputs[3]);
+
+ if (options->axis < -1 || options->axis > static_cast<int32_t>(indices->shape.size()))
+ return false;
+ if (depth->shape.size() != 0)
+ return false;
+ if (on_value->shape.size() != 0)
+ return false;
+ if (off_value->shape.size() != 0)
+ return false;
+ if (on_value->type != off_value->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleOneHotGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleOneHot>();
+
+ node->indices(inputs[0]);
+ node->depth(inputs[1]);
+ node->on_value(inputs[2]);
+ node->off_value(inputs[3]);
+
+ const auto *options = op.builtin_options.AsOneHotOptions();
+ node->axis(options->axis);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CirclePRelu.cpp b/compiler/luci/import/src/Nodes/CirclePRelu.cpp
new file mode 100644
index 000000000..0d87cd423
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CirclePRelu.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CirclePRelu.h"
+
+#include <luci/IR/Nodes/CirclePRelu.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CirclePReluGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CirclePReluGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CirclePRelu>();
+ node->input(inputs[0]);
+ node->alpha(inputs[1]);
+
+ // PRelu options are empty
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CirclePow.cpp b/compiler/luci/import/src/Nodes/CirclePow.cpp
new file mode 100644
index 000000000..ff9833165
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CirclePow.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CirclePow.h"
+
+#include <luci/IR/Nodes/CirclePow.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CirclePowGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CirclePowGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CirclePow>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ // Pow options are empty
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleRange.cpp b/compiler/luci/import/src/Nodes/CircleRange.cpp
new file mode 100644
index 000000000..c21191605
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleRange.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleRange.h"
+
+#include <luci/IR/Nodes/CircleRange.h>
+
+#include <loco.h>
+
+namespace luci
+{
+bool CircleRangeGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 3)
+ return false;
+
+ // TODO Support type check
+ return true;
+}
+
+CircleNode *CircleRangeGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleRange>();
+ node->start(inputs[0]);
+ node->limit(inputs[1]);
+ node->delta(inputs[2]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleRank.cpp b/compiler/luci/import/src/Nodes/CircleRank.cpp
new file mode 100644
index 000000000..705ae0120
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleRank.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleRank.h"
+
+#include <luci/IR/Nodes/CircleRank.h>
+
+#include <loco.h>
+
+namespace luci
+{
+bool CircleRankGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleRankGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleRank>();
+ node->input(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleReduceAny.cpp b/compiler/luci/import/src/Nodes/CircleReduceAny.cpp
new file mode 100644
index 000000000..030c5304c
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleReduceAny.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleReduceAny.h"
+
+#include <luci/IR/Nodes/CircleReduceAny.h>
+
+namespace luci
+{
+
+bool CircleReduceAnyGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 2)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_0 = tensors.at(inputs[0]);
+ const auto &tensor_1 = tensors.at(inputs[1]);
+ const auto &tensor_o = tensors.at(outputs[0]);
+
+ if (tensor_0->type != circle::TensorType_BOOL)
+ return false;
+ if (tensor_o->type != circle::TensorType_BOOL)
+ return false;
+
+ switch (tensor_1->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleReduceAnyGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleReduceAny>();
+ node->input(inputs[0]);
+ node->reduction_indices(inputs[1]);
+
+ const auto *options = op.builtin_options.AsReducerOptions();
+ node->keep_dims(options->keep_dims);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleReduceMax.cpp b/compiler/luci/import/src/Nodes/CircleReduceMax.cpp
new file mode 100644
index 000000000..8ca8e2e34
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleReduceMax.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleReduceMax.h"
+
+#include <luci/IR/Nodes/CircleReduceMax.h>
+
+namespace luci
+{
+
+bool CircleReduceMaxGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_axis = tensors.at(inputs[1]);
+
+ switch (tensor_axis->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleReduceMaxGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleReduceMax>();
+ node->input(inputs[0]);
+ node->reduction_indices(inputs[1]);
+
+ const auto *options = op.builtin_options.AsReducerOptions();
+ node->keep_dims(options->keep_dims);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleReduceMin.cpp b/compiler/luci/import/src/Nodes/CircleReduceMin.cpp
new file mode 100644
index 000000000..3020c3778
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleReduceMin.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleReduceMin.h"
+
+#include <luci/IR/Nodes/CircleReduceMin.h>
+
+namespace luci
+{
+
+bool CircleReduceMinGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_axis = tensors.at(inputs[1]);
+
+ switch (tensor_axis->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleReduceMinGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleReduceMin>();
+ node->input(inputs[0]);
+ node->reduction_indices(inputs[1]);
+
+ const auto *options = op.builtin_options.AsReducerOptions();
+ node->keep_dims(options->keep_dims);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleReduceProd.cpp b/compiler/luci/import/src/Nodes/CircleReduceProd.cpp
new file mode 100644
index 000000000..2bb43f6ce
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleReduceProd.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleReduceProd.h"
+
+#include <luci/IR/Nodes/CircleReduceProd.h>
+
+namespace luci
+{
+
+bool CircleReduceProdGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 2)
+ return false;
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_1 = tensors.at(inputs[1]);
+
+ // TODO check input types
+
+ // Check for reduction_indices types
+ switch (tensor_1->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleReduceProdGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleReduceProd>();
+ node->input(inputs[0]);
+ node->reduction_indices(inputs[1]);
+
+ const auto *options = op.builtin_options.AsReducerOptions();
+ node->keep_dims(options->keep_dims);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleRelu6.cpp b/compiler/luci/import/src/Nodes/CircleRelu6.cpp
new file mode 100644
index 000000000..5b443993b
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleRelu6.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleRelu6.h"
+
+#include <luci/IR/Nodes/CircleRelu6.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleRelu6GraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleRelu6GraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleRelu6>();
+ node->features(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp b/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp
new file mode 100644
index 000000000..edf662fb9
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleReluN1To1.h"
+
+#include <luci/IR/Nodes/CircleReluN1To1.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleReluN1To1GraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ // TODO check dtypes
+
+ return true;
+}
+
+CircleNode *CircleReluN1To1GraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleReluN1To1>();
+ node->features(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleReshape.cpp b/compiler/luci/import/src/Nodes/CircleReshape.cpp
index c83f143a6..f72c152b1 100644
--- a/compiler/luci/import/src/Nodes/CircleReshape.cpp
+++ b/compiler/luci/import/src/Nodes/CircleReshape.cpp
@@ -66,7 +66,14 @@ CircleNode *CircleReshapeGraphBuilder::build_node(const circle::OperatorT &op,
if (shape_node == nullptr)
{
const auto *options = op.builtin_options.AsReshapeOptions();
- shape_node = create_shape_node(options->new_shape, graph);
+ if (options != nullptr)
+ shape_node = create_shape_node(options->new_shape, graph);
+ else
+ {
+ shape_node = graph->nodes()->create<CircleOutputDummy>();
+ shape_node->dtype(loco::DataType::S32);
+ shape_node->rank(0);
+ }
}
auto *node = graph->nodes()->create<CircleReshape>();
@@ -74,7 +81,8 @@ CircleNode *CircleReshapeGraphBuilder::build_node(const circle::OperatorT &op,
node->shape(shape_node);
const auto *options = op.builtin_options.AsReshapeOptions();
- setup_shape_attribute(options->new_shape, node);
+ if (options)
+ setup_shape_attribute(options->new_shape, node);
return node;
}
diff --git a/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp b/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp
new file mode 100644
index 000000000..6128f1b86
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleResizeBilinear.h"
+
+#include <luci/IR/Nodes/CircleConst.h>
+#include <luci/IR/Nodes/CircleResizeBilinear.h>
+
+namespace luci
+{
+
+bool CircleResizeBilinearGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleResizeBilinearGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleResizeBilinear>();
+ node->input(inputs[0]);
+ node->size(inputs[1]);
+
+ const auto *options = op.builtin_options.AsResizeBilinearOptions();
+ node->align_corners(options->align_corners);
+ node->half_pixel_centers(options->half_pixel_centers);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp b/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp
new file mode 100644
index 000000000..a1f1ef0ff
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleResizeNearestNeighbor.h"
+
+#include <luci/IR/Nodes/CircleConst.h>
+#include <luci/IR/Nodes/CircleResizeNearestNeighbor.h>
+
+namespace luci
+{
+
+bool CircleResizeNearestNeighborGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleResizeNearestNeighborGraphBuilder::build_node(
+ const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleResizeNearestNeighbor>();
+ node->input(inputs[0]);
+ node->size(inputs[1]);
+
+ const auto *options = op.builtin_options.AsResizeNearestNeighborOptions();
+ node->align_corners(options->align_corners);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp b/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp
new file mode 100644
index 000000000..72d3b153d
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleReverseSequence.h"
+
+#include <luci/IR/Nodes/CircleReverseSequence.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleReverseSequenceGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_in = tensors.at(inputs[0]);
+ const auto &tensor_lengths = tensors.at(inputs[1]);
+ const auto &tensor_out = tensors.at(outputs[0]);
+
+ switch (tensor_lengths->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensor_in->type != tensor_out->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleReverseSequenceGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleReverseSequence>();
+ node->input(inputs[0]);
+ node->seq_lengths(inputs[1]);
+
+ const auto *options = op.builtin_options.AsReverseSequenceOptions();
+ node->seq_axis(options->seq_dim);
+ node->batch_axis(options->batch_dim);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleReverseV2.cpp b/compiler/luci/import/src/Nodes/CircleReverseV2.cpp
new file mode 100644
index 000000000..cd18128a7
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleReverseV2.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleReverseV2.h"
+
+#include <luci/IR/Nodes/CircleReverseV2.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleReverseV2GraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_in = tensors.at(inputs[0]);
+ const auto &tensor_axis = tensors.at(inputs[1]);
+ const auto &tensor_out = tensors.at(outputs[0]);
+
+ switch (tensor_axis->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensor_out->type != tensor_in->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleReverseV2GraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleReverseV2>();
+ node->tensor(inputs[0]);
+ node->axis(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleRound.cpp b/compiler/luci/import/src/Nodes/CircleRound.cpp
new file mode 100644
index 000000000..896489521
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleRound.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleRound.h"
+
+#include <luci/IR/Nodes/CircleRound.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleRoundGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 1)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ // Must be one of the following types
+ // bfloat16, half (float16), float32, float64, complex64, complex128
+ // Currently, circle supports float16, float32, complex64
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_in = tensors.at(inputs[0]);
+ const auto &tensor_out = tensors.at(outputs[0]);
+
+ switch (tensor_in->type)
+ {
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensor_out->type != tensor_in->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleRoundGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleRound>();
+ node->x(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleScatterNd.cpp b/compiler/luci/import/src/Nodes/CircleScatterNd.cpp
new file mode 100644
index 000000000..adcaa0030
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleScatterNd.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 "luci/Import/Nodes/CircleScatterNd.h"
+
+#include <luci/IR/Nodes/CircleScatterNd.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleScatterNdGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 3)
+ return false;
+
+ // indices must have the same type as shape
+ const auto &tensors = args.reader.tensors();
+
+ if (tensors[inputs[0]]->type != tensors[inputs[2]]->type)
+ return false;
+
+ // indices must be either int32 or int64
+ if (tensors[inputs[0]]->type != circle::TensorType_INT32 &&
+ tensors[inputs[0]]->type != circle::TensorType_INT64)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleScatterNdGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleScatterNd>();
+ node->indices(inputs[0]);
+ node->updates(inputs[1]);
+ node->shape(inputs[2]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp b/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp
new file mode 100644
index 000000000..1122bdca3
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSegmentSum.h"
+
+#include <luci/IR/Nodes/CircleSegmentSum.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleSegmentSumGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 2)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_in = tensors.at(inputs[0]);
+ const auto &tensor_out = tensors.at(outputs[0]);
+ const auto &tensor_ids = tensors.at(inputs[1]);
+
+ switch (tensor_ids->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ if (tensor_out->type != tensor_in->type)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleSegmentSumGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSegmentSum>();
+ node->input(inputs[0]);
+ node->segment_ids(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSelect.cpp b/compiler/luci/import/src/Nodes/CircleSelect.cpp
new file mode 100644
index 000000000..ff94212c3
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSelect.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSelect.h"
+
+#include <luci/IR/Nodes/CircleSelect.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleSelectGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 3)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ if (tensor->type != circle::TensorType_BOOL)
+ return false;
+ // TODO check dtypes for input 1, 2
+
+ return true;
+}
+
+CircleNode *CircleSelectGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSelect>();
+ node->condition(inputs[0]);
+ node->t(inputs[1]);
+ node->e(inputs[2]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSelectV2.cpp b/compiler/luci/import/src/Nodes/CircleSelectV2.cpp
new file mode 100644
index 000000000..78b2e6459
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSelectV2.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSelectV2.h"
+
+#include <luci/IR/Nodes/CircleSelectV2.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleSelectV2GraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 3)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &condition = tensors.at(inputs[0]);
+ if (condition->type != circle::TensorType_BOOL)
+ return false;
+
+ const auto &t = tensors.at(inputs[1]);
+ const auto &e = tensors.at(inputs[2]);
+ if (t->type != e->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleSelectV2GraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSelectV2>();
+ node->condition(inputs[0]);
+ node->t(inputs[1]);
+ node->e(inputs[2]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleShape.cpp b/compiler/luci/import/src/Nodes/CircleShape.cpp
new file mode 100644
index 000000000..864b5eb51
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleShape.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleShape.h"
+
+#include <luci/IR/Nodes/CircleShape.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleShapeGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ if (inputs.size() != 1)
+ return false;
+ if (outputs.size() != 1)
+ return false;
+
+ // TODO check shape, dtype
+
+ return true;
+}
+
+CircleNode *CircleShapeGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleShape>();
+ node->input(inputs[0]);
+
+ const auto *options = op.builtin_options.AsShapeOptions();
+ node->out_type(luci_datatype(options->out_type));
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSin.cpp b/compiler/luci/import/src/Nodes/CircleSin.cpp
new file mode 100644
index 000000000..61d60c78f
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSin.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSin.h"
+
+#include <luci/IR/Nodes/CircleSin.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleSinGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 1)
+ return false;
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ // input type check
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ break;
+ // TODO support TensorType_COMPLEX64, complex128, bfloat16
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleSinGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSin>();
+ node->x(inputs[0]);
+
+ // No options for Sin
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSlice.cpp b/compiler/luci/import/src/Nodes/CircleSlice.cpp
new file mode 100644
index 000000000..313c35599
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSlice.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSlice.h"
+
+#include <luci/IR/Nodes/CircleSlice.h>
+
+#include <loco.h>
+
+#include <cassert>
+
+namespace luci
+{
+
+bool CircleSliceGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 3)
+ return false;
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ // TODO check shapes and types
+
+ return true;
+}
+
+CircleNode *CircleSliceGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSlice>();
+ node->input(inputs[0]);
+ node->begin(inputs[1]);
+ node->size(inputs[2]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp b/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp
new file mode 100644
index 000000000..f1361fb11
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSpaceToBatchND.h"
+
+#include <luci/IR/Nodes/CircleSpaceToBatchND.h>
+
+#include <loco.h>
+
+#include <cassert>
+
+namespace luci
+{
+
+bool CircleSpaceToBatchNDGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 3)
+ return false;
+
+ // input 1 and 2 should have INT32/INT64 type
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_1 = tensors.at(inputs[1]);
+ switch (tensor_1->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+ const auto &tensor_2 = tensors.at(inputs[2]);
+ switch (tensor_2->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ // Only support input shape dimension 3 and 4 only
+ const auto &tensor_0 = tensors.at(inputs[0]);
+ const auto t_0_s = tensor_0->shape.size();
+ if (t_0_s != 3 && t_0_s != 4)
+ return false;
+
+ // TODO check input shape
+
+ return true;
+}
+
+CircleNode *CircleSpaceToBatchNDGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSpaceToBatchND>();
+ node->input(inputs[0]);
+ node->block_shape(inputs[1]);
+ node->paddings(inputs[2]);
+
+ // No options for SpaceToBatchND
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp b/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp
new file mode 100644
index 000000000..b612c9a9a
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSpaceToDepth.h"
+
+#include <luci/IR/Nodes/CircleSpaceToDepth.h>
+
+#include <loco.h>
+
+#include <cassert>
+
+namespace luci
+{
+
+bool CircleSpaceToDepthGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 1)
+ return false;
+
+ // TODO do attribute checks
+
+ return true;
+}
+
+CircleNode *CircleSpaceToDepthGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSpaceToDepth>();
+ node->input(inputs[0]);
+
+ const auto *options = op.builtin_options.AsSpaceToDepthOptions();
+ node->block_size(options->block_size);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp b/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp
new file mode 100644
index 000000000..bfe790fc1
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSparseToDense.h"
+
+#include <luci/IR/Nodes/CircleSparseToDense.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleSparseToDenseGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 4)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleSparseToDenseGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSparseToDense>();
+ node->indices(inputs[0]);
+ node->output_shape(inputs[1]);
+ node->values(inputs[2]);
+ node->default_value(inputs[3]);
+
+ const auto *options = op.builtin_options.AsSparseToDenseOptions();
+ node->validate_indices(options->validate_indices);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSplit.cpp b/compiler/luci/import/src/Nodes/CircleSplit.cpp
new file mode 100644
index 000000000..07b6cc939
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSplit.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSplit.h"
+
+#include <luci/IR/Nodes/CircleSplit.h>
+#include <luci/IR/Nodes/CircleSplitOut.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+bool CircleSplitGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ const auto *options = args.op.builtin_options.AsSplitOptions();
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (static_cast<int32_t>(outputs.size()) != options->num_splits)
+ return false;
+
+ // TODO check types
+
+ return true;
+}
+
+/**
+ * @brief Split Node builder
+ *
+ * @note Current loco does not provide multiple outputs
+ * We will create multiple CircleSplitOut nodes to emulate this
+ * For two outputs that may look like this
+ *
+ * --- CircleSplit --- FullyConnected ---
+ * \- FullyConnected ---
+ *
+ * will be created like this
+ *
+ * --- CircleSplit --- CircleSplitOut --- FullyConnected ---
+ * \- CircleSplitOut --- FullyConnected ---
+ */
+
+void CircleSplitGraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+
+ const std::vector<int32_t> &inputs = op.inputs;
+ const std::vector<int32_t> &outputs = op.outputs;
+ const auto &tensors = context->reader()->tensors();
+ const auto &opcodes = context->reader()->opcodes();
+ auto tensors_ptr = context->reader()->tensors_ptr();
+ assert(tensors_ptr != nullptr);
+
+ std::vector<CircleNode *> input_nodes;
+ for (const int32_t input_tensor_index : inputs)
+ {
+ input_nodes.push_back(context->nodefinder()->node(input_tensor_index));
+ }
+
+ // Create CircleSplit
+ auto node = graph->nodes()->create<CircleSplit>();
+ node->split_dim(input_nodes[0]);
+ node->input(input_nodes[1]);
+
+ const auto *options = op.builtin_options.AsSplitOptions();
+ node->num_split(options->num_splits);
+
+ assert(outputs.size() > 0);
+ assert(int32_t(outputs.size()) == options->num_splits);
+ {
+ // Let's use name of output 0 as Split name
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ node->name(tensor_name(output_tensor));
+ node->op_version(opcodes[op.opcode_index].get()->version);
+
+ // NOTE We don't set quantization for Split itself but to virtual outputs
+ }
+
+ // Create virtual outputs of Split
+ for (int32_t n = 0; n < options->num_splits; ++n)
+ {
+ const circle::TensorT &output_tensor = *tensors[outputs[n]];
+
+ auto *nodeout = graph->nodes()->create<CircleSplitOut>();
+ copy_tensor_attributes(output_tensor, nodeout);
+ // mark shape_status
+ if (tensors_ptr->Get(outputs[n])->shape() == nullptr)
+ nodeout->shape_status(ShapeStatus::NOSHAPE);
+ else
+ nodeout->shape_status(ShapeStatus::VALID);
+
+ nodeout->input(node);
+ nodeout->index(n);
+
+ context->nodefinder()->enroll(outputs[n], nodeout);
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSplitV.cpp b/compiler/luci/import/src/Nodes/CircleSplitV.cpp
new file mode 100644
index 000000000..7c6e83e17
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSplitV.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSplitV.h"
+
+#include <luci/IR/Nodes/CircleSplitV.h>
+#include <luci/IR/Nodes/CircleSplitVOut.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+bool CircleSplitVGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ const auto *options = args.op.builtin_options.AsSplitVOptions();
+
+ if (inputs.size() != 3)
+ return false;
+
+ if (static_cast<int32_t>(outputs.size()) != options->num_splits)
+ return false;
+
+ // TODO check types
+
+ return true;
+}
+
+/**
+ * @brief SplitV Node builder
+ *
+ * @note Current loco does not provide multiple outputs
+ * We will create multiple CircleSplitVOut nodes to emulate this
+ * For two outputs that may look like this
+ *
+ * --- CircleSplitV --- FullyConnected ---
+ * \- FullyConnected ---
+ *
+ * will be created like this
+ *
+ * --- CircleSplitV --- CircleSplitVOut --- FullyConnected ---
+ * \- CircleSplitVOut --- FullyConnected ---
+ */
+
+void CircleSplitVGraphBuilder::build(const circle::OperatorT &op,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+
+ const std::vector<int32_t> &inputs = op.inputs;
+ const std::vector<int32_t> &outputs = op.outputs;
+ const auto &tensors = context->reader()->tensors();
+ const auto &opcodes = context->reader()->opcodes();
+ auto tensors_ptr = context->reader()->tensors_ptr();
+ assert(tensors_ptr != nullptr);
+
+ std::vector<CircleNode *> input_nodes;
+ for (const int32_t input_tensor_index : inputs)
+ {
+ input_nodes.push_back(context->nodefinder()->node(input_tensor_index));
+ }
+
+ // Create CircleSplitV
+ auto node = graph->nodes()->create<CircleSplitV>();
+ node->input(input_nodes[0]);
+ node->size_splits(input_nodes[1]);
+ node->split_dim(input_nodes[2]);
+
+ const auto *options = op.builtin_options.AsSplitVOptions();
+ node->num_split(options->num_splits);
+
+ assert(outputs.size() > 0);
+ assert(int32_t(outputs.size()) == options->num_splits);
+ {
+ // Let's use name of output 0 as Split name
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ node->name(tensor_name(output_tensor));
+ node->op_version(opcodes[op.opcode_index].get()->version);
+
+ // NOTE We don't set quantization for Split itself but to virtual outputs
+ }
+
+ // Create virtual outputs of Split
+ for (int32_t n = 0; n < options->num_splits; ++n)
+ {
+ const circle::TensorT &output_tensor = *tensors[outputs[n]];
+
+ auto *nodeout = graph->nodes()->create<CircleSplitVOut>();
+ copy_tensor_attributes(output_tensor, nodeout);
+ // mark shape_status
+ if (tensors_ptr->Get(outputs[n])->shape() == nullptr)
+ nodeout->shape_status(ShapeStatus::NOSHAPE);
+ else
+ nodeout->shape_status(ShapeStatus::VALID);
+
+ nodeout->input(node);
+ nodeout->index(n);
+
+ context->nodefinder()->enroll(outputs[n], nodeout);
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSqrt.cpp b/compiler/luci/import/src/Nodes/CircleSqrt.cpp
new file mode 100644
index 000000000..8a90f6691
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSqrt.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSqrt.h"
+
+#include <luci/IR/Nodes/CircleSqrt.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleSqrtGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleSqrtGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSqrt>();
+ node->x(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSquare.cpp b/compiler/luci/import/src/Nodes/CircleSquare.cpp
new file mode 100644
index 000000000..8398548b6
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSquare.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSquare.h"
+
+#include <luci/IR/Nodes/CircleSquare.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleSquareGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 1)
+ return false;
+
+ // Must be one of the following types
+ // bfloat16, half (float16), float32, float64, complex64, complex128
+ // Currently, circle supports float16, float32, complex64
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ switch (tensor->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ case circle::TensorType_COMPLEX64:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleSquareGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSquare>();
+ node->x(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp b/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp
new file mode 100644
index 000000000..93ce959e2
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSquaredDifference.h"
+
+#include <luci/IR/Nodes/CircleSquaredDifference.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleSquaredDifferenceGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ // Inputs must be one of the following types
+ // bfloat16, half(float16), float32, float64, int32, int64, complex64, complex128
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_FLOAT64:
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ case circle::TensorType_COMPLEX64:
+ break;
+ // TODO support bfloat16, complex128
+ default:
+ return false;
+ }
+
+ // Input types must match
+ if (tensors.at(inputs[0])->type != tensors.at(inputs[1])->type)
+ return false;
+
+ // Input and output types must match
+ if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleSquaredDifferenceGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSquaredDifference>();
+ node->x(inputs[0]);
+ node->y(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSqueeze.cpp b/compiler/luci/import/src/Nodes/CircleSqueeze.cpp
new file mode 100644
index 000000000..a5252d0bb
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSqueeze.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSqueeze.h"
+
+#include <luci/IR/Nodes/CircleConst.h>
+#include <luci/IR/Nodes/CircleSqueeze.h>
+
+namespace luci
+{
+
+bool CircleSqueezeGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleSqueezeGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSqueeze>();
+ node->input(inputs[0]);
+
+ const auto *options = op.builtin_options.AsSqueezeOptions();
+ assert(options);
+
+ node->squeeze_dims(options->squeeze_dims);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp b/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp
new file mode 100644
index 000000000..95e446704
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleStridedSlice.h"
+
+#include <luci/IR/Nodes/CircleStridedSlice.h>
+
+#include <loco.h>
+
+#include <cassert>
+
+namespace luci
+{
+
+bool CircleStridedSliceGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 4)
+ return false;
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ // TODO check shapes and types
+
+ return true;
+}
+
+CircleNode *CircleStridedSliceGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleStridedSlice>();
+ node->input(inputs[0]);
+ node->begin(inputs[1]);
+ node->end(inputs[2]);
+ node->strides(inputs[3]);
+
+ const auto *options = op.builtin_options.AsStridedSliceOptions();
+ node->begin_mask(options->begin_mask);
+ node->end_mask(options->end_mask);
+ node->ellipsis_mask(options->ellipsis_mask);
+ node->new_axis_mask(options->new_axis_mask);
+ node->shrink_axis_mask(options->shrink_axis_mask);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleSum.cpp b/compiler/luci/import/src/Nodes/CircleSum.cpp
new file mode 100644
index 000000000..b4865de59
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleSum.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleSum.h"
+
+#include <luci/IR/Nodes/CircleSum.h>
+
+namespace luci
+{
+
+bool CircleSumGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 2)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleSumGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleSum>();
+ node->input(inputs[0]);
+ node->reduction_indices(inputs[1]);
+
+ const auto *options = op.builtin_options.AsReducerOptions();
+ node->keep_dims(options->keep_dims);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleTanh.cpp b/compiler/luci/import/src/Nodes/CircleTanh.cpp
new file mode 100644
index 000000000..8986378c4
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleTanh.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleTanh.h"
+
+#include <luci/IR/Nodes/CircleTanh.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleTanhGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ if (inputs.size() != 1)
+ return false;
+
+ // Must be one of the following types
+ // bfloat16, half (float16), float32, float64, complex64, complex128
+ // Currently, circle supports float16, float32, complex64
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ switch (tensor->type)
+ {
+ case circle::TensorType_FLOAT16:
+ case circle::TensorType_FLOAT32:
+ case circle::TensorType_COMPLEX64:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+CircleNode *CircleTanhGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleTanh>();
+ node->x(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleTile.cpp b/compiler/luci/import/src/Nodes/CircleTile.cpp
new file mode 100644
index 000000000..91054ce7f
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleTile.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleTile.h"
+
+#include <luci/IR/Nodes/CircleTile.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleTileGraphBuilder::validate(const ValidateArgs &args) const
+{
+ auto inputs = args.op.inputs;
+ auto outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ // Multiples (inputs[1]) must be one of the following types
+ // int32, int64
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[1]);
+ switch (tensor->type)
+ {
+ case circle::TensorType_INT32:
+ case circle::TensorType_INT64:
+ break;
+ default:
+ return false;
+ }
+
+ // Type of input and output must be the same
+ if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleTileGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleTile>();
+ node->input(inputs[0]);
+ node->multiples(inputs[1]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleTopKV2.cpp b/compiler/luci/import/src/Nodes/CircleTopKV2.cpp
new file mode 100644
index 000000000..5c1051c43
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleTopKV2.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleTopKV2.h"
+
+#include <luci/IR/Nodes/CircleTopKV2.h>
+#include <luci/IR/Nodes/CircleTopKV2Out.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+bool CircleTopKV2GraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 2)
+ return false;
+ if (outputs.size() != 2)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[1]);
+ if (tensor->type != circle::TensorType_INT32)
+ return false;
+
+ return true;
+}
+
+/**
+ * @brief TopKV2 Node builder
+ *
+ * @note Current loco does not provide multiple outputs
+ * We will create multiple CircleTopKV2Out nodes to emulate this
+ * For two outputs that may look like this
+ *
+ * --- CircleTopKV2--- FullyConnected ---
+ * \- FullyConnected ---
+ *
+ * will be created like this
+ *
+ * --- CircleTopKV2 --- CircleTopKV2Out --- FullyConnected ---
+ * \- CircleTopKV2Out --- FullyConnected ---
+ */
+
+void CircleTopKV2GraphBuilder::build(const circle::OperatorT &op,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+
+ const std::vector<int32_t> &inputs = op.inputs;
+ const std::vector<int32_t> &outputs = op.outputs;
+ const auto &tensors = context->reader()->tensors();
+ const auto &opcodes = context->reader()->opcodes();
+ auto tensors_ptr = context->reader()->tensors_ptr();
+ assert(tensors_ptr != nullptr);
+
+ std::vector<CircleNode *> input_nodes;
+ for (const int32_t input_tensor_index : inputs)
+ {
+ input_nodes.push_back(context->nodefinder()->node(input_tensor_index));
+ }
+
+ // Create CircleTopKV2
+ auto node = graph->nodes()->create<CircleTopKV2>();
+ node->input(input_nodes[0]);
+ node->k(input_nodes[1]);
+
+ assert(outputs.size() == 2);
+ {
+ // Let's use name of output 0 as TopKV2 name
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ node->name(tensor_name(output_tensor));
+ node->op_version(opcodes[op.opcode_index].get()->version);
+
+ // NOTE We don't set quantization for TopKV2 itself but to virtual outputs
+ }
+
+ // Create virtual outputs of TopKV2
+ for (size_t n = 0; n < outputs.size(); ++n)
+ {
+ const circle::TensorT &output_tensor = *tensors[outputs[n]];
+
+ auto *nodeout = graph->nodes()->create<CircleTopKV2Out>();
+ copy_tensor_attributes(output_tensor, nodeout);
+ // mark shape_status
+ if (tensors_ptr->Get(outputs[n])->shape() == nullptr)
+ nodeout->shape_status(ShapeStatus::NOSHAPE);
+ else
+ nodeout->shape_status(ShapeStatus::VALID);
+
+ nodeout->input(node);
+ nodeout->index(n);
+
+ context->nodefinder()->enroll(outputs[n], nodeout);
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp b/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp
new file mode 100644
index 000000000..7bdf46daa
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleTransposeConv.h"
+
+#include <luci/IR/Nodes/CircleTransposeConv.h>
+
+#include <loco.h>
+
+#include <cassert>
+
+namespace luci
+{
+
+bool CircleTransposeConvGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 3)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleTransposeConvGraphBuilder::build_node(const circle::OperatorT &op,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleTransposeConv>();
+
+ node->inputSizes(inputs[0]);
+ node->filter(inputs[1]);
+ node->outBackprop(inputs[2]);
+
+ const auto *options = op.builtin_options.AsTransposeConvOptions();
+ node->padding(luci_padding(options->padding));
+ node->stride()->w(options->stride_w);
+ node->stride()->h(options->stride_h);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleUnpack.cpp b/compiler/luci/import/src/Nodes/CircleUnpack.cpp
new file mode 100644
index 000000000..c4282e24f
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleUnpack.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleUnpack.h"
+
+#include <luci/IR/Nodes/CircleUnpack.h>
+#include <luci/IR/Nodes/CircleUnpackOut.h>
+
+#include <luci/UserSettings.h>
+#include <luci/Log.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+bool CircleUnpackGraphBuilder::validate(const ValidateArgs &args) const
+{
+ LOGGER(l);
+
+ auto settings = luci::UserSettings::settings();
+
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+ const auto *options = args.op.builtin_options.AsUnpackOptions();
+
+ if (inputs.size() != 1)
+ return false;
+
+ // NOTE real models may have mismatch
+ if (static_cast<int32_t>(outputs.size()) != options->num)
+ {
+ if (settings->get(luci::UserSettings::Key::DisableValidation))
+ {
+ const auto &tensors = args.reader.tensors();
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ auto name = tensor_name(output_tensor);
+ WARN(l) << "Warning: import Unpack(" << name << ") 'num' is not same as outputs used";
+ }
+ else
+ return false;
+ }
+
+ if (options->num < 0)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor = tensors.at(inputs[0]);
+ const auto &shape = tensor->shape;
+ auto shape_size = static_cast<int32_t>(shape.size());
+ if (shape_size > 0)
+ {
+ // NOTE for unknown shape, shape_size is 0
+ if (options->axis < -shape_size || options->axis >= shape_size)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * @brief Unpack Node builder
+ *
+ * @note Current loco does not provide multiple outputs
+ * We will create multiple CircleUnpackOut nodes to emulate this
+ * For two outputs that may look like this
+ *
+ * --- CircleUnpack --- FullyConnected ---
+ * \- FullyConnected ---
+ *
+ * will be created like this
+ *
+ * --- CircleUnpack --- CircleUnpackOut --- FullyConnected ---
+ * \- CircleUnpackOut --- FullyConnected ---
+ */
+
+void CircleUnpackGraphBuilder::build(const circle::OperatorT &op,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+
+ const std::vector<int32_t> &inputs = op.inputs;
+ const std::vector<int32_t> &outputs = op.outputs;
+ const auto &tensors = context->reader()->tensors();
+ const auto &opcodes = context->reader()->opcodes();
+ auto tensors_ptr = context->reader()->tensors_ptr();
+ assert(tensors_ptr != nullptr);
+
+ // NOTE Unpack has only one input so running a loop is not necessary
+ // This is provided as a reference for other Ops as a reference
+ std::vector<CircleNode *> input_nodes;
+ for (const int32_t input_tensor_index : inputs)
+ {
+ input_nodes.push_back(context->nodefinder()->node(input_tensor_index));
+ }
+
+ // Create CircleUnpack
+ CircleUnpack *node = graph->nodes()->create<CircleUnpack>();
+ node->value(input_nodes[0]);
+
+ const auto *options = op.builtin_options.AsUnpackOptions();
+ node->num(options->num);
+ node->axis(options->axis);
+
+ assert(outputs.size() > 0);
+ {
+ // Let's use name of output 0 as Unpack name
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ node->name(tensor_name(output_tensor));
+ node->op_version(opcodes[op.opcode_index].get()->version);
+
+ // NOTE We don't set quantization for Unpack itself but to virtual outputs
+ }
+
+ // Create virtual outputs of Unpack
+ for (int32_t n = 0; n < options->num; ++n)
+ {
+ const circle::TensorT &output_tensor = *tensors[outputs[n]];
+
+ auto *nodeout = graph->nodes()->create<CircleUnpackOut>();
+ copy_tensor_attributes(output_tensor, nodeout);
+ // mark shape_status
+ if (tensors_ptr->Get(outputs[n])->shape() == nullptr)
+ nodeout->shape_status(ShapeStatus::NOSHAPE);
+ else
+ nodeout->shape_status(ShapeStatus::VALID);
+
+ nodeout->input(node);
+ nodeout->index(n);
+
+ context->nodefinder()->enroll(outputs[n], nodeout);
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleWhere.cpp b/compiler/luci/import/src/Nodes/CircleWhere.cpp
new file mode 100644
index 000000000..a13c4d6c9
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleWhere.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleWhere.h"
+
+#include <luci/IR/Nodes/CircleWhere.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleWhereGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto &outputs = args.op.outputs;
+
+ if (inputs.size() != 1)
+ return false;
+
+ if (outputs.size() != 1)
+ return false;
+
+ const auto &tensors = args.reader.tensors();
+ const auto &tensor_condition = tensors.at(inputs[0]);
+ const auto &tensor_out = tensors.at(outputs[0]);
+
+ if (tensor_condition->type != circle::TensorType_BOOL)
+ return false;
+
+ if (tensor_out->type != circle::TensorType_INT64)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleWhereGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleWhere>();
+ node->condition(inputs[0]);
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleWhile.cpp b/compiler/luci/import/src/Nodes/CircleWhile.cpp
new file mode 100644
index 000000000..aead25071
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleWhile.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleWhile.h"
+
+#include <luci/IR/Nodes/CircleWhile.h>
+#include <luci/IR/Nodes/CircleWhileOut.h>
+
+#include <loco.h>
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+bool CircleWhileGraphBuilder::validate(const ValidateArgs &args) const
+{
+ const auto &inputs = args.op.inputs;
+ const auto *options = args.op.builtin_options.AsWhileOptions();
+
+ if (inputs.size() != args.op.outputs.size())
+ return false;
+
+ auto num_graphs = static_cast<int32_t>(args.reader.num_subgraph());
+ if (options->cond_subgraph_index >= num_graphs)
+ return false;
+ if (options->body_subgraph_index >= num_graphs)
+ return false;
+
+ return true;
+}
+
+/**
+ * @brief While Node builder
+ *
+ * @note Current loco does not provide multiple outputs
+ * We will create multiple CircleWhileOut nodes to emulate this
+ * For two outputs that may look like this
+ *
+ * --- CircleWhile --- Node ---
+ * \- Node ---
+ *
+ * will be created like this
+ *
+ * --- CircleWhile --- CircleWhileOut --- Node ---
+ * \- CircleWhileOut --- Node ---
+ */
+
+void CircleWhileGraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+
+ const std::vector<int32_t> &inputs = op.inputs;
+ const std::vector<int32_t> &outputs = op.outputs;
+ const auto &tensors = context->reader()->tensors();
+ const auto &opcodes = context->reader()->opcodes();
+
+ std::vector<CircleNode *> input_nodes;
+ for (const int32_t input_tensor_index : inputs)
+ {
+ auto input_node = context->nodefinder()->node(input_tensor_index);
+ assert(input_node != nullptr);
+ input_nodes.push_back(input_node);
+ }
+
+ uint32_t input_count = inputs.size();
+ uint32_t output_count = outputs.size();
+
+ // Create CircleWhile
+ CircleWhile *node = graph->nodes()->create<CircleWhile>(input_count, output_count);
+
+ for (uint32_t idx = 0; idx < input_count; ++idx)
+ {
+ node->input(idx, input_nodes[idx]);
+ }
+
+ const auto *options = op.builtin_options.AsWhileOptions();
+ node->cond_branch(options->cond_subgraph_index);
+ node->body_branch(options->body_subgraph_index);
+
+ assert(outputs.size() > 0);
+ {
+ // Lets use name of output 0 as While name
+ const circle::TensorT &output_tensor = *tensors[outputs[0]];
+ node->name(tensor_name(output_tensor));
+ node->op_version(opcodes[op.opcode_index].get()->version);
+
+ // NOTE We don't set quantization for While itself but to virtual outputs
+ }
+
+ // Create virtual outputs of While
+ for (uint32_t n = 0; n < output_count; ++n)
+ {
+ const circle::TensorT &output_tensor = *tensors[outputs[n]];
+
+ auto *nodeout = graph->nodes()->create<CircleWhileOut>();
+
+ nodeout->input(node);
+ nodeout->index(n);
+
+ copy_tensor_attributes(output_tensor, nodeout);
+
+ // Note: leave shape_status to UNKNOWN to run shape inference
+
+ context->nodefinder()->enroll(outputs[n], nodeout);
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/Nodes/CircleZerosLike.cpp b/compiler/luci/import/src/Nodes/CircleZerosLike.cpp
new file mode 100644
index 000000000..4362925cd
--- /dev/null
+++ b/compiler/luci/import/src/Nodes/CircleZerosLike.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Import/Nodes/CircleZerosLike.h"
+
+#include <luci/IR/Nodes/CircleZerosLike.h>
+
+#include <loco.h>
+
+namespace luci
+{
+
+bool CircleZerosLikeGraphBuilder::validate(const ValidateArgs &args) const
+{
+ if (args.op.inputs.size() != 1)
+ return false;
+
+ if (args.op.outputs.size() != 1)
+ return false;
+
+ return true;
+}
+
+CircleNode *CircleZerosLikeGraphBuilder::build_node(const circle::OperatorT &,
+ const std::vector<CircleNode *> &inputs,
+ loco::Graph *graph) const
+{
+ auto *node = graph->nodes()->create<CircleZerosLike>();
+ node->input(inputs[0]);
+
+ // ZerosLikeOptinos are empty
+
+ return node;
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/PostImport.cpp b/compiler/luci/import/src/PostImport.cpp
new file mode 100644
index 000000000..f436b48e8
--- /dev/null
+++ b/compiler/luci/import/src/PostImport.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PostImport.h"
+
+#include "luci/Import/CircleReader.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/IR/CircleDialect.h>
+#include <luci/IR/CircleNodeVisitor.h>
+#include <luci/Log.h>
+
+#include <loco.h>
+#include <oops/InternalExn.h>
+
+namespace
+{
+
+/**
+ * @brief FixInterGraphNodes will fix inter graph connections for each Nodes
+ */
+class FixInterGraphNodes final : public luci::CircleNodeMutableVisitor<void>
+{
+public:
+ FixInterGraphNodes(const luci::Module *m, const luci::CircleReader &r) : _module(m), _reader(r) {}
+
+ /**
+ * @note This will set Graph* to every CircleIf nodes 'else' and 'then'
+ */
+ void visit(luci::CircleIf *node) final
+ {
+ LOGGER(l);
+ INFO(l) << "CircleIf " << node->name() << std::endl;
+
+ auto then_branch = node->then_branch();
+ auto else_branch = node->else_branch();
+ auto num_graphs = static_cast<int32_t>(_module->size());
+ (void)num_graphs;
+
+ assert(num_graphs > 0);
+ assert(then_branch >= 0 && then_branch < num_graphs);
+ assert(else_branch >= 0 && else_branch < num_graphs);
+
+ auto then_graph = _module->graph(then_branch);
+ auto else_graph = _module->graph(else_branch);
+ assert(then_graph != nullptr);
+ assert(else_graph != nullptr);
+
+ node->then_graph(then_graph);
+ node->else_graph(else_graph);
+ }
+
+ void visit(luci::CircleWhile *node) final
+ {
+ LOGGER(l);
+ INFO(l) << "CircleWhile " << node->name() << std::endl;
+
+ auto cond_branch = node->cond_branch();
+ auto body_branch = node->body_branch();
+ auto num_graphs = static_cast<int32_t>(_module->size());
+ (void)num_graphs;
+
+ assert(num_graphs > 0);
+ assert(cond_branch >= 0 && cond_branch < num_graphs);
+ assert(body_branch >= 0 && body_branch < num_graphs);
+
+ auto cond_graph = _module->graph(cond_branch);
+ auto body_graph = _module->graph(body_branch);
+ assert(cond_graph != nullptr);
+ assert(body_graph != nullptr);
+
+ node->cond_graph(cond_graph);
+ node->body_graph(body_graph);
+ }
+
+ void visit(luci::CircleNode *) final
+ {
+ // DO NOTHING
+ }
+
+private:
+ const luci::Module *_module;
+ const luci::CircleReader &_reader;
+};
+
+/**
+ * @brief FixInterGraph will fix inter graph connections
+ */
+class FixInterGraph final
+{
+public:
+ void run(loco::Graph *g, const luci::Module *m, const luci::CircleReader &r)
+ {
+ for (auto node : loco::postorder_traversal(loco::output_nodes(g)))
+ {
+ if (recognize(node->dialect()))
+ {
+ auto cn = loco::must_cast<luci::CircleNode *>(node);
+
+ fix(cn, m, r);
+ }
+ }
+ }
+
+private:
+ bool recognize(const loco::Dialect *dialect) { return (dialect == luci::CircleDialect::get()); }
+
+ void fix(luci::CircleNode *node, const luci::Module *module, const luci::CircleReader &reader)
+ {
+ FixInterGraphNodes fix(module, reader);
+ node->accept(&fix);
+ }
+};
+
+} // namespace
+
+namespace
+{
+/**
+ * @brief ValidateNodeProp will validate inter graph connections for each Nodes
+ */
+class ValidateNodeProp final : public luci::CircleNodeMutableVisitor<void>
+{
+public:
+ ValidateNodeProp(const luci::Module *m, const luci::CircleReader &r) : _module(m), _reader(r) {}
+
+ /**
+ * @note Validate CircleIf node 'else' and 'then' graph input/output count
+ * shape and type
+ */
+ void visit(luci::CircleIf *node) final
+ {
+ LOGGER(l);
+ INFO(l) << "CircleIf " << node->name() << std::endl;
+
+ auto then_graph = node->then_graph();
+ auto else_graph = node->else_graph();
+ assert(then_graph != nullptr);
+ assert(else_graph != nullptr);
+
+ // TODO support for differnt shape; but how?
+ // NODE Shape/Type inference assume below conditions
+
+ // Check both "then" and "else" subgraph outputs are same in count
+ auto then_outputs = loco::output_nodes(then_graph); // CircleOutput nodes
+ auto else_outputs = loco::output_nodes(else_graph);
+ if (then_outputs.size() != else_outputs.size())
+ {
+ INTERNAL_EXN("CircleIf THEN and ELSE Graph are not same in size");
+ }
+
+ // check outputs have same shape and dtype
+ auto then_graph_outputs = then_graph->outputs(); // loco::GraphOutput items
+ auto else_graph_outputs = else_graph->outputs();
+ for (size_t idx = 0; idx < then_outputs.size(); ++idx)
+ {
+ auto then_out = loco::must_cast<luci::CircleOutput *>(then_outputs.at(idx));
+ auto else_out = loco::must_cast<luci::CircleOutput *>(else_outputs.at(idx));
+
+ auto then_graph_output = then_graph_outputs->at(then_out->index());
+ auto else_graph_output = else_graph_outputs->at(else_out->index());
+ if (!(*then_graph_output->shape() == *else_graph_output->shape()))
+ {
+ INTERNAL_EXN_V("CircleIf THEN and ELSE Graph Output shape mismatch ", idx);
+ }
+ if (then_graph_output->dtype() != else_graph_output->dtype())
+ {
+ INTERNAL_EXN_V("CircleIf THEN and ELSE Graph Output type mismatch ", idx);
+ }
+ }
+ }
+
+ /**
+ * @note Validate CircleWhile node 'cond' and 'body' graph input/output count
+ * shape and type
+ */
+ void visit(luci::CircleWhile *node) final
+ {
+ LOGGER(l);
+ INFO(l) << "CircleWhile " << node->name() << std::endl;
+
+ auto cond_graph = node->cond_graph();
+ auto body_graph = node->body_graph();
+ assert(cond_graph != nullptr);
+ assert(body_graph != nullptr);
+
+ // Check input of "cond" and input/output of "body" subgraph have the same size
+ auto cond_inputs = loco::input_nodes(cond_graph);
+ auto cond_outputs = loco::output_nodes(cond_graph);
+ auto body_inputs = loco::input_nodes(body_graph);
+ auto body_outputs = loco::output_nodes(body_graph);
+ if (cond_inputs.size() != body_outputs.size())
+ {
+ INTERNAL_EXN("CircleWhile COND input and BODY output have different sizes");
+ }
+ if (cond_inputs.size() != body_inputs.size())
+ {
+ INTERNAL_EXN("CircleWhile COND input and BODY input have different sizes");
+ }
+ if (cond_outputs.size() != 1)
+ {
+ INTERNAL_EXN("CircleWhile COND output must have size 1");
+ }
+ auto cond_out = loco::must_cast<luci::CircleOutput *>(cond_outputs.at(0));
+ if (cond_out->dtype() != loco::DataType::BOOL)
+ {
+ INTERNAL_EXN("CircleWhile COND output must have bool type");
+ }
+
+ // input of "cond" and input/output of "body" subgraph must have the same shape and type
+ // First we compare input of "cond" with input of "body"
+ auto cond_graph_inputs = cond_graph->inputs();
+ auto body_graph_inputs = body_graph->inputs();
+ for (size_t idx = 0; idx < cond_inputs.size(); ++idx)
+ {
+ auto cond_in = loco::must_cast<luci::CircleInput *>(cond_inputs.at(idx));
+ auto body_in = loco::must_cast<luci::CircleInput *>(body_inputs.at(idx));
+
+ auto cond_graph_input = cond_graph_inputs->at(cond_in->index());
+ auto body_graph_input = body_graph_inputs->at(body_in->index());
+ if ((cond_in->rank() != body_in->rank()))
+ {
+ INTERNAL_EXN_V("CircleWhile COND input and BODY input shape mismatch ", idx);
+ }
+ if (cond_in->rank() > 0 && body_in->rank() > 0)
+ {
+ if (!(*cond_graph_input->shape() == *body_graph_input->shape()))
+ {
+ INTERNAL_EXN_V("CircleWhile COND input and BODY input shape mismatch ", idx);
+ }
+ }
+ if (cond_in->dtype() != body_in->dtype())
+ {
+ INTERNAL_EXN_V("CircleWhile COND input and BODY input type mismatch ", idx);
+ }
+ }
+
+ // Next we compare input of "cond" with output of "body"
+ auto body_graph_outputs = body_graph->outputs();
+ for (size_t idx = 0; idx < cond_inputs.size(); ++idx)
+ {
+ auto cond_in = loco::must_cast<luci::CircleInput *>(cond_inputs.at(idx));
+ auto body_out = loco::must_cast<luci::CircleOutput *>(body_outputs.at(idx));
+
+ auto cond_graph_input = cond_graph_inputs->at(cond_in->index());
+ auto body_graph_output = body_graph_outputs->at(body_out->index());
+ if ((cond_in->rank() != body_out->rank()))
+ {
+ INTERNAL_EXN_V("CircleWhile COND input and BODY output shape mismatch ", idx);
+ }
+ if (cond_in->rank() > 0 && body_out->rank() > 0)
+ {
+ if (!(*cond_graph_input->shape() == *body_graph_output->shape()))
+ {
+ INTERNAL_EXN_V("CircleWhile COND input and BODY output shape mismatch ", idx);
+ }
+ }
+ if (cond_in->dtype() != body_out->dtype())
+ {
+ INTERNAL_EXN_V("CircleWhile COND input and BODY output type mismatch ", idx);
+ }
+ }
+ }
+
+ void visit(luci::CircleNode *) final
+ {
+ // DO NOTHING
+ }
+
+private:
+ const luci::Module *_module;
+ const luci::CircleReader &_reader;
+};
+
+/**
+ * @brief ValidateGraphProp will validate inter graph node properties
+ */
+class ValidateGraphProp final
+{
+public:
+ void run(loco::Graph *g, const luci::Module *m, const luci::CircleReader &r)
+ {
+ for (auto node : loco::postorder_traversal(loco::output_nodes(g)))
+ {
+ if (recognize(node->dialect()))
+ {
+ auto cn = loco::must_cast<luci::CircleNode *>(node);
+
+ eval(cn, m, r);
+ }
+ }
+ }
+
+private:
+ bool recognize(const loco::Dialect *dialect) { return (dialect == luci::CircleDialect::get()); }
+
+ void eval(luci::CircleNode *node, const luci::Module *module, const luci::CircleReader &reader)
+ {
+ ValidateNodeProp val(module, reader);
+ node->accept(&val);
+ }
+};
+
+} // namespace
+
+namespace luci
+{
+
+/**
+ * @brief Do post import actions
+ */
+void post_import_graph(luci::Module *module, const luci::CircleReader &reader)
+{
+ LOGGER(l);
+
+ auto count = module->size();
+
+ for (size_t s = 0; s < count; ++s)
+ {
+ auto g = module->graph(s);
+ assert(g != nullptr);
+
+ INFO(l) << "--- FixInterGraph " << g->name() << "-------------------------";
+ FixInterGraph fix;
+ fix.run(g, module, reader);
+ }
+
+ for (size_t s = 0; s < count; ++s)
+ {
+ auto g = module->graph(s);
+ assert(g != nullptr);
+
+ INFO(l) << "--- ValidateGraphProp " << g->name() << "---------------------";
+ ValidateGraphProp prop;
+ prop.run(g, module, reader);
+ }
+
+ INFO(l) << "--- post_import_graph done -------------------------------------";
+}
+
+} // namespace luci
diff --git a/compiler/luci/import/src/PostImport.h b/compiler/luci/import/src/PostImport.h
new file mode 100644
index 000000000..c719c588a
--- /dev/null
+++ b/compiler/luci/import/src/PostImport.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_POST_IMPORT_H__
+#define __LUCI_POST_IMPORT_H__
+
+#include "luci/Import/CircleReader.h"
+
+#include "luci/IR/Module.h"
+
+namespace luci
+{
+
+/**
+ * @brief Do post import actions
+ */
+void post_import_graph(luci::Module *module, const luci::CircleReader &reader);
+
+} // namespace luci
+
+#endif // __LUCI_POST_IMPORT_H__
diff --git a/compiler/luci/lang/CMakeLists.txt b/compiler/luci/lang/CMakeLists.txt
index 564e777fb..32d0a890d 100644
--- a/compiler/luci/lang/CMakeLists.txt
+++ b/compiler/luci/lang/CMakeLists.txt
@@ -7,6 +7,7 @@ target_include_directories(luci_lang PRIVATE src)
target_include_directories(luci_lang PUBLIC include)
target_link_libraries(luci_lang PUBLIC loco)
target_link_libraries(luci_lang PUBLIC oops)
+target_link_libraries(luci_lang PRIVATE logo)
target_link_libraries(luci_lang PRIVATE nncc_common)
install(TARGETS luci_lang DESTINATION lib)
@@ -20,3 +21,4 @@ nnas_find_package(GTest REQUIRED)
GTest_AddTest(luci_lang_test ${TESTS})
target_include_directories(luci_lang_test PRIVATE src)
target_link_libraries(luci_lang_test luci_lang)
+target_link_libraries(luci_lang_test logo)
diff --git a/compiler/luci/lang/include/luci/IR/AttrDilation.h b/compiler/luci/lang/include/luci/IR/AttrDilation.h
new file mode 100644
index 000000000..c2b28d77d
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/AttrDilation.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_ATTRDILATION_H__
+#define __LUCI_IR_ATTRDILATION_H__
+
+#include <stdint.h>
+
+namespace luci
+{
+
+class Dilation final
+{
+public:
+ Dilation() : _w(1), _h(1) {}
+
+ int32_t w() const { return _w; }
+ void w(int32_t w) { _w = w; }
+
+ int32_t h() const { return _h; }
+ void h(int32_t h) { _h = h; }
+
+private:
+ int32_t _w;
+ int32_t _h;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_ATTRDILATION_H__
diff --git a/compiler/luci/lang/include/luci/IR/AttrMirrorPadMode.h b/compiler/luci/lang/include/luci/IR/AttrMirrorPadMode.h
new file mode 100644
index 000000000..7ca9d5d99
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/AttrMirrorPadMode.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_ATTR_MIRROR_PAD_MODE_H__
+#define __LUCI_IR_ATTR_MIRROR_PAD_MODE_H__
+
+namespace luci
+{
+
+enum class MirrorPadMode
+{
+ UNDEFINED, // This is not defined by Circle. This was added to prevent programming error.
+
+ REFLECT,
+ SYMMETRIC,
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_ATTR_MIRROR_PAD_MODE_H__
diff --git a/compiler/luci/lang/include/luci/IR/CircleNodeDecl.h b/compiler/luci/lang/include/luci/IR/CircleNodeDecl.h
index b87bdf9d0..967103e3c 100644
--- a/compiler/luci/lang/include/luci/IR/CircleNodeDecl.h
+++ b/compiler/luci/lang/include/luci/IR/CircleNodeDecl.h
@@ -17,8 +17,10 @@
#ifndef __LUCI_IR_CIRCLENODEDECL_H__
#define __LUCI_IR_CIRCLENODEDECL_H__
-#include <loco/IR/Node.h>
#include <loco/IR/Dialect.h>
+#include <loco/IR/Node.h>
+#include <loco/IR/NodeMixins.h>
+#include <luci/IR/PropertyShapeStatus.h>
#include "CircleOpcode.h"
#include "CircleNodeVisitor.forward.h"
@@ -31,7 +33,9 @@ namespace luci
using NodeName = std::string;
-struct CircleNode : public loco::Node
+struct CircleNode : public loco::Node,
+ public loco::NodeMixin<loco::NodeTrait::DataType>,
+ public loco::NodeMixin<loco::NodeTrait::TensorShape>
{
virtual ~CircleNode() = default;
@@ -50,9 +54,17 @@ struct CircleNode : public loco::Node
_quantparam = std::move(quantparam);
}
+ ShapeStatus shape_status(void) const { return _shape_status; }
+ void shape_status(ShapeStatus ss) { _shape_status = ss; }
+
+ int32_t op_version(void) const { return _op_version; }
+ void op_version(int32_t op_version) { _op_version = op_version; }
+
private:
NodeName _name;
std::unique_ptr<CircleQuantParam> _quantparam;
+ ShapeStatus _shape_status{ShapeStatus::UNDEFINED};
+ int32_t _op_version = 1;
};
template <CircleOpcode Code> struct CircleNodeImpl : public CircleNode
diff --git a/compiler/luci/lang/include/luci/IR/CircleNodeImpl.h b/compiler/luci/lang/include/luci/IR/CircleNodeImpl.h
index bdcfc9c9d..a6b9488db 100644
--- a/compiler/luci/lang/include/luci/IR/CircleNodeImpl.h
+++ b/compiler/luci/lang/include/luci/IR/CircleNodeImpl.h
@@ -18,7 +18,6 @@
#define __LUCI_IR_CIRCLENODEIMPL_H__
#include "CircleNodes.h"
-#include "CircleNodeVisitor.h"
#include <oops/InternalExn.h>
diff --git a/compiler/luci/lang/include/luci/IR/CircleNodes.h b/compiler/luci/lang/include/luci/IR/CircleNodes.h
index cc822842b..3b31149b2 100644
--- a/compiler/luci/lang/include/luci/IR/CircleNodes.h
+++ b/compiler/luci/lang/include/luci/IR/CircleNodes.h
@@ -19,42 +19,124 @@
#include "Nodes/CircleAbs.h"
#include "Nodes/CircleAdd.h"
+#include "Nodes/CircleAddN.h"
#include "Nodes/CircleArgMax.h"
+#include "Nodes/CircleArgMin.h"
#include "Nodes/CircleAveragePool2D.h"
+#include "Nodes/CircleBatchMatMul.h"
#include "Nodes/CircleBatchToSpaceND.h"
+#include "Nodes/CircleCast.h"
+#include "Nodes/CircleCeil.h"
#include "Nodes/CircleConcatenation.h"
#include "Nodes/CircleConst.h"
#include "Nodes/CircleConv2D.h"
#include "Nodes/CircleCos.h"
+#include "Nodes/CircleCustom.h"
+#include "Nodes/CircleDepthToSpace.h"
#include "Nodes/CircleDepthwiseConv2D.h"
#include "Nodes/CircleDiv.h"
+#include "Nodes/CircleElu.h"
#include "Nodes/CircleEqual.h"
#include "Nodes/CircleExp.h"
+#include "Nodes/CircleExpandDims.h"
+#include "Nodes/CircleFill.h"
+#include "Nodes/CircleFloor.h"
+#include "Nodes/CircleFloorDiv.h"
+#include "Nodes/CircleFloorMod.h"
#include "Nodes/CircleFullyConnected.h"
#include "Nodes/CircleGather.h"
+#include "Nodes/CircleGatherNd.h"
+#include "Nodes/CircleGreater.h"
+#include "Nodes/CircleGreaterEqual.h"
+#include "Nodes/CircleIf.h"
+#include "Nodes/CircleL2Normalize.h"
+#include "Nodes/CircleL2Pool2D.h"
+#include "Nodes/CircleLeakyRelu.h"
+#include "Nodes/CircleLess.h"
+#include "Nodes/CircleLessEqual.h"
+#include "Nodes/CircleLocalResponseNormalization.h"
+#include "Nodes/CircleLog.h"
+#include "Nodes/CircleLogicalAnd.h"
#include "Nodes/CircleLogicalNot.h"
#include "Nodes/CircleLogicalOr.h"
+#include "Nodes/CircleLogistic.h"
+#include "Nodes/CircleLogSoftmax.h"
+#include "Nodes/CircleMatrixDiag.h"
+#include "Nodes/CircleMatrixSetDiag.h"
#include "Nodes/CircleMaximum.h"
#include "Nodes/CircleMaxPool2D.h"
#include "Nodes/CircleMean.h"
+#include "Nodes/CircleMinimum.h"
+#include "Nodes/CircleMirrorPad.h"
#include "Nodes/CircleMul.h"
+#include "Nodes/CircleNeg.h"
+#include "Nodes/CircleNotEqual.h"
+#include "Nodes/CircleOneHot.h"
#include "Nodes/CirclePack.h"
#include "Nodes/CirclePad.h"
-#include "Nodes/CircleRelu6.h"
+#include "Nodes/CirclePow.h"
+#include "Nodes/CirclePRelu.h"
+#include "Nodes/CircleRange.h"
+#include "Nodes/CircleRank.h"
+#include "Nodes/CircleReduceAny.h"
+#include "Nodes/CircleReduceMax.h"
+#include "Nodes/CircleReduceMin.h"
+#include "Nodes/CircleReduceProd.h"
#include "Nodes/CircleRelu.h"
+#include "Nodes/CircleRelu6.h"
+#include "Nodes/CircleReluN1To1.h"
#include "Nodes/CircleReshape.h"
+#include "Nodes/CircleResizeBilinear.h"
+#include "Nodes/CircleResizeNearestNeighbor.h"
+#include "Nodes/CircleReverseSequence.h"
+#include "Nodes/CircleReverseV2.h"
+#include "Nodes/CircleRound.h"
#include "Nodes/CircleRsqrt.h"
+#include "Nodes/CircleScatterNd.h"
+#include "Nodes/CircleSegmentSum.h"
+#include "Nodes/CircleSelect.h"
+#include "Nodes/CircleSelectV2.h"
+#include "Nodes/CircleShape.h"
+#include "Nodes/CircleSin.h"
+#include "Nodes/CircleSlice.h"
#include "Nodes/CircleSoftmax.h"
+#include "Nodes/CircleSpaceToBatchND.h"
+#include "Nodes/CircleSpaceToDepth.h"
+#include "Nodes/CircleSparseToDense.h"
+#include "Nodes/CircleSplit.h"
+#include "Nodes/CircleSplitV.h"
#include "Nodes/CircleSqrt.h"
+#include "Nodes/CircleSquare.h"
#include "Nodes/CircleSquaredDifference.h"
+#include "Nodes/CircleSqueeze.h"
+#include "Nodes/CircleStridedSlice.h"
#include "Nodes/CircleSub.h"
-#include "Nodes/CircleTransposeConv.h"
+#include "Nodes/CircleSum.h"
+#include "Nodes/CircleTanh.h"
+#include "Nodes/CircleTile.h"
+#include "Nodes/CircleTopKV2.h"
#include "Nodes/CircleTranspose.h"
+#include "Nodes/CircleTransposeConv.h"
+#include "Nodes/CircleUnpack.h"
+#include "Nodes/CircleWhere.h"
+#include "Nodes/CircleWhile.h"
+#include "Nodes/CircleZerosLike.h"
// Circle only
+#include "Nodes/CircleBCQFullyConnected.h"
+#include "Nodes/CircleBCQGather.h"
#include "Nodes/CircleInstanceNorm.h"
// Virtual nodes
#include "Nodes/CircleInput.h"
#include "Nodes/CircleOutput.h"
+#include "Nodes/CircleCustomOut.h"
+#include "Nodes/CircleIfOut.h"
+#include "Nodes/CircleUnpackOut.h"
+#include "Nodes/CircleSplitOut.h"
+#include "Nodes/CircleSplitVOut.h"
+#include "Nodes/CircleTopKV2Out.h"
+#include "Nodes/CircleWhileOut.h"
+
+#include <loco/IR/Graph.h>
namespace luci
{
@@ -68,6 +150,18 @@ namespace luci
*/
void set_new_shape(CircleReshape *node, int32_t *base, uint32_t size);
+/// @brief Link GraphOutput with CircleOutput node
+void link(loco::GraphOutput *, CircleOutput *);
+
+/// @brief Link GraphInput with CircleInput node
+void link(loco::GraphInput *, CircleInput *);
+
+/// @brief Find a CircleOutput node with a given output index
+CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &index);
+
+/// @brief Find a Pull node with a given input index
+CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index);
+
} // namespace luci
#endif // __LUCI_IR_CIRCLENODES_H__
diff --git a/compiler/luci/lang/include/luci/IR/CircleNodes.lst b/compiler/luci/lang/include/luci/IR/CircleNodes.lst
index ca3f7fb0f..488dcfb89 100644
--- a/compiler/luci/lang/include/luci/IR/CircleNodes.lst
+++ b/compiler/luci/lang/include/luci/IR/CircleNodes.lst
@@ -13,40 +13,121 @@
CIRCLE_NODE(ABS, luci::CircleAbs)
CIRCLE_NODE(ADD, luci::CircleAdd)
+CIRCLE_NODE(ADD_N, luci::CircleAddN)
CIRCLE_NODE(ARG_MAX, luci::CircleArgMax)
+CIRCLE_NODE(ARG_MIN, luci::CircleArgMin)
CIRCLE_NODE(AVERAGE_POOL_2D, luci::CircleAveragePool2D)
CIRCLE_NODE(BATCH_TO_SPACE_ND, luci::CircleBatchToSpaceND)
+CIRCLE_NODE(BATCHMATMUL, luci::CircleBatchMatMul)
+CIRCLE_NODE(CAST, luci::CircleCast)
+CIRCLE_NODE(CEIL, luci::CircleCeil)
CIRCLE_NODE(CONCATENATION, luci::CircleConcatenation)
CIRCLE_NODE(CONST, luci::CircleConst)
CIRCLE_NODE(CONV_2D, luci::CircleConv2D)
CIRCLE_NODE(COS, luci::CircleCos)
+CIRCLE_NODE(CUSTOM, luci::CircleCustom)
+CIRCLE_NODE(DEPTH_TO_SPACE, luci::CircleDepthToSpace)
CIRCLE_NODE(DEPTHWISE_CONV_2D, luci::CircleDepthwiseConv2D)
CIRCLE_NODE(DIV, luci::CircleDiv)
+CIRCLE_NODE(ELU, luci::CircleElu)
CIRCLE_NODE(EQUAL, luci::CircleEqual)
CIRCLE_NODE(EXP, luci::CircleExp)
+CIRCLE_NODE(EXPAND_DIMS, luci::CircleExpandDims)
+CIRCLE_NODE(FILL, luci::CircleFill)
+CIRCLE_NODE(FLOOR, luci::CircleFloor)
+CIRCLE_NODE(FLOOR_DIV, luci::CircleFloorDiv)
+CIRCLE_NODE(FLOOR_MOD, luci::CircleFloorMod)
CIRCLE_NODE(FULLY_CONNECTED, luci::CircleFullyConnected)
CIRCLE_NODE(GATHER, luci::CircleGather)
+CIRCLE_NODE(GATHER_ND, luci::CircleGatherNd)
+CIRCLE_NODE(GREATER, luci::CircleGreater)
+CIRCLE_NODE(GREATER_EQUAL, luci::CircleGreaterEqual)
+CIRCLE_NODE(IF, luci::CircleIf)
+CIRCLE_NODE(L2_NORMALIZATION, luci::CircleL2Normalize)
+CIRCLE_NODE(L2_POOL_2D, luci::CircleL2Pool2D)
+CIRCLE_NODE(LEAKY_RELU, luci::CircleLeakyRelu)
+CIRCLE_NODE(LESS, luci::CircleLess)
+CIRCLE_NODE(LESS_EQUAL, luci::CircleLessEqual)
+CIRCLE_NODE(LOCAL_RESPONSE_NORMALIZATION, luci::CircleLocalResponseNormalization)
+CIRCLE_NODE(LOG, luci::CircleLog)
+CIRCLE_NODE(LOGICAL_AND, luci::CircleLogicalAnd)
CIRCLE_NODE(LOGICAL_NOT, luci::CircleLogicalNot)
CIRCLE_NODE(LOGICAL_OR, luci::CircleLogicalOr)
-CIRCLE_NODE(MAXIMUM, luci::CircleMaximum)
+CIRCLE_NODE(LOGISTIC, luci::CircleLogistic)
+CIRCLE_NODE(LOG_SOFTMAX, luci::CircleLogSoftmax)
+CIRCLE_NODE(MATRIX_DIAG, luci::CircleMatrixDiag)
CIRCLE_NODE(MAX_POOL_2D, luci::CircleMaxPool2D)
+CIRCLE_NODE(MATRIX_SET_DIAG, luci::CircleMatrixSetDiag)
+CIRCLE_NODE(MAXIMUM, luci::CircleMaximum)
CIRCLE_NODE(MEAN, luci::CircleMean)
+CIRCLE_NODE(MINIMUM, luci::CircleMinimum)
+CIRCLE_NODE(MIRROR_PAD, luci::CircleMirrorPad)
CIRCLE_NODE(MUL, luci::CircleMul)
+CIRCLE_NODE(NEG, luci::CircleNeg)
+CIRCLE_NODE(NOT_EQUAL, luci::CircleNotEqual)
+CIRCLE_NODE(ONE_HOT, luci::CircleOneHot)
CIRCLE_NODE(PACK, luci::CirclePack)
CIRCLE_NODE(PAD, luci::CirclePad)
+CIRCLE_NODE(POW, luci::CirclePow)
+CIRCLE_NODE(PRELU, luci::CirclePRelu)
+CIRCLE_NODE(RANGE, luci::CircleRange)
+CIRCLE_NODE(RANK, luci::CircleRank)
+CIRCLE_NODE(REDUCE_ANY, luci::CircleReduceAny)
+CIRCLE_NODE(REDUCE_MAX, luci::CircleReduceMax)
+CIRCLE_NODE(REDUCE_MIN, luci::CircleReduceMin)
+CIRCLE_NODE(REDUCE_PROD, luci::CircleReduceProd)
CIRCLE_NODE(RELU, luci::CircleRelu)
CIRCLE_NODE(RELU6, luci::CircleRelu6)
+CIRCLE_NODE(RELU_N1_TO_1, luci::CircleReluN1To1)
CIRCLE_NODE(RESHAPE, luci::CircleReshape)
+CIRCLE_NODE(RESIZE_BILINEAR, luci::CircleResizeBilinear)
+CIRCLE_NODE(RESIZE_NEAREST_NEIGHBOR, luci::CircleResizeNearestNeighbor)
+CIRCLE_NODE(REVERSE_SEQUENCE, luci::CircleReverseSequence)
+CIRCLE_NODE(REVERSE_V2, luci::CircleReverseV2)
+CIRCLE_NODE(ROUND, luci::CircleRound)
CIRCLE_NODE(RSQRT, luci::CircleRsqrt)
+CIRCLE_NODE(SCATTER_ND, luci::CircleScatterNd)
+CIRCLE_NODE(SEGMENT_SUM, luci::CircleSegmentSum)
+CIRCLE_NODE(SELECT, luci::CircleSelect)
+CIRCLE_NODE(SELECT_V2, luci::CircleSelectV2)
+CIRCLE_NODE(SHAPE, luci::CircleShape)
+CIRCLE_NODE(SIN, luci::CircleSin)
+CIRCLE_NODE(SLICE, luci::CircleSlice)
CIRCLE_NODE(SOFTMAX, luci::CircleSoftmax)
+CIRCLE_NODE(SPACE_TO_BATCH_ND, luci::CircleSpaceToBatchND)
+CIRCLE_NODE(SPACE_TO_DEPTH, luci::CircleSpaceToDepth)
+CIRCLE_NODE(SPARSE_TO_DENSE, luci::CircleSparseToDense)
+CIRCLE_NODE(SPLIT, luci::CircleSplit)
+CIRCLE_NODE(SPLIT_V, luci::CircleSplitV)
CIRCLE_NODE(SQRT, luci::CircleSqrt)
+CIRCLE_NODE(SQUARE, luci::CircleSquare)
CIRCLE_NODE(SQUARED_DIFFERENCE, luci::CircleSquaredDifference)
+CIRCLE_NODE(SQUEEZE, luci::CircleSqueeze)
+CIRCLE_NODE(STRIDED_SLICE, luci::CircleStridedSlice)
CIRCLE_NODE(SUB, luci::CircleSub)
-// TODO TFLTanh
+CIRCLE_NODE(SUM, luci::CircleSum)
+CIRCLE_NODE(TANH, luci::CircleTanh)
+CIRCLE_NODE(TILE, luci::CircleTile)
+CIRCLE_NODE(TOPK_V2, luci::CircleTopKV2)
CIRCLE_NODE(TRANSPOSE, luci::CircleTranspose)
CIRCLE_NODE(TRANSPOSE_CONV, luci::CircleTransposeConv)
+CIRCLE_NODE(UNPACK, luci::CircleUnpack)
+CIRCLE_NODE(WHERE, luci::CircleWhere)
+CIRCLE_NODE(WHILE, luci::CircleWhile)
+CIRCLE_NODE(ZEROS_LIKE, luci::CircleZerosLike)
// Circle Only
+CIRCLE_NODE(BCQ_FULLY_CONNECTED, luci::CircleBCQFullyConnected)
+CIRCLE_NODE(BCQ_GATHER, luci::CircleBCQGather)
CIRCLE_NODE(INSTANCE_NORM, luci::CircleInstanceNorm)
// Virtual node(s)
CIRCLE_NODE(CIRCLEINPUT, luci::CircleInput)
CIRCLE_NODE(CIRCLEOUTPUT, luci::CircleOutput)
+CIRCLE_NODE(CIRCLEOUTPUTDUMMY, luci::CircleOutputDummy)
+CIRCLE_NODE(CIRCLEOUTPUTEXCLUDE, luci::CircleOutputExclude)
+CIRCLE_NODE(CIRCLECUSTOMOUT, luci::CircleCustomOut)
+CIRCLE_NODE(CIRCLEIFOUT, luci::CircleIfOut)
+CIRCLE_NODE(CIRCLESPLITOUT, luci::CircleSplitOut)
+CIRCLE_NODE(CIRCLESPLITVOUT, luci::CircleSplitVOut)
+CIRCLE_NODE(CIRCLETOPKV2OUT, luci::CircleTopKV2Out)
+CIRCLE_NODE(CIRCLEUNPACKOUT, luci::CircleUnpackOut)
+CIRCLE_NODE(CIRCLEWHILEOUT, luci::CircleWhileOut)
diff --git a/compiler/luci/lang/include/luci/IR/LuciNodeMixins.h b/compiler/luci/lang/include/luci/IR/LuciNodeMixins.h
index b18ac5dc4..c1bb0db11 100644
--- a/compiler/luci/lang/include/luci/IR/LuciNodeMixins.h
+++ b/compiler/luci/lang/include/luci/IR/LuciNodeMixins.h
@@ -22,6 +22,8 @@
#include <loco/IR/Node.h>
#include <loco/IR/NodeMixins.h>
+#include <vector>
+
namespace luci
{
@@ -70,6 +72,7 @@ template <unsigned N, typename Base> class FixedArityNode : public Base
public:
FixedArityNode()
{
+ _args.resize(N);
for (uint32_t n = 0; n < N; ++n)
{
_args[n] = std::make_unique<loco::Use>(this);
@@ -96,7 +99,7 @@ protected:
loco::Use *at(unsigned n) const { return _args.at(n).get(); }
private:
- std::array<std::unique_ptr<loco::Use>, N> _args;
+ std::vector<std::unique_ptr<loco::Use>> _args{};
};
} // namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleAddN.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleAddN.h
new file mode 100644
index 000000000..6ba4a96bc
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleAddN.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCEL_ADD_N_H__
+#define __LUCI_IR_CIRCEL_ADD_N_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/VariadicArityNode.h"
+
+namespace luci
+{
+
+/**
+ * @brief ADD_N in Circle
+ */
+class CircleAddN final : public VariadicArityNode<CircleNodeImpl<CircleOpcode::ADD_N>>
+{
+public:
+ CircleAddN(uint32_t arity) : VariadicArityNode<CircleNodeImpl<CircleOpcode::ADD_N>>(arity)
+ {
+ assert(arity >= 1);
+ }
+
+public:
+ Node *inputs(uint32_t index) const { return at(index)->node(); }
+ void inputs(uint32_t index, Node *node) { at(index)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCEL_ADD_N_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleArgMin.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleArgMin.h
new file mode 100644
index 000000000..8cb561983
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleArgMin.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCELARGMIN_H__
+#define __LUCI_IR_CIRCELARGMIN_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief ARG_Min in Circle
+ */
+class CircleArgMin final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::ARG_MIN>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *dimension(void) const { return at(1)->node(); }
+ void dimension(loco::Node *node) { at(1)->node(node); }
+
+public:
+ loco::DataType output_type(void) const { return _output_type; }
+ void output_type(loco::DataType ot) { _output_type = ot; }
+
+private:
+ loco::DataType _output_type{loco::DataType::S64};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCELARGMIN_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQFullyConnected.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQFullyConnected.h
new file mode 100644
index 000000000..7d12d593a
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQFullyConnected.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEBCQFULLYCONNECTED_H__
+#define __LUCI_IR_CIRCLEBCQFULLYCONNECTED_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/AttrFusedActFunc.h"
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief BCQ_FULLY_CONNECTED in Circle
+ */
+class CircleBCQFullyConnected final
+ : public FixedArityNode<5, CircleNodeImpl<CircleOpcode::BCQ_FULLY_CONNECTED>>,
+ public LuciNodeMixin<LuciNodeTrait::FusedActFunc>,
+ public LuciNodeMixin<LuciNodeTrait::Bias>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *weights_scales(void) const { return at(1)->node(); }
+ void weights_scales(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *weights_binary(void) const { return at(2)->node(); }
+ void weights_binary(loco::Node *node) { at(2)->node(node); }
+
+ loco::Node *bias(void) const override { return at(3)->node(); }
+ void bias(loco::Node *node) override { at(3)->node(node); }
+
+ loco::Node *weights_clusters(void) const { return at(4)->node(); }
+ void weights_clusters(loco::Node *node) { at(4)->node(node); }
+
+public:
+ int32_t weights_hidden_size(void) const { return _weights_hidden_size; }
+ void weights_hidden_size(int32_t weights_hidden_size)
+ {
+ _weights_hidden_size = weights_hidden_size;
+ }
+
+private:
+ int32_t _weights_hidden_size = 0;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEBCQFULLYCONNECTED_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQGather.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQGather.h
new file mode 100644
index 000000000..f7638261d
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQGather.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEBCQGATHER_H__
+#define __LUCI_IR_CIRCLEBCQGATHER_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief BCQ_GATHER in Circle
+ */
+class CircleBCQGather final : public FixedArityNode<4, CircleNodeImpl<CircleOpcode::BCQ_GATHER>>
+{
+public:
+ loco::Node *input_scales(void) const { return at(0)->node(); }
+ void input_scales(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *input_binary(void) const { return at(1)->node(); }
+ void input_binary(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *indices(void) const { return at(2)->node(); }
+ void indices(loco::Node *node) { at(2)->node(node); }
+
+ loco::Node *input_clusters(void) const { return at(3)->node(); }
+ void input_clusters(loco::Node *node) { at(3)->node(node); }
+
+public:
+ int32_t axis(void) const { return _axis; }
+ void axis(int32_t axis) { _axis = axis; }
+
+ int32_t input_hidden_size(void) const { return _input_hidden_size; }
+ void input_hidden_size(int32_t input_hidden_size) { _input_hidden_size = input_hidden_size; }
+
+private:
+ int32_t _axis = 0;
+ int32_t _input_hidden_size = 0;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEBCQGATHER_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleBatchMatMul.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleBatchMatMul.h
new file mode 100644
index 000000000..19999924e
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleBatchMatMul.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCELBATCHMATMUL_H__
+#define __LUCI_IR_CIRCELBATCHMATMUL_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief BATCHMATMUL in Circle
+ */
+class CircleBatchMatMul final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::BATCHMATMUL>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+
+public:
+ bool adj_x(void) const { return _adj_x; }
+ void adj_x(bool arg) { _adj_x = arg; }
+
+ bool adj_y(void) const { return _adj_y; }
+ void adj_y(bool arg) { _adj_y = arg; }
+
+private:
+ bool _adj_x = false;
+ bool _adj_y = false;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCELBATCHMATMUL_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleCast.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleCast.h
new file mode 100644
index 000000000..9a89d0b2b
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleCast.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCELECAST_H__
+#define __LUCI_IR_CIRCELECAST_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief CAST in Circle
+ */
+class CircleCast final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CAST>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+public:
+ loco::DataType in_data_type(void) const { return _in_data_type; }
+ void in_data_type(loco::DataType it) { _in_data_type = it; }
+
+ loco::DataType out_data_type(void) const { return _out_data_type; }
+ void out_data_type(loco::DataType ot) { _out_data_type = ot; }
+
+private:
+ loco::DataType _in_data_type{loco::DataType::FLOAT32};
+ loco::DataType _out_data_type{loco::DataType::FLOAT32};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCELECAST_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleCeil.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleCeil.h
new file mode 100644
index 000000000..8a8715dcf
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleCeil.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_CEIL_H__
+#define __LUCI_IR_CIRCLE_CEIL_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief CEIL in Circle
+ */
+class CircleCeil final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CEIL>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_CEIL_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h
index 8a6778a2f..dea1a4613 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h
@@ -64,7 +64,7 @@ public:
void axis(int32_t axis) { _axis = axis; }
private:
- int32_t _axis;
+ int32_t _axis{0};
};
} // namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h
index 089836eb9..fc671746f 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
#include <loco/IR/DataTypeTraits.h>
@@ -32,9 +31,7 @@ namespace luci
* @brief Class to build tensor data
* @note This will not be exported as a specific op
*/
-class CircleConst final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CONST>>,
- public loco::NodeMixin<loco::NodeTrait::DataType>,
- public loco::NodeMixin<loco::NodeTrait::TensorShape>
+class CircleConst final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CONST>>
{
public:
CircleConst() = default;
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h
index 54318e65c..13657cee4 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h
@@ -22,6 +22,7 @@
#include "luci/IR/AttrPadding.h"
#include "luci/IR/AttrStride.h"
+#include "luci/IR/AttrDilation.h"
#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
@@ -52,9 +53,13 @@ public:
const Stride *stride(void) const { return &_stride; }
Stride *stride(void) { return &_stride; }
+ const Dilation *dilation(void) const { return &_dilation; }
+ Dilation *dilation(void) { return &_dilation; }
+
private:
Padding _padding = Padding::UNDEFINED;
Stride _stride;
+ Dilation _dilation;
};
} // namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleCustom.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleCustom.h
new file mode 100644
index 000000000..6c722b766
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleCustom.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLECUSTOM_H__
+#define __LUCI_IR_CIRCLECUSTOM_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/VariadicArityNode.h"
+
+namespace luci
+{
+
+/**
+ * @brief CUSTOM in Circle
+ */
+class CircleCustom final : public VariadicArityNode<CircleNodeImpl<CircleOpcode::CUSTOM>>
+{
+public:
+ CircleCustom(uint32_t arity) : VariadicArityNode<CircleNodeImpl<CircleOpcode::CUSTOM>>(arity)
+ {
+ // TODO Support when arity is 0
+ assert(arity >= 1);
+ }
+
+public:
+ uint32_t numInputs(void) const { return arity(); }
+
+public:
+ Node *inputs(uint32_t index) const { return at(index)->node(); }
+ void inputs(uint32_t index, Node *node) { at(index)->node(node); }
+
+ const std::vector<uint8_t> &custom_options(void) const { return _custom_options; }
+ void custom_options(const std::vector<uint8_t> &custom_options)
+ {
+ _custom_options = custom_options;
+ }
+
+ const std::string &custom_code(void) const { return _custom_code; }
+ void custom_code(const std::string &custom_code) { _custom_code = custom_code; }
+
+private:
+ std::vector<uint8_t> _custom_options;
+ std::string _custom_code;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLECUSTOM_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleCustomOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleCustomOut.h
new file mode 100644
index 000000000..36b8e4aed
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleCustomOut.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_CUSTOMOUT_H__
+#define __LUCI_IR_CIRCLE_CUSTOMOUT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief Virtual CIRCLECUSTOMOUT in Circle
+ */
+class CircleCustomOut final
+ : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLECUSTOMOUT>>
+{
+public:
+ CircleCustomOut() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t index(void) const { return _index; }
+ void index(int32_t index) { _index = index; }
+
+private:
+ int32_t _index{-1};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_CUSTOMOUT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthToSpace.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthToSpace.h
new file mode 100644
index 000000000..e19282b97
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthToSpace.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_DEPTHTOSPACE_H__
+#define __LUCI_IR_CIRCLE_DEPTHTOSPACE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief DEPTH_TO_SPACE in Circle
+ */
+class CircleDepthToSpace final
+ : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::DEPTH_TO_SPACE>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int block_size(void) const { return _block_size; }
+ void block_size(int block_size) { _block_size = block_size; }
+
+private:
+ int _block_size{0};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_DEPTHTOSPACE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h
index 15ee62ba7..eb058cec1 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h
@@ -20,6 +20,7 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
+#include "luci/IR/AttrDilation.h"
#include "luci/IR/AttrFilter.h"
#include "luci/IR/AttrPadding.h"
#include "luci/IR/AttrStride.h"
@@ -57,10 +58,14 @@ public:
int32_t depthMultiplier(void) const { return _depth_multiplier; }
void depthMultiplier(int32_t arg) { _depth_multiplier = arg; }
+ const Dilation *dilation(void) const { return &_dilation; }
+ Dilation *dilation(void) { return &_dilation; }
+
private:
Padding _padding = Padding::UNDEFINED;
Stride _stride;
int32_t _depth_multiplier = 0;
+ Dilation _dilation;
};
} // namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleElu.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleElu.h
new file mode 100644
index 000000000..fbb2f3533
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleElu.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEELU_H__
+#define __LUCI_IR_CIRCLEELU_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief ELU in Circle
+ */
+class CircleElu final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::ELU>>
+{
+public:
+ CircleElu() = default;
+
+public:
+ loco::Node *features(void) const { return at(0)->node(); }
+ void features(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEELU_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleExpandDims.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleExpandDims.h
new file mode 100644
index 000000000..f70219614
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleExpandDims.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEEXPAND_DIMS_H__
+#define __LUCI_IR_CIRCLEEXPAND_DIMS_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief EXPAND_DIMS in Circle
+ */
+class CircleExpandDims final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::EXPAND_DIMS>>
+{
+public:
+ CircleExpandDims() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *axis(void) const { return at(1)->node(); }
+ void axis(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEEXPAND_DIMS_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleFill.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleFill.h
new file mode 100644
index 000000000..bfc65274a
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleFill.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCEFILL_H__
+#define __LUCI_IR_CIRCEFILL_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief FILL in Circle
+ */
+class CircleFill final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::FILL>>
+{
+public:
+ loco::Node *dims(void) const { return at(0)->node(); }
+ void dims(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *value(void) const { return at(1)->node(); }
+ void value(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCEFILL_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleFloor.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloor.h
new file mode 100644
index 000000000..7e10547b6
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloor.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_FLOOR_H__
+#define __LUCI_IR_CIRCLE_FLOOR_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief FLOOR in Circle
+ */
+class CircleFloor final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::FLOOR>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_FLOOR_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorDiv.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorDiv.h
new file mode 100644
index 000000000..ba9db010c
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorDiv.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_FLOOR_DIV_H__
+#define __LUCI_IR_CIRCLE_FLOOR_DIV_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief FLOOR_DIV in Circle
+ */
+class CircleFloorDiv final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::FLOOR_DIV>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_FLOOR_DIV_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorMod.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorMod.h
new file mode 100644
index 000000000..4d13717a0
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorMod.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_FLOOR_MOD_H__
+#define __LUCI_IR_CIRCLE_FLOOR_MOD_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief FLOOR_MOD in Circle
+ */
+class CircleFloorMod final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::FLOOR_MOD>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_FLOOR_MOD_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h
index 489596c04..1e8c4982a 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
@@ -32,11 +31,11 @@ namespace luci
class CircleGather final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::GATHER>>
{
public:
- loco::Node *input(void) const { return at(0)->node(); }
- void input(loco::Node *node) { at(0)->node(node); }
+ loco::Node *params(void) const { return at(0)->node(); }
+ void params(loco::Node *node) { at(0)->node(node); }
- loco::Node *positions(void) const { return at(1)->node(); }
- void positions(loco::Node *node) { at(1)->node(node); }
+ loco::Node *indices(void) const { return at(1)->node(); }
+ void indices(loco::Node *node) { at(1)->node(node); }
public:
int32_t axis(void) const { return _axis; }
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleGatherNd.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleGatherNd.h
new file mode 100644
index 000000000..3423a8216
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleGatherNd.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEGATHER_ND_H__
+#define __LUCI_IR_CIRCLEGATHER_ND_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief GATHER_ND in Circle
+ */
+class CircleGatherNd final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::GATHER_ND>>
+{
+public:
+ loco::Node *params(void) const { return at(0)->node(); }
+ void params(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *indices(void) const { return at(1)->node(); }
+ void indices(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEGATHER_ND_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleGreater.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleGreater.h
new file mode 100644
index 000000000..040a4e338
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleGreater.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_GREATER_H__
+#define __LUCI_IR_CIRCLE_GREATER_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief Greater in Circle
+ */
+class CircleGreater final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::GREATER>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_GREATER_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleGreaterEqual.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleGreaterEqual.h
new file mode 100644
index 000000000..82bdab212
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleGreaterEqual.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_GREATEREQUAL_H__
+#define __LUCI_IR_CIRCLE_GREATEREQUAL_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief GREATER EQUAL in Circle
+ */
+class CircleGreaterEqual final
+ : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::GREATER_EQUAL>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_GREATEREQUAL_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleIf.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleIf.h
new file mode 100644
index 000000000..2f9eac211
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleIf.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_IF_H__
+#define __LUCI_IR_CIRCLE_IF_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/VariadicArityNode.h"
+
+#include <cassert>
+
+namespace luci
+{
+
+/**
+ * @brief IF in Circle
+ */
+class CircleIf final : public VariadicArityNode<CircleNodeImpl<CircleOpcode::IF>>
+{
+public:
+ CircleIf(uint32_t arity, uint32_t out)
+ : VariadicArityNode<CircleNodeImpl<CircleOpcode::IF>>(arity + 1), _output_count(out)
+ {
+ assert(arity > 0);
+ assert(out > 0);
+ }
+
+public:
+ uint32_t input_count(void) const { return arity() - 1; }
+ uint32_t output_count(void) const { return _output_count; }
+
+public:
+ Node *cond(void) const { return at(0)->node(); }
+ void cond(Node *node) { at(0)->node(node); }
+
+ Node *input(uint32_t index) const { return at(index + 1)->node(); }
+ void input(uint32_t index, Node *node) { at(index + 1)->node(node); }
+
+public:
+ int32_t then_branch(void) const { return _then_branch; }
+ void then_branch(int32_t then_branch) { _then_branch = then_branch; }
+
+ int32_t else_branch(void) const { return _else_branch; }
+ void else_branch(int32_t else_branch) { _else_branch = else_branch; }
+
+public:
+ loco::Graph *then_graph(void) const { return _then_graph; }
+ void then_graph(loco::Graph *then_graph) { _then_graph = then_graph; }
+
+ loco::Graph *else_graph(void) const { return _else_graph; }
+ void else_graph(loco::Graph *else_graph) { _else_graph = else_graph; }
+
+private:
+ uint32_t _output_count{0};
+ int32_t _then_branch{-1};
+ int32_t _else_branch{-1};
+
+ loco::Graph *_then_graph{nullptr};
+ loco::Graph *_else_graph{nullptr};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_IF_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleIfOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleIfOut.h
new file mode 100644
index 000000000..3654e943b
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleIfOut.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_IFOUT_H__
+#define __LUCI_IR_CIRCLE_IFOUT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief Virtual CIRCLEIFOUT in Circle
+ */
+class CircleIfOut final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLEIFOUT>>
+{
+public:
+ CircleIfOut() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t index(void) const { return _index; }
+ void index(int32_t index) { _index = index; }
+
+private:
+ int32_t _index{-1};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_IFOUT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h
index 2c4d60253..4a7d36a4e 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
#include <loco/IR/DataTypeTraits.h>
@@ -33,9 +32,7 @@ namespace luci
* @brief CircleNode used for Input of the Graph
* @note This will not be exported as a specific op
*/
-class CircleInput final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLEINPUT>>,
- public loco::NodeMixin<loco::NodeTrait::DataType>,
- public loco::NodeMixin<loco::NodeTrait::TensorShape>
+class CircleInput final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLEINPUT>>
{
public:
CircleInput() = default;
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Normalize.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Normalize.h
new file mode 100644
index 000000000..efa932d95
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Normalize.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCEL2NORMALIZE_H__
+#define __LUCI_IR_CIRCEL2NORMALIZE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/AttrFusedActFunc.h"
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief L2_NORMALIZATION in Circle
+ */
+class CircleL2Normalize final
+ : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::L2_NORMALIZATION>>,
+ public LuciNodeMixin<LuciNodeTrait::FusedActFunc>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCEL2NORMALIZE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Pool2D.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Pool2D.h
new file mode 100644
index 000000000..7c76ee5d0
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Pool2D.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 __LUCI_IR_CIRCLE_L2_POOL2D_H__
+#define __LUCI_IR_CIRCLE_L2_POOL2D_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/AttrFilter.h"
+#include "luci/IR/AttrPadding.h"
+#include "luci/IR/AttrStride.h"
+#include "luci/IR/AttrFusedActFunc.h"
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief L2_POOL_2D in Circle
+ */
+class CircleL2Pool2D final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::L2_POOL_2D>>,
+ public LuciNodeMixin<LuciNodeTrait::FusedActFunc>
+{
+public:
+ CircleL2Pool2D() : _padding(Padding::UNDEFINED) { /* empty */}
+
+public:
+ loco::Node *value(void) const { return at(0)->node(); }
+ void value(loco::Node *node) { at(0)->node(node); }
+
+ Padding padding() const { return _padding; }
+ void padding(Padding padding) { _padding = padding; }
+
+ const Filter *filter(void) const { return &_filter; }
+ Filter *filter(void) { return &_filter; }
+
+ const Stride *stride(void) const { return &_stride; }
+ Stride *stride(void) { return &_stride; }
+
+private:
+ Padding _padding;
+ Stride _stride;
+ Filter _filter;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_L2_POOL2D_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLeakyRelu.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLeakyRelu.h
new file mode 100644
index 000000000..d6ac97fc0
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLeakyRelu.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_LEAKY_RELU_H__
+#define __LUCI_IR_CIRCLE_LEAKY_RELU_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief LEAKY_RELU in Circle
+ */
+class CircleLeakyRelu final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LEAKY_RELU>>
+{
+public:
+ CircleLeakyRelu() = default;
+
+public:
+ loco::Node *features(void) const { return at(0)->node(); }
+ void features(loco::Node *node) { at(0)->node(node); }
+
+ float alpha() const { return _alpha; }
+ void alpha(float alpha) { _alpha = alpha; }
+
+private:
+ float _alpha = 0.2f;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_LEAKY_RELU_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLess.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLess.h
new file mode 100644
index 000000000..cd6cf1872
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLess.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_LESS_H__
+#define __LUCI_IR_CIRCLE_LESS_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief LESS in Circle
+ */
+class CircleLess final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::LESS>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_LESS_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLessEqual.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLessEqual.h
new file mode 100644
index 000000000..4c7c6a49b
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLessEqual.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_LESSEQUAL_H__
+#define __LUCI_IR_CIRCLE_LESSEQUAL_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief LESS_EQUAL in Circle
+ */
+class CircleLessEqual final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::LESS_EQUAL>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_LESSEQUAL_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLocalResponseNormalization.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLocalResponseNormalization.h
new file mode 100644
index 000000000..8ad2b40fd
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLocalResponseNormalization.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLELOCAL_RESPONSE_NORMALIZATION_H__
+#define __LUCI_IR_CIRCLELOCAL_RESPONSE_NORMALIZATION_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief LOCAL_RESPONSE_NORMALIZATION in Circle
+ */
+class CircleLocalResponseNormalization final
+ : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LOCAL_RESPONSE_NORMALIZATION>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t radius(void) const { return _radius; }
+ void radius(int32_t radius) { _radius = radius; }
+
+ float bias(void) const { return _bias; }
+ void bias(float bias) { _bias = bias; }
+
+ float alpha(void) const { return _alpha; }
+ void alpha(float alpha) { _alpha = alpha; }
+
+ float beta(void) const { return _beta; }
+ void beta(float beta) { _beta = beta; }
+
+private:
+ int32_t _radius{5};
+ float _bias{1.0f};
+ float _alpha{1.0f};
+ float _beta{0.5f};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLELOCAL_RESPONSE_NORMALIZATION_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLog.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLog.h
new file mode 100644
index 000000000..aeb13fed9
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLog.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_LOG_H__
+#define __LUCI_IR_CIRCLE_LOG_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief LOG in Circle
+ */
+class CircleLog final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LOG>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_LOG_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLogSoftmax.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogSoftmax.h
new file mode 100644
index 000000000..5dfd2c1f9
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogSoftmax.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_LOG_SOFTMAX_H__
+#define __LUCI_IR_CIRCLE_LOG_SOFTMAX_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief LOG_SOFTMAX in Circle
+ */
+class CircleLogSoftmax final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LOG_SOFTMAX>>
+{
+public:
+ loco::Node *logits(void) const { return at(0)->node(); }
+ void logits(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_LOG_SOFTMAX_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLogicalAnd.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogicalAnd.h
new file mode 100644
index 000000000..975f6dbc7
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogicalAnd.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_LOGICALAND_H__
+#define __LUCI_IR_CIRCLE_LOGICALAND_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief LOGICAL_AND in Circle
+ */
+class CircleLogicalAnd final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::LOGICAL_AND>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_LOGICALAND_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLogistic.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogistic.h
new file mode 100644
index 000000000..8328cb328
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogistic.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_LOGISTIC_H__
+#define __LUCI_IR_CIRCLE_LOGISTIC_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief LOGISTIC in Circle
+ */
+class CircleLogistic final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LOGISTIC>>
+{
+public:
+ CircleLogistic() = default;
+
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_LOGISTIC_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixDiag.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixDiag.h
new file mode 100644
index 000000000..dca6538c3
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixDiag.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEMATRIXDIAG_H__
+#define __LUCI_IR_CIRCLEMATRIXDIAG_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief MATRIX_DIAG in Circle
+ */
+class CircleMatrixDiag final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::MATRIX_DIAG>>
+{
+public:
+ loco::Node *diagonal(void) const { return at(0)->node(); }
+ void diagonal(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEMATRIXDIAG_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixSetDiag.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixSetDiag.h
new file mode 100644
index 000000000..c1f5f3023
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixSetDiag.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEMATRIXSETDIAG_H__
+#define __LUCI_IR_CIRCLEMATRIXSETDIAG_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief MATRIX_SET_DIAG in Circle
+ */
+class CircleMatrixSetDiag final
+ : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::MATRIX_SET_DIAG>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *diagonal(void) const { return at(1)->node(); }
+ void diagonal(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEMATRIXSETDIAG_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h
index cf7305e3a..6f789bc14 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h
index 6fd791450..7f8aeb5aa 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMinimum.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMinimum.h
new file mode 100644
index 000000000..79d5a6f17
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMinimum.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEMINIMUM_H__
+#define __LUCI_IR_CIRCLEMINIMUM_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief MINIMUM in Circle
+ */
+class CircleMinimum final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::MINIMUM>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEMINIMUM_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMirrorPad.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMirrorPad.h
new file mode 100644
index 000000000..68db8f6f3
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMirrorPad.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_MIRRORPAD_H__
+#define __LUCI_IR_CIRCLE_MIRRORPAD_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+#include "luci/IR/AttrMirrorPadMode.h"
+
+namespace luci
+{
+
+/**
+ * @brief MIRROR_PAD in Circle
+ */
+class CircleMirrorPad final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::MIRROR_PAD>>
+{
+public:
+ CircleMirrorPad() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *paddings(void) const { return at(1)->node(); }
+ void paddings(loco::Node *node) { at(1)->node(node); }
+
+public:
+ MirrorPadMode mode(void) const { return _mode; }
+ void mode(MirrorPadMode mode) { _mode = mode; }
+
+private:
+ MirrorPadMode _mode{MirrorPadMode::REFLECT};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_MIRRORPAD_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleNeg.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleNeg.h
new file mode 100644
index 000000000..4149ac4a7
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleNeg.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLENEG_H__
+#define __LUCI_IR_CIRCLENEG_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief NEG in Circle
+ */
+class CircleNeg final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::NEG>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLENEG_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleNotEqual.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleNotEqual.h
new file mode 100644
index 000000000..cca7a5e22
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleNotEqual.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_NOTEQUAL_H__
+#define __LUCI_IR_CIRCLE_NOTEQUAL_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief NOT EQUAL in Circle
+ */
+class CircleNotEqual final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::NOT_EQUAL>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_NOTEQUAL_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleOneHot.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleOneHot.h
new file mode 100644
index 000000000..665e01d48
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleOneHot.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 __LUCI_IR_CIRCLEONEHOT_H__
+#define __LUCI_IR_CIRCLEONEHOT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief ONEHOT in Circle
+ */
+class CircleOneHot final : public FixedArityNode<4, CircleNodeImpl<CircleOpcode::ONE_HOT>>
+{
+public:
+ loco::Node *indices(void) const { return at(0)->node(); }
+ void indices(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *depth(void) const { return at(1)->node(); }
+ void depth(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *on_value(void) const { return at(2)->node(); }
+ void on_value(loco::Node *node) { at(2)->node(node); }
+
+ loco::Node *off_value(void) const { return at(3)->node(); }
+ void off_value(loco::Node *node) { at(3)->node(node); }
+
+public:
+ int32_t axis(void) const { return _axis; }
+ void axis(int32_t axis) { _axis = axis; }
+
+private:
+ int32_t _axis = -1;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEONEHOT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h
index c65317ad1..67e55f1a1 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
#include <loco/IR/GraphOutputIndex.h>
@@ -50,6 +49,27 @@ private:
int64_t _index = -1; // Uninitialized
};
+/**
+ * @brief Temporary DummyNode used with dangle CircleNode
+ */
+// TODO remove CircleOutputDummy
+class CircleOutputDummy final
+ : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLEOUTPUTDUMMY>>
+{
+public:
+ CircleOutputDummy() = default;
+};
+
+/**
+ * @brief CircleOutputExclude is used to specifying not exported nodes
+ */
+class CircleOutputExclude final
+ : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLEOUTPUTEXCLUDE>>
+{
+public:
+ CircleOutputExclude() = default;
+};
+
} // namespace luci
#endif // __LUCI_IR_CIRCLEOUTPUT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CirclePRelu.h b/compiler/luci/lang/include/luci/IR/Nodes/CirclePRelu.h
new file mode 100644
index 000000000..693777512
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CirclePRelu.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_PRELU_H__
+#define __LUCI_IR_PRELU_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief PRelu in Circle
+ */
+class CirclePRelu final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::PRELU>>
+{
+public:
+ CirclePRelu() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *alpha(void) const { return at(1)->node(); }
+ void alpha(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_PRELU_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CirclePow.h b/compiler/luci/lang/include/luci/IR/Nodes/CirclePow.h
new file mode 100644
index 000000000..006e3dd86
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CirclePow.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_POW_H__
+#define __LUCI_IR_POW_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief POW in Circle
+ */
+class CirclePow final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::POW>>
+{
+public:
+ CirclePow() = default;
+
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *y(void) const { return at(1)->node(); }
+ void y(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_POW_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRange.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRange.h
new file mode 100644
index 000000000..977a37a52
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRange.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLERANGE_H__
+#define __LUCI_IR_CIRCLERANGE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief RANGE in Circle
+ */
+class CircleRange final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::RANGE>>
+{
+public:
+ loco::Node *start(void) const { return at(0)->node(); }
+ void start(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *limit(void) const { return at(1)->node(); }
+ void limit(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *delta(void) const { return at(2)->node(); }
+ void delta(loco::Node *node) { at(2)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLERANGE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRank.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRank.h
new file mode 100644
index 000000000..ba6d67f69
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRank.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLERANK_H__
+#define __LUCI_IR_CIRCLERANK_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief RANK in Circle
+ */
+class CircleRank final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::RANK>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLERANK_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceAny.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceAny.h
new file mode 100644
index 000000000..0456be863
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceAny.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_REDUCE_ANY_H__
+#define __LUCI_IR_CIRCLE_REDUCE_ANY_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief REDUCE_ANY in Circle
+ */
+class CircleReduceAny final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REDUCE_ANY>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *reduction_indices(void) const { return at(1)->node(); }
+ void reduction_indices(loco::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 luci
+
+#endif // __LUCI_IR_CIRCLE_REDUCE_ANY_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMax.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMax.h
new file mode 100644
index 000000000..925c977e5
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMax.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_REDUCE_MAX_H__
+#define __LUCI_IR_CIRCLE_REDUCE_MAX_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief REDUCE_MAX in Circle
+ */
+class CircleReduceMax final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REDUCE_MAX>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *reduction_indices(void) const { return at(1)->node(); }
+ void reduction_indices(loco::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 luci
+
+#endif // __LUCI_IR_CIRCLE_REDUCE_MAX_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMin.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMin.h
new file mode 100644
index 000000000..fd789ae5e
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMin.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_REDUCE_MIN_H__
+#define __LUCI_IR_CIRCLE_REDUCE_MIN_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief REDUCE_MIN in Circle
+ */
+class CircleReduceMin final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REDUCE_MIN>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *reduction_indices(void) const { return at(1)->node(); }
+ void reduction_indices(loco::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 luci
+
+#endif // __LUCI_IR_CIRCLE_REDUCE_MIN_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceProd.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceProd.h
new file mode 100644
index 000000000..b7d226255
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceProd.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_REDUCE_PROD_H__
+#define __LUCI_IR_CIRCLE_REDUCE_PROD_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief REDUCE_PROD in Circle
+ */
+class CircleReduceProd final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REDUCE_PROD>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *reduction_indices(void) const { return at(1)->node(); }
+ void reduction_indices(loco::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 luci
+
+#endif // __LUCI_IR_CIRCLE_REDUCE_PROD_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h
index afb2c667a..91272d2bf 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h
index b313a5557..b4274ded9 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReluN1To1.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReluN1To1.h
new file mode 100644
index 000000000..a5c5710c2
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReluN1To1.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_RELU_N1_TO_1_H__
+#define __LUCI_IR_CIRCLE_RELU_N1_TO_1_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief RELU_N1_TO_1 in Circle
+ */
+class CircleReluN1To1 final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::RELU_N1_TO_1>>
+{
+public:
+ CircleReluN1To1() = default;
+
+public:
+ loco::Node *features(void) const { return at(0)->node(); }
+ void features(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_RELU_N1_TO_1_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h
index a3a2a3f31..b13144f7e 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
@@ -38,8 +37,8 @@ public:
loco::Node *tensor(void) const { return at(0)->node(); }
void tensor(loco::Node *node) { at(0)->node(node); }
- // TODO Make this input optional. That is, loco system does not emit error
- // with this input being null
+ // NOTE shape is optional and can be CircleConst or any other type
+ // and also can be CircleOutputDummy when reshape option does not exist
loco::Node *shape(void) const { return at(1)->node(); }
void shape(loco::Node *node) { at(1)->node(node); }
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeBilinear.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeBilinear.h
new file mode 100644
index 000000000..3c8223338
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeBilinear.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLERESIZE_BILINEAR_H__
+#define __LUCI_IR_CIRCLERESIZE_BILINEAR_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief RESIZE_BILINEAR in Circle
+ */
+class CircleResizeBilinear final
+ : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::RESIZE_BILINEAR>>
+{
+public:
+ CircleResizeBilinear() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *size(void) const { return at(1)->node(); }
+ void size(loco::Node *node) { at(1)->node(node); }
+
+ bool align_corners() const { return _align_corners; }
+ void align_corners(bool value) { _align_corners = value; }
+
+ bool half_pixel_centers() const { return _half_pixel_centers; }
+ void half_pixel_centers(bool value) { _half_pixel_centers = value; }
+
+private:
+ bool _align_corners = false;
+ bool _half_pixel_centers = false;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLERESIZE_BILINEAR_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeNearestNeighbor.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeNearestNeighbor.h
new file mode 100644
index 000000000..dc32ebee7
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeNearestNeighbor.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLERESSIZE_NEAREST_NEIGHBOR_H__
+#define __LUCI_IR_CIRCLERESSIZE_NEAREST_NEIGHBOR_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief RESIZE_NEAREST_NEIGHBOR in Circle
+ */
+class CircleResizeNearestNeighbor final
+ : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::RESIZE_NEAREST_NEIGHBOR>>
+{
+public:
+ CircleResizeNearestNeighbor() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *size(void) const { return at(1)->node(); }
+ void size(loco::Node *node) { at(1)->node(node); }
+
+ bool align_corners() const { return _align_corners; }
+ void align_corners(bool value) { _align_corners = value; }
+
+private:
+ bool _align_corners = false;
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLERESSIZE_NEAREST_NEIGHBOR_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseSequence.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseSequence.h
new file mode 100644
index 000000000..b0766dd3e
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseSequence.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEREVERSESEQUENCE_H__
+#define __LUCI_IR_CIRCLEREVERSESEQUENCE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief REVERSE_SEQUENCE in Circle
+ */
+class CircleReverseSequence final
+ : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REVERSE_SEQUENCE>>
+{
+public:
+ CircleReverseSequence() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *seq_lengths(void) const { return at(1)->node(); }
+ void seq_lengths(loco::Node *node) { at(1)->node(node); }
+
+public:
+ int seq_axis(void) const { return _seq_axis; }
+ void seq_axis(int seq_axis) { _seq_axis = seq_axis; }
+
+ int batch_axis(void) const { return _batch_axis; }
+ void batch_axis(int batch_axis) { _batch_axis = batch_axis; }
+
+private:
+ int _seq_axis{0};
+ int _batch_axis{0};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEREVERSESEQUENCE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseV2.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseV2.h
new file mode 100644
index 000000000..71d9f65aa
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseV2.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEREVERSE_V2_H__
+#define __LUCI_IR_CIRCLEREVERSE_V2_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief ReverseV2 in Circle
+ */
+class CircleReverseV2 final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REVERSE_V2>>
+{
+public:
+ loco::Node *tensor(void) const { return at(0)->node(); }
+ void tensor(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *axis(void) const { return at(1)->node(); }
+ void axis(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEREVERSE_V2_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRound.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRound.h
new file mode 100644
index 000000000..30296ce9e
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRound.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLEROUND_H__
+#define __LUCI_IR_CIRCLEROUND_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief ROUND in Circle
+ */
+class CircleRound final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::ROUND>>
+{
+public:
+ CircleRound() = default;
+
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLEROUND_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h
index 44d22ef22..873397bce 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleScatterNd.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleScatterNd.h
new file mode 100644
index 000000000..9f93a0a80
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleScatterNd.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLESCATTER_ND_H__
+#define __LUCI_IR_CIRCLESCATTER_ND_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SCATTER_ND in Circle
+ */
+class CircleScatterNd final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SCATTER_ND>>
+{
+public:
+ loco::Node *indices(void) const { return at(0)->node(); }
+ void indices(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *updates(void) const { return at(1)->node(); }
+ void updates(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *shape(void) const { return at(2)->node(); }
+ void shape(loco::Node *node) { at(2)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLESCATTER_ND_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSegmentSum.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSegmentSum.h
new file mode 100644
index 000000000..416d617b2
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSegmentSum.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SEGMENT_SUM_H__
+#define __LUCI_IR_CIRCLE_SEGMENT_SUM_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SEGMENT_SUM in Circle
+ */
+class CircleSegmentSum final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::SEGMENT_SUM>>
+{
+public:
+ CircleSegmentSum() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *segment_ids(void) const { return at(1)->node(); }
+ void segment_ids(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SEGMENT_SUM_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSelect.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSelect.h
new file mode 100644
index 000000000..727647168
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSelect.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SELECT_H__
+#define __LUCI_IR_CIRCLE_SELECT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SELECT in Circle
+ */
+class CircleSelect final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SELECT>>
+{
+public:
+ CircleSelect() = default;
+
+public:
+ loco::Node *condition(void) const { return at(0)->node(); }
+ void condition(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *t(void) const { return at(1)->node(); }
+ void t(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *e(void) const { return at(2)->node(); }
+ void e(loco::Node *node) { at(2)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SELECT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSelectV2.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSelectV2.h
new file mode 100644
index 000000000..7ac3c0524
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSelectV2.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SELECT_V2_H__
+#define __LUCI_IR_CIRCLE_SELECT_V2_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SELECT_V2 in Circle
+ */
+class CircleSelectV2 final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SELECT_V2>>
+{
+public:
+ CircleSelectV2() = default;
+
+public:
+ loco::Node *condition(void) const { return at(0)->node(); }
+ void condition(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *t(void) const { return at(1)->node(); }
+ void t(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *e(void) const { return at(2)->node(); }
+ void e(loco::Node *node) { at(2)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SELECT_V2_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleShape.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleShape.h
new file mode 100644
index 000000000..ff20ce684
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleShape.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SHAPE_H__
+#define __LUCI_IR_CIRCLE_SHAPE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SHAPE in Circle
+ */
+class CircleShape final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SHAPE>>
+{
+public:
+ CircleShape() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ loco::DataType out_type(void) const { return _out_type; }
+ void out_type(loco::DataType ot) { _out_type = ot; }
+
+private:
+ loco::DataType _out_type{loco::DataType::S32};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SHAPE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSin.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSin.h
new file mode 100644
index 000000000..5624db253
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSin.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SIN_H__
+#define __LUCI_IR_CIRCLE_SIN_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SIN in Circle
+ */
+class CircleSin final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SIN>>
+{
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SIN_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSlice.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSlice.h
new file mode 100644
index 000000000..a2113643d
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSlice.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_SLICE_H__
+#define __LUCI_IR_SLICE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SLICE in Circle
+ */
+class CircleSlice final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SLICE>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *begin(void) const { return at(1)->node(); }
+ void begin(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *size(void) const { return at(2)->node(); }
+ void size(loco::Node *node) { at(2)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_SLICE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h
index 4ea3c4b0e..7166a329b 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h
@@ -39,7 +39,7 @@ public:
void beta(float beta) { _beta = beta; }
private:
- float _beta;
+ float _beta{0.0f};
};
} // namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToBatchND.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToBatchND.h
new file mode 100644
index 000000000..042ebffcd
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToBatchND.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SPACETOBATCHND_H__
+#define __LUCI_IR_CIRCLE_SPACETOBATCHND_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SPACE_TO_BATCH_ND in Circle
+ */
+class CircleSpaceToBatchND final
+ : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SPACE_TO_BATCH_ND>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *block_shape(void) const { return at(1)->node(); }
+ void block_shape(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *paddings(void) const { return at(2)->node(); }
+ void paddings(loco::Node *node) { at(2)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SPACETOBATCHND_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToDepth.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToDepth.h
new file mode 100644
index 000000000..420a4cb96
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToDepth.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SPACETODEPTH_H__
+#define __LUCI_IR_CIRCLE_SPACETODEPTH_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SPACE_TO_DEPTH in Circle
+ */
+class CircleSpaceToDepth final
+ : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SPACE_TO_DEPTH>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int block_size(void) const { return _block_size; }
+ void block_size(int block_size) { _block_size = block_size; }
+
+private:
+ int _block_size{0};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SPACETODEPTH_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSparseToDense.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSparseToDense.h
new file mode 100644
index 000000000..9f5051317
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSparseToDense.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCELSPARSETODENSE_H__
+#define __LUCI_IR_CIRCELSPARSETODENSE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SPARSE_TO_DENSE in Circle
+ */
+class CircleSparseToDense final
+ : public FixedArityNode<4, CircleNodeImpl<CircleOpcode::SPARSE_TO_DENSE>>
+{
+public:
+ loco::Node *indices(void) const { return at(0)->node(); }
+ void indices(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *output_shape(void) const { return at(1)->node(); }
+ void output_shape(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *values(void) const { return at(2)->node(); }
+ void values(loco::Node *node) { at(2)->node(node); }
+
+ loco::Node *default_value(void) const { return at(3)->node(); }
+ void default_value(loco::Node *node) { at(3)->node(node); }
+
+public:
+ bool validate_indices(void) const { return _validate_indices; }
+ void validate_indices(bool validate_indices) { _validate_indices = validate_indices; }
+
+private:
+ bool _validate_indices{true};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCELSPARSETODENSE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSplit.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplit.h
new file mode 100644
index 000000000..0eda19501
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplit.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SPLIT_H__
+#define __LUCI_IR_CIRCLE_SPLIT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SPLIT in Circle
+ */
+class CircleSplit final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::SPLIT>>
+{
+public:
+ loco::Node *split_dim(void) const { return at(0)->node(); }
+ void split_dim(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *input(void) const { return at(1)->node(); }
+ void input(loco::Node *node) { at(1)->node(node); }
+
+public:
+ // NOTE it is num_split() not num_splits() as we follow TF name
+ int32_t num_split(void) const { return _num_split; }
+ void num_split(int32_t num_split) { _num_split = num_split; }
+
+private:
+ int32_t _num_split{0};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SPLIT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitOut.h
new file mode 100644
index 000000000..6bf4a9fef
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitOut.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SPLITOUT_H__
+#define __LUCI_IR_CIRCLE_SPLITOUT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief Virtual CIRCLESPLITOUT in Circle
+ */
+class CircleSplitOut final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLESPLITOUT>>
+{
+public:
+ CircleSplitOut() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t index(void) const { return _index; }
+ void index(int32_t index) { _index = index; }
+
+private:
+ int32_t _index{-1};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SPLITOUT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitV.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitV.h
new file mode 100644
index 000000000..1b7d55534
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitV.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SPLIT_V_H__
+#define __LUCI_IR_CIRCLE_SPLIT_V_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SPLIT_V in Circle
+ */
+class CircleSplitV final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SPLIT_V>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *size_splits(void) const { return at(1)->node(); }
+ void size_splits(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *split_dim(void) const { return at(2)->node(); }
+ void split_dim(loco::Node *node) { at(2)->node(node); }
+
+public:
+ // NOTE it is num_split() not num_splits() as we follow TF name
+ int32_t num_split(void) const { return _num_split; }
+ void num_split(int32_t num_split) { _num_split = num_split; }
+
+private:
+ int32_t _num_split{0};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SPLIT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitVOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitVOut.h
new file mode 100644
index 000000000..d3b2f1e5a
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitVOut.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_SPLITVOUT_H__
+#define __LUCI_IR_CIRCLE_SPLITVOUT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief Virtual CIRCLESPLITVOUT in Circle
+ */
+class CircleSplitVOut final
+ : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLESPLITVOUT>>
+{
+public:
+ CircleSplitVOut() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t index(void) const { return _index; }
+ void index(int32_t index) { _index = index; }
+
+private:
+ int32_t _index{-1};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_SPLITVOUT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h
index bc1f39d90..c96ca8498 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSquare.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSquare.h
new file mode 100644
index 000000000..a29edfe82
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSquare.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLESQUARE_H__
+#define __LUCI_IR_CIRCLESQUARE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SQUARE in Circle
+ */
+class CircleSquare final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SQUARE>>
+{
+public:
+ CircleSquare() = default;
+
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLESQUARE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h
index ff337dfbe..b5b39f920 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSqueeze.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSqueeze.h
new file mode 100644
index 000000000..f175f1411
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSqueeze.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLESQUEEZE_H__
+#define __LUCI_IR_CIRCLESQUEEZE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SQUEEZE in Circle
+ */
+class CircleSqueeze final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SQUEEZE>>
+{
+public:
+ CircleSqueeze() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ const std::vector<int32_t> &squeeze_dims() const { return _squeeze_dims; }
+ void squeeze_dims(const std::vector<int32_t> &squeeze_dims) { _squeeze_dims = squeeze_dims; };
+
+private:
+ std::vector<int32_t> _squeeze_dims{};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLESQUEEZE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleStridedSlice.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleStridedSlice.h
new file mode 100644
index 000000000..98799fec1
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleStridedSlice.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_STRIDEDSLICE_H__
+#define __LUCI_IR_STRIDEDSLICE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief STRIDED_SLICE in Circle
+ */
+class CircleStridedSlice final
+ : public FixedArityNode<4, CircleNodeImpl<CircleOpcode::STRIDED_SLICE>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *begin(void) const { return at(1)->node(); }
+ void begin(loco::Node *node) { at(1)->node(node); }
+
+ loco::Node *end(void) const { return at(2)->node(); }
+ void end(loco::Node *node) { at(2)->node(node); }
+
+ loco::Node *strides(void) const { return at(3)->node(); }
+ void strides(loco::Node *node) { at(3)->node(node); }
+
+public:
+ int32_t begin_mask() const { return _begin_mask; }
+ void begin_mask(int32_t mask) { _begin_mask = mask; }
+
+ int32_t end_mask() const { return _end_mask; }
+ void end_mask(int32_t mask) { _end_mask = mask; }
+
+ int32_t ellipsis_mask() const { return _ellipsis_mask; }
+ void ellipsis_mask(int32_t mask) { _ellipsis_mask = mask; }
+
+ int32_t new_axis_mask() const { return _new_axis_mask; }
+ void new_axis_mask(int32_t mask) { _new_axis_mask = mask; }
+
+ int32_t shrink_axis_mask() const { return _shrink_axis_mask; }
+ void shrink_axis_mask(int32_t mask) { _shrink_axis_mask = 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 luci
+
+#endif // __LUCI_IR_STRIDEDSLICE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSum.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSum.h
new file mode 100644
index 000000000..21faa76fe
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSum.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLESUM_H__
+#define __LUCI_IR_CIRCLESUM_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief SUM in Circle
+ */
+class CircleSum final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::SUM>>
+{
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *reduction_indices(void) const { return at(1)->node(); }
+ void reduction_indices(loco::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 luci
+
+#endif // __LUCI_IR_CIRCLESUM_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTanh.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTanh.h
new file mode 100644
index 000000000..f7444921f
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTanh.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLETANH_H__
+#define __LUCI_IR_CIRCLETANH_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief TANH in Circle
+ */
+class CircleTanh final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::TANH>>
+{
+public:
+ CircleTanh() = default;
+
+public:
+ loco::Node *x(void) const { return at(0)->node(); }
+ void x(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLETANH_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTile.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTile.h
new file mode 100644
index 000000000..96e1f69c6
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTile.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLETILE_H__
+#define __LUCI_IR_CIRCLETILE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief TILE in Circle
+ */
+class CircleTile final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::TILE>>
+{
+public:
+ CircleTile() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *multiples(void) const { return at(1)->node(); }
+ void multiples(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLETILE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2.h
new file mode 100644
index 000000000..3b2b5abb7
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_TOPK_V2_H__
+#define __LUCI_IR_CIRCLE_TOPK_V2_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief TOPK_V2 in Circle
+ */
+class CircleTopKV2 final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::TOPK_V2>>
+{
+public:
+ CircleTopKV2() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+ loco::Node *k(void) const { return at(1)->node(); }
+ void k(loco::Node *node) { at(1)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_TOPK_V2_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2Out.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2Out.h
new file mode 100644
index 000000000..5a6dd0c02
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2Out.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_TOPK_V2_OUT_H__
+#define __LUCI_IR_CIRCLE_TOPK_V2_OUT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief Virtual CIRCLETOPKV2OUT in Circle
+ */
+class CircleTopKV2Out final
+ : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLETOPKV2OUT>>
+{
+public:
+ CircleTopKV2Out() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t index(void) const { return _index; }
+ void index(int32_t index) { _index = index; }
+
+private:
+ int32_t _index{-1};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_TOPK_V2_OUT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h
index 198b56afd..095cd6746 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h
@@ -20,7 +20,6 @@
#include "luci/IR/CircleNodeDecl.h"
#include "luci/IR/CircleOpcode.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h
index 54a0d010c..fc638d49f 100644
--- a/compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h
@@ -22,7 +22,6 @@
#include "luci/IR/AttrPadding.h"
#include "luci/IR/AttrStride.h"
-#include "luci/IR/AttrFusedActFunc.h"
#include "luci/IR/LuciNodeMixins.h"
namespace luci
@@ -55,7 +54,7 @@ public:
Stride *stride(void) { return &_stride; }
private:
- Padding _padding;
+ Padding _padding{Padding::UNDEFINED};
Stride _stride;
};
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpack.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpack.h
new file mode 100644
index 000000000..cb91d7e6a
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpack.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_UNPACK_H__
+#define __LUCI_IR_CIRCLE_UNPACK_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief UNPACK in Circle
+ */
+class CircleUnpack final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::UNPACK>>
+{
+public:
+ CircleUnpack() = default;
+
+public:
+ loco::Node *value(void) const { return at(0)->node(); }
+ void value(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t num(void) const { return _num; }
+ void num(int32_t num) { _num = num; }
+
+ int32_t axis(void) const { return _axis; }
+ void axis(int32_t axis) { _axis = axis; }
+
+private:
+ int32_t _num{0};
+ int32_t _axis{0};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_UNPACK_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpackOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpackOut.h
new file mode 100644
index 000000000..6f24578a1
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpackOut.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_UNPACKOUT_H__
+#define __LUCI_IR_CIRCLE_UNPACKOUT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief Virtual CIRCLEUNPACKOUT in Circle
+ */
+class CircleUnpackOut final
+ : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLEUNPACKOUT>>
+{
+public:
+ CircleUnpackOut() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t index(void) const { return _index; }
+ void index(int32_t index) { _index = index; }
+
+private:
+ int32_t _index{0};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_UNPACKOUT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleWhere.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhere.h
new file mode 100644
index 000000000..51eda3d6e
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhere.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_WHERE_H__
+#define __LUCI_IR_CIRCLE_WHERE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+#include <cassert>
+
+namespace luci
+{
+
+/**
+ * @brief WHERE in Circle
+ */
+class CircleWhere final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::WHERE>>
+{
+public:
+ CircleWhere() = default;
+
+public:
+ loco::Node *condition() const { return at(0)->node(); }
+ void condition(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_WHERE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleWhile.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhile.h
new file mode 100644
index 000000000..40ec96414
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhile.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_WHILE_H__
+#define __LUCI_IR_CIRCLE_WHILE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/VariadicArityNode.h"
+
+#include <cassert>
+
+namespace luci
+{
+
+/**
+ * @brief WHILE in Circle
+ */
+class CircleWhile final : public VariadicArityNode<CircleNodeImpl<CircleOpcode::WHILE>>
+{
+public:
+ CircleWhile(uint32_t arity, uint32_t out)
+ : VariadicArityNode<CircleNodeImpl<CircleOpcode::WHILE>>(arity), _output_count(out)
+ {
+ assert(arity > 0);
+ assert(out > 0);
+
+ // input and output must have the same size
+ assert(arity == out);
+ }
+
+public:
+ uint32_t input_count(void) const { return arity(); }
+ uint32_t output_count(void) const { return _output_count; }
+
+public:
+ Node *input(uint32_t index) const { return at(index)->node(); }
+ void input(uint32_t index, Node *node) { at(index)->node(node); }
+
+public:
+ int32_t cond_branch(void) const { return _cond_branch; }
+ void cond_branch(int32_t cond_branch) { _cond_branch = cond_branch; }
+
+ int32_t body_branch(void) const { return _body_branch; }
+ void body_branch(int32_t body_branch) { _body_branch = body_branch; }
+
+public:
+ loco::Graph *cond_graph(void) const { return _cond_graph; }
+ void cond_graph(loco::Graph *cond_graph) { _cond_graph = cond_graph; }
+
+ loco::Graph *body_graph(void) const { return _body_graph; }
+ void body_graph(loco::Graph *body_graph) { _body_graph = body_graph; }
+
+private:
+ uint32_t _output_count{0};
+ int32_t _cond_branch{-1};
+ int32_t _body_branch{-1};
+
+ loco::Graph *_cond_graph{nullptr};
+ loco::Graph *_body_graph{nullptr};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_WHILE_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleWhileOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhileOut.h
new file mode 100644
index 000000000..cdf617848
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhileOut.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_WHILEOUT_H__
+#define __LUCI_IR_CIRCLE_WHILEOUT_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief Virtual CIRCLEWHILEOUT in Circle
+ */
+class CircleWhileOut final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLEWHILEOUT>>
+{
+public:
+ CircleWhileOut() = default;
+
+public:
+ loco::Node *input(void) const { return at(0)->node(); }
+ void input(loco::Node *node) { at(0)->node(node); }
+
+public:
+ int32_t index(void) const { return _index; }
+ void index(int32_t index) { _index = index; }
+
+private:
+ int32_t _index{-1};
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_WHILEOUT_H__
diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleZerosLike.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleZerosLike.h
new file mode 100644
index 000000000..d3b6d272a
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleZerosLike.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_CIRCLE_ZEROS_LIKE_H__
+#define __LUCI_IR_CIRCLE_ZEROS_LIKE_H__
+
+#include "luci/IR/CircleNodeDecl.h"
+#include "luci/IR/CircleOpcode.h"
+
+#include "luci/IR/LuciNodeMixins.h"
+
+namespace luci
+{
+
+/**
+ * @brief ZEROS_LIKE in Circle
+ */
+class CircleZerosLike final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::ZEROS_LIKE>>
+{
+public:
+ CircleZerosLike() = default;
+
+public:
+ /// @brief Get the input node
+ loco::Node *input(void) const { return at(0)->node(); }
+
+ /// @brief Set the input node
+ void input(loco::Node *node) { at(0)->node(node); }
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_CIRCLE_ZEROS_LIKE_H__
diff --git a/compiler/luci/lang/include/luci/IR/PropertyShapeStatus.h b/compiler/luci/lang/include/luci/IR/PropertyShapeStatus.h
new file mode 100644
index 000000000..179a8ab3c
--- /dev/null
+++ b/compiler/luci/lang/include/luci/IR/PropertyShapeStatus.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_IR_PROPERTY_SHAPE_STATUS_H__
+#define __LUCI_IR_PROPERTY_SHAPE_STATUS_H__
+
+namespace luci
+{
+
+/**
+ * @brief ShapeStatus is to remember circle node shape status.
+ * @note This is not an attribute from the file but inner status of a node.
+ * Shape with [] is scalar but sometimes it acts as dynamic shape.
+ */
+enum class ShapeStatus
+{
+ UNDEFINED, // Shape status is undefined
+
+ NOSHAPE, // shape is unknown; to distinguish from scalar
+ VALID, // shape is valid
+};
+
+} // namespace luci
+
+#endif // __LUCI_IR_PROPERTY_SHAPE_STATUS_H__
diff --git a/compiler/luci/lang/include/luci/IR/VariadicArityNode.h b/compiler/luci/lang/include/luci/IR/VariadicArityNode.h
index a4814ee48..e83d90978 100644
--- a/compiler/luci/lang/include/luci/IR/VariadicArityNode.h
+++ b/compiler/luci/lang/include/luci/IR/VariadicArityNode.h
@@ -46,11 +46,7 @@ public:
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();
- }
+ loco::Node *arg(uint32_t n) const final { return _args.at(n)->node(); }
void drop(void) final
{
@@ -62,11 +58,7 @@ public:
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();
- }
+ loco::Use *at(uint32_t n) const { return _args.at(n).get(); }
private:
std::vector<std::unique_ptr<loco::Use>> _args;
diff --git a/compiler/luci/lang/src/CircleDialect.cpp b/compiler/luci/lang/src/CircleDialect.cpp
index e1c925de4..42ca3c917 100644
--- a/compiler/luci/lang/src/CircleDialect.cpp
+++ b/compiler/luci/lang/src/CircleDialect.cpp
@@ -22,6 +22,8 @@
#include <loco/IR/GraphInputIndex.h>
#include <loco/IR/GraphOutputIndex.h>
+#include "DeadNodeQueryService.h"
+
#include <cassert>
#include <memory>
@@ -42,8 +44,7 @@ struct GiiQueryServiceImpl final : public loco::GraphInputIndexQueryService
loco::GraphOutputIndex index(const loco::Node *node) const final
{
assert(associated(node));
- auto circleinput = dynamic_cast<const luci::CircleInput *>(node);
- assert(circleinput != nullptr);
+ auto circleinput = loco::must_cast<const luci::CircleInput *>(node);
return circleinput->index();
}
};
@@ -62,8 +63,7 @@ struct GoiQueryServiceImpl final : public loco::GraphOutputIndexQueryService
loco::GraphOutputIndex index(const loco::Node *node) const final
{
assert(associated(node));
- auto circleoutput = dynamic_cast<const luci::CircleOutput *>(node);
- assert(circleoutput != nullptr);
+ auto circleoutput = loco::must_cast<const luci::CircleOutput *>(node);
return circleoutput->index();
}
};
@@ -77,6 +77,7 @@ CircleDialect::CircleDialect()
{
service<loco::GraphInputIndexQueryService>(std::make_unique<GiiQueryServiceImpl>());
service<loco::GraphOutputIndexQueryService>(std::make_unique<GoiQueryServiceImpl>());
+ service<logo::DeadNodeQueryService>(std::make_unique<DeadNodeQueryServiceImpl>());
}
loco::Dialect *CircleDialect::get(void)
diff --git a/compiler/luci/lang/src/CircleDialect.test.cpp b/compiler/luci/lang/src/CircleDialect.test.cpp
index 78221f199..a09c105ec 100644
--- a/compiler/luci/lang/src/CircleDialect.test.cpp
+++ b/compiler/luci/lang/src/CircleDialect.test.cpp
@@ -15,6 +15,10 @@
*/
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodes.h"
+
+#include <loco.h>
+#include <logo/DeadNodeQueryService.h>
#include <gtest/gtest.h>
@@ -25,10 +29,59 @@ TEST(CircleDialectTest, get_P)
// get() SHOULD return a valid(non-null) pointer
ASSERT_NE(d, nullptr);
// The return value SHOULD be stable across multiple invocations
- ASSERT_EQ(d, luci::CircleDialect::get());
+ ASSERT_EQ(luci::CircleDialect::get(), d);
}
-TEST(CircleDialectTest, get_N)
+TEST(CircleDialectTest, check_if_dead_node_service)
{
- // TBD
+ /**
+ * [CircleInput1] [CircleInput2] [CircleInput3]
+ * \ / (dangling input)
+ * \ /
+ * [CircleAdd] [CircleBatchMatMul]
+ * | (dangling node)
+ * |
+ * [CircleOutput1] [CircleOutput2]
+ * (dangling output)
+ */
+ auto g = loco::make_graph();
+
+ auto graph_input1 = g->inputs()->create();
+ auto circle_input1 = g->nodes()->create<luci::CircleInput>();
+ circle_input1->index(graph_input1->index());
+
+ auto graph_input2 = g->inputs()->create();
+ auto circle_input2 = g->nodes()->create<luci::CircleInput>();
+ circle_input2->index(graph_input2->index());
+
+ // dangling output
+ auto graph_input3 = g->inputs()->create();
+ auto dangling_input = g->nodes()->create<luci::CircleInput>();
+ dangling_input->index(graph_input3->index());
+
+ auto active_node = g->nodes()->create<luci::CircleAdd>();
+ active_node->x(circle_input1);
+ active_node->y(circle_input2);
+
+ auto dangling_node = g->nodes()->create<luci::CircleBatchMatMul>();
+
+ auto graph_output1 = g->outputs()->create();
+ auto circle_output1 = g->nodes()->create<luci::CircleOutput>();
+ circle_output1->index(graph_output1->index());
+ circle_output1->from(active_node);
+
+ // dangling output
+ auto graph_output2 = g->outputs()->create();
+ auto circle_output2 = g->nodes()->create<luci::CircleOutput>();
+ circle_output2->index(graph_output2->index());
+
+ auto service = active_node->dialect()->service<logo::DeadNodeQueryService>();
+
+ ASSERT_TRUE(service->isDeadNode(dangling_node));
+ ASSERT_FALSE(service->isDeadNode(dangling_input));
+ ASSERT_FALSE(service->isDeadNode(active_node));
+ ASSERT_FALSE(service->isDeadNode(circle_input1));
+ ASSERT_FALSE(service->isDeadNode(circle_input2));
+ ASSERT_FALSE(service->isDeadNode(circle_output1));
+ ASSERT_FALSE(service->isDeadNode(circle_output2));
}
diff --git a/compiler/luci/lang/src/CircleNodeShapeDtype.test.cpp b/compiler/luci/lang/src/CircleNodeShapeDtype.test.cpp
new file mode 100644
index 000000000..61eab4b77
--- /dev/null
+++ b/compiler/luci/lang/src/CircleNodeShapeDtype.test.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/CircleNodes.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleNodeShapeDTypeTest, constructor)
+{
+ luci::CircleAdd node;
+
+ ASSERT_EQ(loco::DataType::Unknown, node.dtype());
+ ASSERT_EQ(0, node.rank());
+}
+
+TEST(CircleNodeShapeDTypeTest, values)
+{
+ luci::CircleAdd node;
+
+ node.dtype(loco::DataType::FLOAT32);
+ ASSERT_EQ(loco::DataType::FLOAT32, node.dtype());
+
+ node.rank(4);
+ ASSERT_EQ(4, node.rank());
+ ASSERT_FALSE(node.dim(0).known());
+
+ node.dim(0) = loco::Dimension(1);
+ ASSERT_TRUE(node.dim(0).known());
+ ASSERT_EQ(1, node.dim(0).value());
+}
+
+TEST(CircleNodeShapeDTypeTest, values_NEG)
+{
+ luci::CircleAdd node;
+
+ node.rank(4);
+ EXPECT_ANY_THROW(node.dim(100).known());
+ EXPECT_ANY_THROW(node.dim(100) = loco::Dimension(1));
+}
diff --git a/compiler/luci/lang/src/CircleNodes.cpp b/compiler/luci/lang/src/CircleNodes.cpp
index 76ff7ec5a..c77c06861 100644
--- a/compiler/luci/lang/src/CircleNodes.cpp
+++ b/compiler/luci/lang/src/CircleNodes.cpp
@@ -37,6 +37,7 @@ void set_new_shape(CircleReshape *node, int32_t *base, uint32_t size)
const_shape_node->dim(0) = size;
const_shape_node->dtype(S32);
const_shape_node->size<S32>(size);
+ const_shape_node->shape_status(luci::ShapeStatus::VALID);
for (uint32_t axis = 0; axis < size; ++axis)
const_shape_node->at<S32>(axis) = base[axis];
node->shape(const_shape_node);
@@ -47,4 +48,38 @@ void set_new_shape(CircleReshape *node, int32_t *base, uint32_t size)
node->newShape()->dim(axis) = base[axis];
}
+void link(loco::GraphOutput *output, CircleOutput *node) { node->index(output->index()); }
+
+CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &index)
+{
+ for (uint32_t n = 0; n < g->nodes()->size(); ++n)
+ {
+ if (auto output = dynamic_cast<CircleOutput *>(g->nodes()->at(n)))
+ {
+ if (output->indexed() && output->index() == index)
+ {
+ return output;
+ }
+ }
+ }
+ return nullptr;
+}
+
+void link(loco::GraphInput *input, CircleInput *node) { node->index(input->index()); }
+
+CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index)
+{
+ for (uint32_t n = 0; n < g->nodes()->size(); ++n)
+ {
+ if (auto input = dynamic_cast<CircleInput *>(g->nodes()->at(n)))
+ {
+ if (input->indexed() && input->index() == index)
+ {
+ return input;
+ }
+ }
+ }
+ return nullptr;
+}
+
} // namespace luci
diff --git a/compiler/luci/lang/src/DeadNodeQueryService.cpp b/compiler/luci/lang/src/DeadNodeQueryService.cpp
new file mode 100644
index 000000000..a22574c94
--- /dev/null
+++ b/compiler/luci/lang/src/DeadNodeQueryService.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DeadNodeQueryService.h"
+
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <loco/IR/Graph.h>
+
+namespace luci
+{
+
+struct VirtualOutputDetector final : public luci::CircleNodeMutableVisitor<bool>
+{
+ bool visit(luci::CircleIfOut *) final { return true; }
+ bool visit(luci::CircleSplitOut *) final { return true; }
+ bool visit(luci::CircleSplitVOut *) final { return true; }
+ bool visit(luci::CircleTopKV2Out *) final { return true; }
+ bool visit(luci::CircleUnpackOut *) final { return true; }
+ bool visit(luci::CircleWhileOut *) final { return true; }
+ // TODO add more nodes that multi output virtual nodes
+
+ // default is false
+ bool visit(luci::CircleNode *) final { return false; }
+};
+
+bool DeadNodeQueryServiceImpl::isDeadNode(loco::Node *node)
+{
+ auto g = node->graph();
+ auto input_nodes_vec = loco::input_nodes(g);
+ auto output_nodes_vec = loco::output_nodes(g);
+
+ auto input_nodes = std::set<loco::Node *>(input_nodes_vec.begin(), input_nodes_vec.end());
+ auto output_nodes = std::set<loco::Node *>(output_nodes_vec.begin(), output_nodes_vec.end());
+ auto active_nodes = loco::active_nodes(output_nodes_vec);
+
+ if (active_nodes.find(node) != active_nodes.end())
+ return false;
+ // input and output nodes are not dead node even if it is not active.
+ if (input_nodes.find(node) != input_nodes.end())
+ return false;
+
+ // if node is one of virtual mulitple outputs, we need to ask the real node
+ if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
+ {
+ VirtualOutputDetector d;
+ if (circle_node->accept(&d))
+ {
+ assert(node->arity() == 1);
+ loco::Node *real_node = node->arg(0);
+ if (active_nodes.find(real_node) != active_nodes.end())
+ return false;
+ if (input_nodes.find(real_node) != input_nodes.end())
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace luci
diff --git a/compiler/luci/lang/src/DeadNodeQueryService.h b/compiler/luci/lang/src/DeadNodeQueryService.h
new file mode 100644
index 000000000..d10696667
--- /dev/null
+++ b/compiler/luci/lang/src/DeadNodeQueryService.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_LANG_DEADNODEQUERYSERVICE_H__
+#define __LUCI_LANG_DEADNODEQUERYSERVICE_H__
+
+#include <logo/DeadNodeQueryService.h>
+
+#include <loco/IR/Node.h>
+
+namespace luci
+{
+
+struct DeadNodeQueryServiceImpl final : public logo::DeadNodeQueryService
+{
+ bool isDeadNode(loco::Node *node) final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_LANG_DEADNODEQUERYSERVICE_H__
diff --git a/compiler/luci/lang/src/Module.cpp b/compiler/luci/lang/src/Module.cpp
index e52d897a5..80ef61910 100644
--- a/compiler/luci/lang/src/Module.cpp
+++ b/compiler/luci/lang/src/Module.cpp
@@ -43,4 +43,4 @@ loco::Graph *Module::graph(size_t idx) const
std::unique_ptr<Module> make_module(void) { return std::make_unique<Module>(); }
-} // namespace loco
+} // namespace luci
diff --git a/compiler/luci/lang/src/Module.test.cpp b/compiler/luci/lang/src/Module.test.cpp
index f60319944..26bf073be 100644
--- a/compiler/luci/lang/src/Module.test.cpp
+++ b/compiler/luci/lang/src/Module.test.cpp
@@ -33,8 +33,8 @@ TEST(ModuleTest, add)
m->add(std::move(g));
- ASSERT_EQ(m->graph(), g_ptr);
- ASSERT_EQ(m->graph(0), g_ptr);
+ ASSERT_EQ(g_ptr, m->graph());
+ ASSERT_EQ(g_ptr, m->graph(0));
}
TEST(ModuleTest, add_more)
@@ -51,11 +51,11 @@ TEST(ModuleTest, add_more)
m->add(std::move(g2));
m->add(std::move(g3));
- ASSERT_EQ(m->size(), 3);
- ASSERT_EQ(m->graph(), g1_ptr);
- ASSERT_EQ(m->graph(0), g1_ptr);
- ASSERT_EQ(m->graph(1), g2_ptr);
- ASSERT_EQ(m->graph(2), g3_ptr);
+ ASSERT_EQ(3, m->size());
+ ASSERT_EQ(g1_ptr, m->graph());
+ ASSERT_EQ(g1_ptr, m->graph(0));
+ ASSERT_EQ(g2_ptr, m->graph(1));
+ ASSERT_EQ(g3_ptr, m->graph(2));
}
TEST(ModuleTest, add_nullptr_NEG)
diff --git a/compiler/luci/lang/src/Nodes/CircleAbs.test.cpp b/compiler/luci/lang/src/Nodes/CircleAbs.test.cpp
index 847f1500b..f97becba8 100644
--- a/compiler/luci/lang/src/Nodes/CircleAbs.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleAbs.test.cpp
@@ -17,15 +17,78 @@
#include "luci/IR/Nodes/CircleAbs.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
+#include <memory>
+
TEST(CircleAbsTest, constructor)
{
luci::CircleAbs abs_node;
- ASSERT_EQ(abs_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(abs_node.opcode(), luci::CircleOpcode::ABS);
+ ASSERT_EQ(luci::CircleDialect::get(), abs_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ABS, abs_node.opcode());
+
+ ASSERT_EQ(nullptr, abs_node.x());
+}
+
+TEST(CircleAbsTest, common_NEG)
+{
+ luci::CircleAbs abs_node;
+
+ abs_node.name("name");
+ ASSERT_EQ("name", abs_node.name());
+
+ auto q = std::make_unique<luci::CircleQuantParam>();
+ abs_node.quantparam(std::move(q));
+ ASSERT_NE(nullptr, abs_node.quantparam());
+
+ ASSERT_EQ(luci::ShapeStatus::UNDEFINED, abs_node.shape_status());
+ abs_node.shape_status(luci::ShapeStatus::NOSHAPE);
+ ASSERT_NE(luci::ShapeStatus::UNDEFINED, abs_node.shape_status());
+}
+
+TEST(CircleAbsTest, input_NEG)
+{
+ luci::CircleAbs abs_node;
+ luci::CircleAbs node;
+
+ abs_node.x(&node);
+ ASSERT_NE(nullptr, abs_node.x());
+
+ abs_node.x(nullptr);
+ ASSERT_EQ(nullptr, abs_node.x());
+}
+
+TEST(CircleAbsTest, arity_NEG)
+{
+ luci::CircleAbs abs_node;
+
+ ASSERT_NO_THROW(abs_node.arg(0));
+ ASSERT_THROW(abs_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleAbsTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleAbs abs_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(abs_node.accept(&tv), std::exception);
+}
+
+TEST(CircleAbsTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleAbs abs_node;
- ASSERT_EQ(abs_node.x(), nullptr);
+ TestVisitor tv;
+ ASSERT_THROW(abs_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleAdd.test.cpp b/compiler/luci/lang/src/Nodes/CircleAdd.test.cpp
index a7701963d..382faa5ef 100644
--- a/compiler/luci/lang/src/Nodes/CircleAdd.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleAdd.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleAdd.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CircleAddTest, constructor_P)
{
luci::CircleAdd add_node;
- ASSERT_EQ(add_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(add_node.opcode(), luci::CircleOpcode::ADD);
+ ASSERT_EQ(luci::CircleDialect::get(), add_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ADD, add_node.opcode());
- ASSERT_EQ(add_node.x(), nullptr);
- ASSERT_EQ(add_node.y(), nullptr);
+ ASSERT_EQ(nullptr, add_node.x());
+ ASSERT_EQ(nullptr, add_node.y());
+}
+
+TEST(CircleAddTest, input_NEG)
+{
+ luci::CircleAdd add_node;
+ luci::CircleAdd node;
+
+ add_node.x(&node);
+ add_node.y(&node);
+ ASSERT_NE(nullptr, add_node.x());
+ ASSERT_NE(nullptr, add_node.y());
+
+ add_node.x(nullptr);
+ add_node.y(nullptr);
+ ASSERT_EQ(nullptr, add_node.x());
+ ASSERT_EQ(nullptr, add_node.y());
+}
+
+TEST(CircleAddTest, arity_NEG)
+{
+ luci::CircleAdd add_node;
+
+ ASSERT_NO_THROW(add_node.arg(1));
+ ASSERT_THROW(add_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleAddTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleAdd add_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(add_node.accept(&tv), std::exception);
+}
+
+TEST(CircleAddTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleAdd add_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(add_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleAddN.test.cpp b/compiler/luci/lang/src/Nodes/CircleAddN.test.cpp
new file mode 100644
index 000000000..399d8cb82
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleAddN.test.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleAddN.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleAddNTest, constructor)
+{
+ luci::CircleAddN add_node(3);
+
+ ASSERT_EQ(luci::CircleDialect::get(), add_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ADD_N, add_node.opcode());
+
+ ASSERT_EQ(nullptr, add_node.inputs(0));
+ ASSERT_EQ(nullptr, add_node.inputs(1));
+ ASSERT_EQ(nullptr, add_node.inputs(2));
+}
+
+TEST(CircleAddNTest, input_NEG)
+{
+ luci::CircleAddN add_node(3);
+ luci::CircleAddN node(2);
+
+ add_node.inputs(0, &node);
+ add_node.inputs(1, &node);
+ add_node.inputs(2, &node);
+ ASSERT_NE(nullptr, add_node.inputs(0));
+ ASSERT_NE(nullptr, add_node.inputs(1));
+ ASSERT_NE(nullptr, add_node.inputs(2));
+
+ add_node.inputs(0, nullptr);
+ add_node.inputs(1, nullptr);
+ add_node.inputs(2, nullptr);
+ ASSERT_EQ(nullptr, add_node.inputs(0));
+ ASSERT_EQ(nullptr, add_node.inputs(1));
+ ASSERT_EQ(nullptr, add_node.inputs(2));
+}
+
+TEST(CircleAddNTest, arity_NEG)
+{
+ luci::CircleAddN add_node(3);
+ luci::CircleAddN node(2);
+
+ ASSERT_NO_THROW(add_node.inputs(2, &node));
+ ASSERT_NO_THROW(add_node.inputs(2, nullptr));
+ ASSERT_THROW(add_node.inputs(3, &node), std::out_of_range);
+
+ ASSERT_NO_THROW(add_node.arg(2));
+ ASSERT_THROW(add_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleAddNTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleAddN add_node(2);
+
+ TestVisitor tv;
+ ASSERT_THROW(add_node.accept(&tv), std::exception);
+}
+
+TEST(CircleAddNTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleAddN add_node(2);
+
+ TestVisitor tv;
+ ASSERT_THROW(add_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp b/compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp
index 6b2cff11c..375a74c20 100644
--- a/compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp
@@ -17,16 +17,65 @@
#include "luci/IR/Nodes/CircleArgMax.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
TEST(CircleArgMaxTest, constructor_P)
{
- luci::CircleArgMax add_node;
+ luci::CircleArgMax argmax_node;
- ASSERT_EQ(add_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(add_node.opcode(), luci::CircleOpcode::ARG_MAX);
+ ASSERT_EQ(luci::CircleDialect::get(), argmax_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ARG_MAX, argmax_node.opcode());
- ASSERT_EQ(add_node.input(), nullptr);
- ASSERT_EQ(add_node.dimension(), nullptr);
+ ASSERT_EQ(nullptr, argmax_node.input());
+ ASSERT_EQ(nullptr, argmax_node.dimension());
+}
+
+TEST(CircleArgMaxTest, input_NEG)
+{
+ luci::CircleArgMax argmax_node;
+ luci::CircleArgMax node;
+
+ argmax_node.input(&node);
+ argmax_node.dimension(&node);
+ ASSERT_NE(nullptr, argmax_node.input());
+ ASSERT_NE(nullptr, argmax_node.dimension());
+
+ argmax_node.input(nullptr);
+ argmax_node.dimension(nullptr);
+ ASSERT_EQ(nullptr, argmax_node.input());
+ ASSERT_EQ(nullptr, argmax_node.dimension());
+}
+
+TEST(CircleArgMaxTest, arity_NEG)
+{
+ luci::CircleArgMax argmax_node;
+
+ ASSERT_NO_THROW(argmax_node.arg(1));
+ ASSERT_THROW(argmax_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleArgMaxTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleArgMax argmax_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(argmax_node.accept(&tv), std::exception);
+}
+
+TEST(CircleArgMaxTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleArgMax argmax_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(argmax_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleArgMin.test.cpp b/compiler/luci/lang/src/Nodes/CircleArgMin.test.cpp
new file mode 100644
index 000000000..6607bf82f
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleArgMin.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleArgMin.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleArgMinTest, constructor_P)
+{
+ luci::CircleArgMin argmin_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), argmin_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ARG_MIN, argmin_node.opcode());
+
+ ASSERT_EQ(nullptr, argmin_node.input());
+ ASSERT_EQ(nullptr, argmin_node.dimension());
+}
+
+TEST(CircleArgMinTest, input_NEG)
+{
+ luci::CircleArgMin argmin_node;
+ luci::CircleArgMin node;
+
+ argmin_node.input(&node);
+ argmin_node.dimension(&node);
+ ASSERT_NE(nullptr, argmin_node.input());
+ ASSERT_NE(nullptr, argmin_node.dimension());
+
+ argmin_node.input(nullptr);
+ argmin_node.dimension(nullptr);
+ ASSERT_EQ(nullptr, argmin_node.input());
+ ASSERT_EQ(nullptr, argmin_node.dimension());
+}
+
+TEST(CircleArgMinTest, arity_NEG)
+{
+ luci::CircleArgMin argmin_node;
+
+ ASSERT_NO_THROW(argmin_node.arg(1));
+ ASSERT_THROW(argmin_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleArgMinTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleArgMin argmin_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(argmin_node.accept(&tv), std::exception);
+}
+
+TEST(CircleArgMinTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleArgMin argmin_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(argmin_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleAveragePool2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleAveragePool2D.test.cpp
new file mode 100644
index 000000000..fc7265cf0
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleAveragePool2D.test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleAveragePool2D.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleAveragePool2DTest, constructor_P)
+{
+ luci::CircleAveragePool2D average_pool_2d_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), average_pool_2d_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::AVERAGE_POOL_2D, average_pool_2d_node.opcode());
+
+ ASSERT_EQ(nullptr, average_pool_2d_node.value());
+ ASSERT_EQ(luci::Padding::UNDEFINED, average_pool_2d_node.padding());
+ ASSERT_EQ(1, average_pool_2d_node.filter()->h());
+ ASSERT_EQ(1, average_pool_2d_node.filter()->w());
+ ASSERT_EQ(1, average_pool_2d_node.stride()->h());
+ ASSERT_EQ(1, average_pool_2d_node.stride()->w());
+}
+
+TEST(CircleAveragePool2DTest, input_NEG)
+{
+ luci::CircleAveragePool2D avgpool_node;
+ luci::CircleAveragePool2D node;
+
+ avgpool_node.value(&node);
+ ASSERT_NE(nullptr, avgpool_node.value());
+
+ avgpool_node.value(nullptr);
+ ASSERT_EQ(nullptr, avgpool_node.value());
+
+ avgpool_node.filter()->h(2);
+ avgpool_node.filter()->w(2);
+ avgpool_node.stride()->h(2);
+ avgpool_node.stride()->w(2);
+ ASSERT_NE(1, avgpool_node.filter()->h());
+ ASSERT_NE(1, avgpool_node.filter()->w());
+ ASSERT_NE(1, avgpool_node.stride()->h());
+ ASSERT_NE(1, avgpool_node.stride()->w());
+}
+
+TEST(CircleAveragePool2DTest, arity_NEG)
+{
+ luci::CircleAveragePool2D avgpool_node;
+
+ ASSERT_NO_THROW(avgpool_node.arg(0));
+ ASSERT_THROW(avgpool_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleAveragePool2DTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleAveragePool2D avgpool_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(avgpool_node.accept(&tv), std::exception);
+}
+
+TEST(CircleAveragePool2DTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleAveragePool2D avgpool_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(avgpool_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleBCQFullyConnected.test.cpp b/compiler/luci/lang/src/Nodes/CircleBCQFullyConnected.test.cpp
new file mode 100644
index 000000000..35c9ab95b
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleBCQFullyConnected.test.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleBCQFullyConnected.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleBCQFullyConnectedTest, constructor)
+{
+ luci::CircleBCQFullyConnected bcq_FC_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), bcq_FC_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::BCQ_FULLY_CONNECTED, bcq_FC_node.opcode());
+
+ ASSERT_EQ(nullptr, bcq_FC_node.input());
+ ASSERT_EQ(nullptr, bcq_FC_node.weights_scales());
+ ASSERT_EQ(nullptr, bcq_FC_node.weights_binary());
+ ASSERT_EQ(nullptr, bcq_FC_node.bias());
+ ASSERT_EQ(nullptr, bcq_FC_node.weights_clusters());
+
+ ASSERT_EQ(luci::FusedActFunc::UNDEFINED, bcq_FC_node.fusedActivationFunction());
+ ASSERT_EQ(0, bcq_FC_node.weights_hidden_size());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleBCQGather.test.cpp b/compiler/luci/lang/src/Nodes/CircleBCQGather.test.cpp
new file mode 100644
index 000000000..c187a9033
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleBCQGather.test.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleBCQGather.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleBCQGatherTest, constructor)
+{
+ luci::CircleBCQGather bcq_gather_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), bcq_gather_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::BCQ_GATHER, bcq_gather_node.opcode());
+
+ ASSERT_EQ(nullptr, bcq_gather_node.input_scales());
+ ASSERT_EQ(nullptr, bcq_gather_node.input_binary());
+ ASSERT_EQ(nullptr, bcq_gather_node.indices());
+ ASSERT_EQ(nullptr, bcq_gather_node.input_clusters());
+
+ ASSERT_EQ(0, bcq_gather_node.axis());
+ ASSERT_EQ(0, bcq_gather_node.input_hidden_size());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleBatchMatMul.test.cpp b/compiler/luci/lang/src/Nodes/CircleBatchMatMul.test.cpp
new file mode 100644
index 000000000..d7712c8dd
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleBatchMatMul.test.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 "luci/IR/Nodes/CircleBatchMatMul.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleBatchMatMulTest, constructor)
+{
+ luci::CircleBatchMatMul batchmatmul_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), batchmatmul_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::BATCHMATMUL, batchmatmul_node.opcode());
+
+ ASSERT_EQ(nullptr, batchmatmul_node.x());
+ ASSERT_EQ(nullptr, batchmatmul_node.y());
+
+ ASSERT_FALSE(batchmatmul_node.adj_x());
+ ASSERT_FALSE(batchmatmul_node.adj_y());
+}
+
+TEST(CircleBatchMatMulTest, input_NEG)
+{
+ luci::CircleBatchMatMul batchmatmul_node;
+ luci::CircleBatchMatMul node;
+
+ batchmatmul_node.x(&node);
+ batchmatmul_node.y(&node);
+ ASSERT_NE(nullptr, batchmatmul_node.x());
+ ASSERT_NE(nullptr, batchmatmul_node.y());
+
+ batchmatmul_node.x(nullptr);
+ batchmatmul_node.y(nullptr);
+ ASSERT_EQ(nullptr, batchmatmul_node.x());
+ ASSERT_EQ(nullptr, batchmatmul_node.y());
+}
+
+TEST(CircleBatchMatMulTest, arity_NEG)
+{
+ luci::CircleBatchMatMul batchmatmul_node;
+
+ ASSERT_NO_THROW(batchmatmul_node.arg(1));
+ ASSERT_THROW(batchmatmul_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleBatchMatMulTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleBatchMatMul batchmatmul_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(batchmatmul_node.accept(&tv), std::exception);
+}
+
+TEST(CircleBatchMatMulTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleBatchMatMul batchmatmul_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(batchmatmul_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp b/compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp
index e995718a1..0374fe008 100644
--- a/compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleBatchToSpaceND.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,10 +25,62 @@ TEST(CircleBatchToSpaceNDTest, constructor)
{
luci::CircleBatchToSpaceND bts_node;
- ASSERT_EQ(bts_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(bts_node.opcode(), luci::CircleOpcode::BATCH_TO_SPACE_ND);
+ ASSERT_EQ(luci::CircleDialect::get(), bts_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::BATCH_TO_SPACE_ND, bts_node.opcode());
- ASSERT_EQ(bts_node.input(), nullptr);
- ASSERT_EQ(bts_node.block_shape(), nullptr);
- ASSERT_EQ(bts_node.crops(), nullptr);
+ ASSERT_EQ(nullptr, bts_node.input());
+ ASSERT_EQ(nullptr, bts_node.block_shape());
+ ASSERT_EQ(nullptr, bts_node.crops());
+}
+
+TEST(CircleBatchToSpaceNDTest, input_NEG)
+{
+ luci::CircleBatchToSpaceND bts_node;
+ luci::CircleBatchToSpaceND node;
+
+ bts_node.input(&node);
+ bts_node.block_shape(&node);
+ bts_node.crops(&node);
+ ASSERT_NE(nullptr, bts_node.input());
+ ASSERT_NE(nullptr, bts_node.block_shape());
+ ASSERT_NE(nullptr, bts_node.crops());
+
+ bts_node.input(nullptr);
+ bts_node.block_shape(nullptr);
+ bts_node.crops(nullptr);
+ ASSERT_EQ(nullptr, bts_node.input());
+ ASSERT_EQ(nullptr, bts_node.block_shape());
+ ASSERT_EQ(nullptr, bts_node.crops());
+}
+
+TEST(CircleBatchToSpaceNDTest, arity_NEG)
+{
+ luci::CircleBatchToSpaceND bts_node;
+
+ ASSERT_NO_THROW(bts_node.arg(2));
+ ASSERT_THROW(bts_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleBatchToSpaceNDTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleBatchToSpaceND bts_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(bts_node.accept(&tv), std::exception);
+}
+
+TEST(CircleBatchToSpaceNDTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleBatchToSpaceND bts_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(bts_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleCast.test.cpp b/compiler/luci/lang/src/Nodes/CircleCast.test.cpp
new file mode 100644
index 000000000..b58bf96f9
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleCast.test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleCast.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleCastTest, constructor)
+{
+ luci::CircleCast cast_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), cast_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CAST, cast_node.opcode());
+
+ ASSERT_EQ(nullptr, cast_node.x());
+ ASSERT_EQ(loco::DataType::FLOAT32, cast_node.in_data_type());
+ ASSERT_EQ(loco::DataType::FLOAT32, cast_node.out_data_type());
+}
+
+TEST(CircleCastTest, input_NEG)
+{
+ luci::CircleCast cast_node;
+ luci::CircleCast node;
+
+ cast_node.x(&node);
+ ASSERT_NE(nullptr, cast_node.x());
+
+ cast_node.x(nullptr);
+ ASSERT_EQ(nullptr, cast_node.x());
+}
+
+TEST(CircleCastTest, arity_NEG)
+{
+ luci::CircleCast cast_node;
+
+ ASSERT_NO_THROW(cast_node.arg(0));
+ ASSERT_THROW(cast_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleCastTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleCast cast_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(cast_node.accept(&tv), std::exception);
+}
+
+TEST(CircleCastTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleCast cast_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(cast_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleCeil.test.cpp b/compiler/luci/lang/src/Nodes/CircleCeil.test.cpp
new file mode 100644
index 000000000..efac614b2
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleCeil.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleCeil.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleCeilTest, constructor)
+{
+ luci::CircleCeil ceil_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), ceil_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CEIL, ceil_node.opcode());
+
+ ASSERT_EQ(nullptr, ceil_node.x());
+}
+
+TEST(CircleCeilTest, input_NEG)
+{
+ luci::CircleCeil ceil_node;
+ luci::CircleCeil node;
+
+ ceil_node.x(&node);
+ ASSERT_NE(nullptr, ceil_node.x());
+
+ ceil_node.x(nullptr);
+ ASSERT_EQ(nullptr, ceil_node.x());
+}
+
+TEST(CircleCeilTest, arity_NEG)
+{
+ luci::CircleCeil ceil_node;
+
+ ASSERT_NO_THROW(ceil_node.arg(0));
+ ASSERT_THROW(ceil_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleCeilTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleCeil ceil_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(ceil_node.accept(&tv), std::exception);
+}
+
+TEST(CircleCeilTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleCeil ceil_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(ceil_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp b/compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp
index 7167682b2..9f219a386 100644
--- a/compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleConcatenation.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,12 +25,60 @@ TEST(CircleConcatenationTest, constructor_P)
{
luci::CircleConcatenation concat_node(3);
- ASSERT_EQ(concat_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(concat_node.opcode(), luci::CircleOpcode::CONCATENATION);
+ ASSERT_EQ(luci::CircleDialect::get(), concat_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CONCATENATION, concat_node.opcode());
- ASSERT_EQ(concat_node.numValues(), 3);
- ASSERT_EQ(concat_node.values(0), nullptr);
- ASSERT_EQ(concat_node.values(1), nullptr);
- ASSERT_EQ(concat_node.values(2), nullptr);
- ASSERT_EQ(concat_node.fusedActivationFunction(), luci::FusedActFunc::UNDEFINED);
+ ASSERT_EQ(3, concat_node.numValues());
+ ASSERT_EQ(nullptr, concat_node.values(0));
+ ASSERT_EQ(nullptr, concat_node.values(1));
+ ASSERT_EQ(nullptr, concat_node.values(2));
+ ASSERT_EQ(luci::FusedActFunc::UNDEFINED, concat_node.fusedActivationFunction());
+}
+
+TEST(CircleConcatenationTest, input_NEG)
+{
+ luci::CircleConcatenation concat_node(2);
+ luci::CircleConcatenation node(2);
+
+ concat_node.values(0, &node);
+ concat_node.values(1, &node);
+ ASSERT_NE(nullptr, concat_node.values(0));
+ ASSERT_NE(nullptr, concat_node.values(1));
+
+ concat_node.values(0, nullptr);
+ concat_node.values(1, nullptr);
+ ASSERT_EQ(nullptr, concat_node.values(0));
+ ASSERT_EQ(nullptr, concat_node.values(1));
+}
+
+TEST(CircleConcatenationTest, arity_NEG)
+{
+ luci::CircleConcatenation concat_node(5);
+
+ ASSERT_NO_THROW(concat_node.arg(4));
+ ASSERT_THROW(concat_node.arg(5), std::out_of_range);
+}
+
+TEST(CircleConcatenationTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleConcatenation concat_node(2);
+
+ TestVisitor tv;
+ ASSERT_THROW(concat_node.accept(&tv), std::exception);
+}
+
+TEST(CircleConcatenationTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleConcatenation concat_node(2);
+
+ TestVisitor tv;
+ ASSERT_THROW(concat_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleConst.cpp b/compiler/luci/lang/src/Nodes/CircleConst.cpp
index 1c46884d8..17ff853eb 100644
--- a/compiler/luci/lang/src/Nodes/CircleConst.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleConst.cpp
@@ -70,9 +70,12 @@ template <loco::DataType DT> typename loco::DataTypeImpl<DT>::Type &CircleConst:
template const typename loco::DataTypeImpl<DT>::Type &CircleConst::scalar<DT>(void) const; \
template typename loco::DataTypeImpl<DT>::Type &CircleConst::scalar<DT>(void);
+INSTANTIATE(loco::DataType::S64);
INSTANTIATE(loco::DataType::S32);
+INSTANTIATE(loco::DataType::S16);
INSTANTIATE(loco::DataType::FLOAT32);
INSTANTIATE(loco::DataType::U8);
+INSTANTIATE(loco::DataType::BOOL);
#undef INSTANTIATE
diff --git a/compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp
index 7931c7eba..7fcc71d6e 100644
--- a/compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleConv2D.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,10 +25,84 @@ TEST(CircleConv2Dest, constructor_P)
{
luci::CircleConv2D conv2d_node;
- ASSERT_EQ(conv2d_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(conv2d_node.opcode(), luci::CircleOpcode::CONV_2D);
+ ASSERT_EQ(luci::CircleDialect::get(), conv2d_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CONV_2D, conv2d_node.opcode());
- ASSERT_EQ(conv2d_node.input(), nullptr);
- ASSERT_EQ(conv2d_node.filter(), nullptr);
- ASSERT_EQ(conv2d_node.bias(), nullptr);
+ ASSERT_EQ(nullptr, conv2d_node.input());
+ ASSERT_EQ(nullptr, conv2d_node.filter());
+ ASSERT_EQ(nullptr, conv2d_node.bias());
+ ASSERT_EQ(luci::Padding::UNDEFINED, conv2d_node.padding());
+ ASSERT_EQ(1, conv2d_node.stride()->h());
+ ASSERT_EQ(1, conv2d_node.stride()->w());
+ ASSERT_EQ(1, conv2d_node.dilation()->h());
+ ASSERT_EQ(1, conv2d_node.dilation()->w());
+ ASSERT_EQ(luci::FusedActFunc::UNDEFINED, conv2d_node.fusedActivationFunction());
+}
+
+TEST(CircleConv2Dest, input_NEG)
+{
+ luci::CircleConv2D conv2d_node;
+ luci::CircleConv2D node;
+
+ conv2d_node.input(&node);
+ conv2d_node.filter(&node);
+ conv2d_node.bias(&node);
+ ASSERT_NE(nullptr, conv2d_node.input());
+ ASSERT_NE(nullptr, conv2d_node.filter());
+ ASSERT_NE(nullptr, conv2d_node.bias());
+
+ conv2d_node.input(nullptr);
+ conv2d_node.filter(nullptr);
+ conv2d_node.bias(nullptr);
+ ASSERT_EQ(nullptr, conv2d_node.input());
+ ASSERT_EQ(nullptr, conv2d_node.filter());
+ ASSERT_EQ(nullptr, conv2d_node.bias());
+
+ conv2d_node.padding(luci::Padding::SAME);
+ ASSERT_NE(luci::Padding::UNDEFINED, conv2d_node.padding());
+
+ conv2d_node.stride()->h(2);
+ conv2d_node.stride()->w(2);
+ ASSERT_EQ(2, conv2d_node.stride()->h());
+ ASSERT_EQ(2, conv2d_node.stride()->w());
+
+ conv2d_node.dilation()->h(2);
+ conv2d_node.dilation()->w(2);
+ ASSERT_EQ(2, conv2d_node.dilation()->h());
+ ASSERT_EQ(2, conv2d_node.dilation()->w());
+
+ conv2d_node.fusedActivationFunction(luci::FusedActFunc::RELU);
+ ASSERT_NE(luci::FusedActFunc::UNDEFINED, conv2d_node.fusedActivationFunction());
+}
+
+TEST(CircleConv2Dest, arity_NEG)
+{
+ luci::CircleConv2D conv2d_node;
+
+ ASSERT_NO_THROW(conv2d_node.arg(2));
+ ASSERT_THROW(conv2d_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleConv2Dest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleConv2D conv2d_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(conv2d_node.accept(&tv), std::exception);
+}
+
+TEST(CircleConv2Dest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleConv2D conv2d_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(conv2d_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleCos.test.cpp b/compiler/luci/lang/src/Nodes/CircleCos.test.cpp
index 34c2cfdf0..55438d37f 100644
--- a/compiler/luci/lang/src/Nodes/CircleCos.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleCos.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleCos.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,8 +25,52 @@ TEST(CircleCosTest, constructor_P)
{
luci::CircleCos cos_node;
- ASSERT_EQ(cos_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(cos_node.opcode(), luci::CircleOpcode::COS);
+ ASSERT_EQ(luci::CircleDialect::get(), cos_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::COS, cos_node.opcode());
- ASSERT_EQ(cos_node.x(), nullptr);
+ ASSERT_EQ(nullptr, cos_node.x());
+}
+
+TEST(CircleCosTest, input_NEG)
+{
+ luci::CircleCos cos_node;
+ luci::CircleCos node;
+
+ cos_node.x(&node);
+ ASSERT_NE(nullptr, cos_node.x());
+
+ cos_node.x(nullptr);
+ ASSERT_EQ(nullptr, cos_node.x());
+}
+
+TEST(CircleCosTest, arity_NEG)
+{
+ luci::CircleCos cos_node;
+
+ ASSERT_NO_THROW(cos_node.arg(0));
+ ASSERT_THROW(cos_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleCosTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleCos cos_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(cos_node.accept(&tv), std::exception);
+}
+
+TEST(CircleCosTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleCos cos_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(cos_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp b/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp
new file mode 100644
index 000000000..74ea82c6c
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleCustom.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleCustomTest, constructor)
+{
+ luci::CircleCustom custom_node(2);
+
+ ASSERT_EQ(luci::CircleDialect::get(), custom_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CUSTOM, custom_node.opcode());
+
+ ASSERT_EQ(2, custom_node.arity());
+ ASSERT_EQ(nullptr, custom_node.arg(0));
+ ASSERT_EQ(nullptr, custom_node.arg(1));
+
+ ASSERT_EQ(2, custom_node.numInputs());
+ ASSERT_EQ(0, custom_node.custom_code().size());
+}
+
+TEST(CircleCustomTest, constructor_NEG) { ASSERT_DEBUG_DEATH(luci::CircleCustom{0}, ""); }
+
+TEST(CircleCustomTest, invalidIndex_NEG)
+{
+ luci::CircleCustom custom_node(2);
+
+ EXPECT_ANY_THROW(custom_node.arg(5));
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleCustomOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleCustomOut.test.cpp
new file mode 100644
index 000000000..8b63f97b1
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleCustomOut.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleCustomOut.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleCustomOutTest, constructor)
+{
+ luci::CircleCustomOut customout_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), customout_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CIRCLECUSTOMOUT, customout_node.opcode());
+
+ ASSERT_EQ(nullptr, customout_node.input());
+ ASSERT_EQ(-1, customout_node.index());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleDepthToSpace.test.cpp b/compiler/luci/lang/src/Nodes/CircleDepthToSpace.test.cpp
new file mode 100644
index 000000000..9e3bbb7b7
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleDepthToSpace.test.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleDepthToSpace.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleDepthToSpaceTest, constructor_P)
+{
+ luci::CircleDepthToSpace std_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), std_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::DEPTH_TO_SPACE, std_node.opcode());
+
+ ASSERT_EQ(nullptr, std_node.input());
+ ASSERT_EQ(0, std_node.block_size());
+}
+
+TEST(CircleDepthToSpaceTest, input_NEG)
+{
+ luci::CircleDepthToSpace std_node;
+ luci::CircleDepthToSpace node;
+
+ std_node.input(&node);
+ ASSERT_NE(nullptr, std_node.input());
+
+ std_node.input(nullptr);
+ ASSERT_EQ(nullptr, std_node.input());
+
+ std_node.block_size(2);
+ ASSERT_EQ(2, std_node.block_size());
+}
+
+TEST(CircleDepthToSpaceTest, arity_NEG)
+{
+ luci::CircleDepthToSpace std_node;
+
+ ASSERT_NO_THROW(std_node.arg(0));
+ ASSERT_THROW(std_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleDepthToSpaceTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleDepthToSpace std_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(std_node.accept(&tv), std::exception);
+}
+
+TEST(CircleDepthToSpaceTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleDepthToSpace std_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(std_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp
index bbc1ea543..5761775e5 100644
--- a/compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleDepthwiseConv2D.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,15 +25,85 @@ TEST(CircleDepthwiseConv2DTest, constructor_P)
{
luci::CircleDepthwiseConv2D dw_conv2d_node;
- ASSERT_EQ(dw_conv2d_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(dw_conv2d_node.opcode(), luci::CircleOpcode::DEPTHWISE_CONV_2D);
-
- ASSERT_EQ(dw_conv2d_node.input(), nullptr);
- ASSERT_EQ(dw_conv2d_node.filter(), nullptr);
- ASSERT_EQ(dw_conv2d_node.bias(), nullptr);
- ASSERT_EQ(dw_conv2d_node.padding(), luci::Padding::UNDEFINED);
- ASSERT_EQ(dw_conv2d_node.stride()->h(), 1);
- ASSERT_EQ(dw_conv2d_node.stride()->w(), 1);
- ASSERT_EQ(dw_conv2d_node.depthMultiplier(), 0);
- ASSERT_EQ(dw_conv2d_node.fusedActivationFunction(), luci::FusedActFunc::UNDEFINED);
+ ASSERT_EQ(luci::CircleDialect::get(), dw_conv2d_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::DEPTHWISE_CONV_2D, dw_conv2d_node.opcode());
+
+ ASSERT_EQ(nullptr, dw_conv2d_node.input());
+ ASSERT_EQ(nullptr, dw_conv2d_node.filter());
+ ASSERT_EQ(nullptr, dw_conv2d_node.bias());
+ ASSERT_EQ(luci::Padding::UNDEFINED, dw_conv2d_node.padding());
+ ASSERT_EQ(1, dw_conv2d_node.stride()->h());
+ ASSERT_EQ(1, dw_conv2d_node.stride()->w());
+ ASSERT_EQ(1, dw_conv2d_node.dilation()->h());
+ ASSERT_EQ(1, dw_conv2d_node.dilation()->w());
+ ASSERT_EQ(0, dw_conv2d_node.depthMultiplier());
+ ASSERT_EQ(luci::FusedActFunc::UNDEFINED, dw_conv2d_node.fusedActivationFunction());
+}
+
+TEST(CircleDepthwiseConv2DTest, input_NEG)
+{
+ luci::CircleDepthwiseConv2D dw_conv2d_node;
+ luci::CircleDepthwiseConv2D node;
+
+ dw_conv2d_node.input(&node);
+ dw_conv2d_node.filter(&node);
+ dw_conv2d_node.bias(&node);
+ ASSERT_NE(nullptr, dw_conv2d_node.input());
+ ASSERT_NE(nullptr, dw_conv2d_node.filter());
+ ASSERT_NE(nullptr, dw_conv2d_node.bias());
+
+ dw_conv2d_node.input(nullptr);
+ dw_conv2d_node.filter(nullptr);
+ dw_conv2d_node.bias(nullptr);
+ ASSERT_EQ(nullptr, dw_conv2d_node.input());
+ ASSERT_EQ(nullptr, dw_conv2d_node.filter());
+ ASSERT_EQ(nullptr, dw_conv2d_node.bias());
+
+ dw_conv2d_node.padding(luci::Padding::SAME);
+ ASSERT_NE(luci::Padding::UNDEFINED, dw_conv2d_node.padding());
+
+ dw_conv2d_node.stride()->h(2);
+ dw_conv2d_node.stride()->w(2);
+ ASSERT_EQ(2, dw_conv2d_node.stride()->h());
+ ASSERT_EQ(2, dw_conv2d_node.stride()->w());
+
+ dw_conv2d_node.dilation()->h(2);
+ dw_conv2d_node.dilation()->w(2);
+ ASSERT_EQ(2, dw_conv2d_node.dilation()->h());
+ ASSERT_EQ(2, dw_conv2d_node.dilation()->w());
+
+ dw_conv2d_node.fusedActivationFunction(luci::FusedActFunc::RELU);
+ ASSERT_NE(luci::FusedActFunc::UNDEFINED, dw_conv2d_node.fusedActivationFunction());
+}
+
+TEST(CircleDepthwiseConv2DTest, arity_NEG)
+{
+ luci::CircleDepthwiseConv2D dw_conv2d_node;
+
+ ASSERT_NO_THROW(dw_conv2d_node.arg(2));
+ ASSERT_THROW(dw_conv2d_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleDepthwiseConv2DTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleDepthwiseConv2D dw_conv2d_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(dw_conv2d_node.accept(&tv), std::exception);
+}
+
+TEST(CircleDepthwiseConv2DTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleDepthwiseConv2D dw_conv2d_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(dw_conv2d_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleDiv.test.cpp b/compiler/luci/lang/src/Nodes/CircleDiv.test.cpp
index e950cc6be..d0b632ca9 100644
--- a/compiler/luci/lang/src/Nodes/CircleDiv.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleDiv.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleDiv.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CircleDivTest, constructor_P)
{
luci::CircleDiv div_node;
- ASSERT_EQ(div_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(div_node.opcode(), luci::CircleOpcode::DIV);
+ ASSERT_EQ(luci::CircleDialect::get(), div_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::DIV, div_node.opcode());
- ASSERT_EQ(div_node.x(), nullptr);
- ASSERT_EQ(div_node.y(), nullptr);
+ ASSERT_EQ(nullptr, div_node.x());
+ ASSERT_EQ(nullptr, div_node.y());
+}
+
+TEST(CircleDivTest, input_NEG)
+{
+ luci::CircleDiv div_node;
+ luci::CircleDiv node;
+
+ div_node.x(&node);
+ div_node.y(&node);
+ ASSERT_NE(nullptr, div_node.x());
+ ASSERT_NE(nullptr, div_node.y());
+
+ div_node.x(nullptr);
+ div_node.y(nullptr);
+ ASSERT_EQ(nullptr, div_node.x());
+ ASSERT_EQ(nullptr, div_node.y());
+}
+
+TEST(CircleDivTest, arity_NEG)
+{
+ luci::CircleDiv div_node;
+
+ ASSERT_NO_THROW(div_node.arg(1));
+ ASSERT_THROW(div_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleDivTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleDiv div_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(div_node.accept(&tv), std::exception);
+}
+
+TEST(CircleDivTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleDiv div_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(div_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleElu.test.cpp b/compiler/luci/lang/src/Nodes/CircleElu.test.cpp
new file mode 100644
index 000000000..2a044d75b
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleElu.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleElu.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleEluTest, constructor_P)
+{
+ luci::CircleElu elu_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), elu_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ELU, elu_node.opcode());
+
+ ASSERT_EQ(nullptr, elu_node.features());
+}
+
+TEST(CircleEluTest, input_NEG)
+{
+ luci::CircleElu elu_node;
+ luci::CircleElu node;
+
+ elu_node.features(&node);
+ ASSERT_NE(nullptr, elu_node.features());
+
+ elu_node.features(nullptr);
+ ASSERT_EQ(nullptr, elu_node.features());
+}
+
+TEST(CircleEluTest, arity_NEG)
+{
+ luci::CircleElu elu_node;
+
+ ASSERT_NO_THROW(elu_node.arg(0));
+ ASSERT_THROW(elu_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleEluTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleElu elu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(elu_node.accept(&tv), std::exception);
+}
+
+TEST(CircleEluTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleElu elu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(elu_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleEqual.test.cpp b/compiler/luci/lang/src/Nodes/CircleEqual.test.cpp
index e2757f094..2ae15290d 100644
--- a/compiler/luci/lang/src/Nodes/CircleEqual.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleEqual.test.cpp
@@ -17,16 +17,65 @@
#include "luci/IR/Nodes/CircleEqual.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
TEST(CircleEqualTest, constructor_P)
{
- luci::CircleEqual or_node;
+ luci::CircleEqual equ_node;
- ASSERT_EQ(or_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(or_node.opcode(), luci::CircleOpcode::EQUAL);
+ ASSERT_EQ(luci::CircleDialect::get(), equ_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::EQUAL, equ_node.opcode());
- ASSERT_EQ(or_node.x(), nullptr);
- ASSERT_EQ(or_node.y(), nullptr);
+ ASSERT_EQ(nullptr, equ_node.x());
+ ASSERT_EQ(nullptr, equ_node.y());
+}
+
+TEST(CircleEqualTest, input_NEG)
+{
+ luci::CircleEqual equ_node;
+ luci::CircleEqual node;
+
+ equ_node.x(&node);
+ equ_node.y(&node);
+ ASSERT_NE(nullptr, equ_node.x());
+ ASSERT_NE(nullptr, equ_node.y());
+
+ equ_node.x(nullptr);
+ equ_node.y(nullptr);
+ ASSERT_EQ(nullptr, equ_node.x());
+ ASSERT_EQ(nullptr, equ_node.y());
+}
+
+TEST(CircleEqualTest, arity_NEG)
+{
+ luci::CircleEqual equ_node;
+
+ ASSERT_NO_THROW(equ_node.arg(1));
+ ASSERT_THROW(equ_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleEqualTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleEqual equ_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(equ_node.accept(&tv), std::exception);
+}
+
+TEST(CircleEqualTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleEqual equ_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(equ_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleExp.test.cpp b/compiler/luci/lang/src/Nodes/CircleExp.test.cpp
index db10d0b03..5ca90e90f 100644
--- a/compiler/luci/lang/src/Nodes/CircleExp.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleExp.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleExp.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,8 +25,52 @@ TEST(CircleExpTest, constructor)
{
luci::CircleExp exp_node;
- ASSERT_EQ(exp_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(exp_node.opcode(), luci::CircleOpcode::EXP);
+ ASSERT_EQ(luci::CircleDialect::get(), exp_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::EXP, exp_node.opcode());
- ASSERT_EQ(exp_node.x(), nullptr);
+ ASSERT_EQ(nullptr, exp_node.x());
+}
+
+TEST(CircleExpTest, input_NEG)
+{
+ luci::CircleExp exp_node;
+ luci::CircleExp node;
+
+ exp_node.x(&node);
+ ASSERT_NE(nullptr, exp_node.x());
+
+ exp_node.x(nullptr);
+ ASSERT_EQ(nullptr, exp_node.x());
+}
+
+TEST(CircleExpTest, arity_NEG)
+{
+ luci::CircleExp exp_node;
+
+ ASSERT_NO_THROW(exp_node.arg(0));
+ ASSERT_THROW(exp_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleExpTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleExp exp_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(exp_node.accept(&tv), std::exception);
+}
+
+TEST(CircleExpTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleExp exp_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(exp_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleExpandDims.test.cpp b/compiler/luci/lang/src/Nodes/CircleExpandDims.test.cpp
new file mode 100644
index 000000000..754ef01f9
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleExpandDims.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleExpandDims.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleExpandDimsTest, constructor_P)
+{
+ luci::CircleExpandDims expand_dims;
+
+ ASSERT_EQ(luci::CircleDialect::get(), expand_dims.dialect());
+ ASSERT_EQ(luci::CircleOpcode::EXPAND_DIMS, expand_dims.opcode());
+
+ ASSERT_EQ(nullptr, expand_dims.input());
+ ASSERT_EQ(nullptr, expand_dims.axis());
+}
+
+TEST(CircleExpandDimsTest, input_NEG)
+{
+ luci::CircleExpandDims expand_dims;
+ luci::CircleExpandDims node;
+
+ expand_dims.input(&node);
+ expand_dims.axis(&node);
+ ASSERT_NE(nullptr, expand_dims.input());
+ ASSERT_NE(nullptr, expand_dims.axis());
+
+ expand_dims.input(nullptr);
+ expand_dims.axis(nullptr);
+ ASSERT_EQ(nullptr, expand_dims.input());
+ ASSERT_EQ(nullptr, expand_dims.axis());
+}
+
+TEST(CircleExpandDimsTest, arity_NEG)
+{
+ luci::CircleExpandDims expand_dims;
+
+ ASSERT_NO_THROW(expand_dims.arg(1));
+ ASSERT_THROW(expand_dims.arg(2), std::out_of_range);
+}
+
+TEST(CircleExpandDimsTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleExpandDims expand_dims;
+
+ TestVisitor tv;
+ ASSERT_THROW(expand_dims.accept(&tv), std::exception);
+}
+
+TEST(CircleExpandDimsTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleExpandDims expand_dims;
+
+ TestVisitor tv;
+ ASSERT_THROW(expand_dims.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleFill.test.cpp b/compiler/luci/lang/src/Nodes/CircleFill.test.cpp
new file mode 100644
index 000000000..4555da1cb
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleFill.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleFill.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleFillTest, constructor_P)
+{
+ luci::CircleFill fill;
+
+ ASSERT_EQ(fill.dialect(), luci::CircleDialect::get());
+ ASSERT_EQ(fill.opcode(), luci::CircleOpcode::FILL);
+
+ ASSERT_EQ(nullptr, fill.dims());
+ ASSERT_EQ(nullptr, fill.value());
+}
+
+TEST(CircleFillTest, input_NEG)
+{
+ luci::CircleFill fill_node;
+ luci::CircleFill node;
+
+ fill_node.dims(&node);
+ fill_node.value(&node);
+ ASSERT_NE(nullptr, fill_node.dims());
+ ASSERT_NE(nullptr, fill_node.value());
+
+ fill_node.dims(nullptr);
+ fill_node.value(nullptr);
+ ASSERT_EQ(nullptr, fill_node.dims());
+ ASSERT_EQ(nullptr, fill_node.value());
+}
+
+TEST(CircleFillTest, arity_NEG)
+{
+ luci::CircleFill fill_node;
+
+ ASSERT_NO_THROW(fill_node.arg(1));
+ ASSERT_THROW(fill_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleFillTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleFill fill_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(fill_node.accept(&tv), std::exception);
+}
+
+TEST(CircleFillTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleFill fill_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(fill_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleFloor.test.cpp b/compiler/luci/lang/src/Nodes/CircleFloor.test.cpp
new file mode 100644
index 000000000..38d38a0da
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleFloor.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleFloor.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleFloorTest, constructor)
+{
+ luci::CircleFloor floor_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), floor_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::FLOOR, floor_node.opcode());
+
+ ASSERT_EQ(nullptr, floor_node.x());
+}
+
+TEST(CircleFloorTest, input_NEG)
+{
+ luci::CircleFloor floor_node;
+ luci::CircleFloor node;
+
+ floor_node.x(&node);
+ ASSERT_NE(nullptr, floor_node.x());
+
+ floor_node.x(nullptr);
+ ASSERT_EQ(nullptr, floor_node.x());
+}
+
+TEST(CircleFloorTest, arity_NEG)
+{
+ luci::CircleFloor floor_node;
+
+ ASSERT_NO_THROW(floor_node.arg(0));
+ ASSERT_THROW(floor_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleFloorTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleFloor floor_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(floor_node.accept(&tv), std::exception);
+}
+
+TEST(CircleFloorTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleFloor floor_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(floor_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleFloorDiv.test.cpp b/compiler/luci/lang/src/Nodes/CircleFloorDiv.test.cpp
new file mode 100644
index 000000000..6c52eee73
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleFloorDiv.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleFloorDiv.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleFloorDivTest, constructor_P)
+{
+ luci::CircleFloorDiv floordiv_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), floordiv_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::FLOOR_DIV, floordiv_node.opcode());
+
+ ASSERT_EQ(nullptr, floordiv_node.x());
+ ASSERT_EQ(nullptr, floordiv_node.y());
+}
+
+TEST(CircleFloorDivTest, input_NEG)
+{
+ luci::CircleFloorDiv floordiv_node;
+ luci::CircleFloorDiv node;
+
+ floordiv_node.x(&node);
+ floordiv_node.y(&node);
+ ASSERT_NE(nullptr, floordiv_node.x());
+ ASSERT_NE(nullptr, floordiv_node.y());
+
+ floordiv_node.x(nullptr);
+ floordiv_node.y(nullptr);
+ ASSERT_EQ(nullptr, floordiv_node.x());
+ ASSERT_EQ(nullptr, floordiv_node.y());
+}
+
+TEST(CircleFloorDivTest, arity_NEG)
+{
+ luci::CircleFloorDiv floordiv_node;
+
+ ASSERT_NO_THROW(floordiv_node.arg(1));
+ ASSERT_THROW(floordiv_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleFloorDivTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleFloorDiv floordiv_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(floordiv_node.accept(&tv), std::exception);
+}
+
+TEST(CircleFloorDivTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleFloorDiv floordiv_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(floordiv_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleFloorMod.test.cpp b/compiler/luci/lang/src/Nodes/CircleFloorMod.test.cpp
new file mode 100644
index 000000000..c3fa187f2
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleFloorMod.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleFloorMod.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleFloorModTest, constructor)
+{
+ luci::CircleFloorMod floormod_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), floormod_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::FLOOR_MOD, floormod_node.opcode());
+
+ ASSERT_EQ(nullptr, floormod_node.x());
+ ASSERT_EQ(nullptr, floormod_node.y());
+}
+
+TEST(CircleFloorModTest, input_NEG)
+{
+ luci::CircleFloorMod floormod_node;
+ luci::CircleFloorMod node;
+
+ floormod_node.x(&node);
+ floormod_node.y(&node);
+ ASSERT_NE(nullptr, floormod_node.x());
+ ASSERT_NE(nullptr, floormod_node.y());
+
+ floormod_node.x(nullptr);
+ floormod_node.y(nullptr);
+ ASSERT_EQ(nullptr, floormod_node.x());
+ ASSERT_EQ(nullptr, floormod_node.y());
+}
+
+TEST(CircleFloorModTest, arity_NEG)
+{
+ luci::CircleFloorMod floormod_node;
+
+ ASSERT_NO_THROW(floormod_node.arg(1));
+ ASSERT_THROW(floormod_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleFloorModTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleFloorMod floormod_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(floormod_node.accept(&tv), std::exception);
+}
+
+TEST(CircleFloorModTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleFloorMod floormod_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(floormod_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp b/compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp
index 994dcd239..bb0e3c51b 100644
--- a/compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleFullyConnected.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,11 +25,66 @@ TEST(CircleFullyConnectedTest, constructor)
{
luci::CircleFullyConnected fc_node;
- ASSERT_EQ(fc_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(fc_node.opcode(), luci::CircleOpcode::FULLY_CONNECTED);
+ ASSERT_EQ(luci::CircleDialect::get(), fc_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::FULLY_CONNECTED, fc_node.opcode());
- ASSERT_EQ(fc_node.input(), nullptr);
- ASSERT_EQ(fc_node.weights(), nullptr);
- ASSERT_EQ(fc_node.bias(), nullptr);
- ASSERT_EQ(fc_node.fusedActivationFunction(), luci::FusedActFunc::UNDEFINED);
+ ASSERT_EQ(nullptr, fc_node.input());
+ ASSERT_EQ(nullptr, fc_node.weights());
+ ASSERT_EQ(nullptr, fc_node.bias());
+ ASSERT_EQ(luci::FusedActFunc::UNDEFINED, fc_node.fusedActivationFunction());
+}
+
+TEST(CircleFullyConnectedTest, input_NEG)
+{
+ luci::CircleFullyConnected fc_node;
+ luci::CircleFullyConnected node;
+
+ fc_node.input(&node);
+ fc_node.weights(&node);
+ fc_node.bias(&node);
+ ASSERT_NE(nullptr, fc_node.input());
+ ASSERT_NE(nullptr, fc_node.weights());
+ ASSERT_NE(nullptr, fc_node.bias());
+
+ fc_node.input(nullptr);
+ fc_node.weights(nullptr);
+ fc_node.bias(nullptr);
+ ASSERT_EQ(nullptr, fc_node.input());
+ ASSERT_EQ(nullptr, fc_node.weights());
+ ASSERT_EQ(nullptr, fc_node.bias());
+
+ fc_node.fusedActivationFunction(luci::FusedActFunc::RELU);
+ ASSERT_NE(luci::FusedActFunc::UNDEFINED, fc_node.fusedActivationFunction());
+}
+
+TEST(CircleFullyConnectedTest, arity_NEG)
+{
+ luci::CircleFullyConnected fc_node;
+
+ ASSERT_NO_THROW(fc_node.arg(2));
+ ASSERT_THROW(fc_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleFullyConnectedTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleFullyConnected fc_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(fc_node.accept(&tv), std::exception);
+}
+
+TEST(CircleFullyConnectedTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleFullyConnected fc_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(fc_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleGather.test.cpp b/compiler/luci/lang/src/Nodes/CircleGather.test.cpp
index 4eace9a02..5194d6bdd 100644
--- a/compiler/luci/lang/src/Nodes/CircleGather.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleGather.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleGather.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,10 +25,61 @@ TEST(CircleGatherTest, constructor)
{
luci::CircleGather gather_node;
- ASSERT_EQ(gather_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(gather_node.opcode(), luci::CircleOpcode::GATHER);
+ ASSERT_EQ(luci::CircleDialect::get(), gather_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::GATHER, gather_node.opcode());
- ASSERT_EQ(gather_node.input(), nullptr);
- ASSERT_EQ(gather_node.positions(), nullptr);
- ASSERT_EQ(gather_node.axis(), 0);
+ ASSERT_EQ(nullptr, gather_node.params());
+ ASSERT_EQ(nullptr, gather_node.indices());
+ ASSERT_EQ(0, gather_node.axis());
+}
+
+TEST(CircleGatherTest, input_NEG)
+{
+ luci::CircleGather gather_node;
+ luci::CircleGather node;
+
+ gather_node.params(&node);
+ gather_node.indices(&node);
+ ASSERT_NE(nullptr, gather_node.params());
+ ASSERT_NE(nullptr, gather_node.indices());
+
+ gather_node.params(nullptr);
+ gather_node.indices(nullptr);
+ ASSERT_EQ(nullptr, gather_node.params());
+ ASSERT_EQ(nullptr, gather_node.indices());
+
+ gather_node.axis(1);
+ ASSERT_NE(0, gather_node.axis());
+}
+
+TEST(CircleGatherTest, arity_NEG)
+{
+ luci::CircleGather gather_node;
+
+ ASSERT_NO_THROW(gather_node.arg(1));
+ ASSERT_THROW(gather_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleGatherTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleGather gather_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(gather_node.accept(&tv), std::exception);
+}
+
+TEST(CircleGatherTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleGather gather_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(gather_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleGatherNd.test.cpp b/compiler/luci/lang/src/Nodes/CircleGatherNd.test.cpp
new file mode 100644
index 000000000..1402e6e45
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleGatherNd.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleGatherNd.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleGatherNdTest, constructor)
+{
+ luci::CircleGatherNd gather_nd_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), gather_nd_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::GATHER_ND, gather_nd_node.opcode());
+
+ ASSERT_EQ(nullptr, gather_nd_node.params());
+ ASSERT_EQ(nullptr, gather_nd_node.indices());
+}
+
+TEST(CircleGatherNdTest, input_NEG)
+{
+ luci::CircleGatherNd gather_nd_node;
+ luci::CircleGatherNd node;
+
+ gather_nd_node.params(&node);
+ gather_nd_node.indices(&node);
+ ASSERT_NE(nullptr, gather_nd_node.params());
+ ASSERT_NE(nullptr, gather_nd_node.indices());
+
+ gather_nd_node.params(nullptr);
+ gather_nd_node.indices(nullptr);
+ ASSERT_EQ(nullptr, gather_nd_node.params());
+ ASSERT_EQ(nullptr, gather_nd_node.indices());
+}
+
+TEST(CircleGatherNdTest, arity_NEG)
+{
+ luci::CircleGatherNd gather_nd_node;
+
+ ASSERT_NO_THROW(gather_nd_node.arg(1));
+ ASSERT_THROW(gather_nd_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleGatherNdTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleGatherNd gather_nd_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(gather_nd_node.accept(&tv), std::exception);
+}
+
+TEST(CircleGatherNdTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleGatherNd gather_nd_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(gather_nd_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleGreater.test.cpp b/compiler/luci/lang/src/Nodes/CircleGreater.test.cpp
new file mode 100644
index 000000000..9a2b5f9f9
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleGreater.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleGreater.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleGreaterTest, constructor_P)
+{
+ luci::CircleGreater greater_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), greater_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::GREATER, greater_node.opcode());
+
+ ASSERT_EQ(nullptr, greater_node.x());
+ ASSERT_EQ(nullptr, greater_node.y());
+}
+
+TEST(CircleGreaterTest, input_NEG)
+{
+ luci::CircleGreater greater_node;
+ luci::CircleGreater node;
+
+ greater_node.x(&node);
+ greater_node.y(&node);
+ ASSERT_NE(nullptr, greater_node.x());
+ ASSERT_NE(nullptr, greater_node.y());
+
+ greater_node.x(nullptr);
+ greater_node.y(nullptr);
+ ASSERT_EQ(nullptr, greater_node.x());
+ ASSERT_EQ(nullptr, greater_node.y());
+}
+
+TEST(CircleGreaterTest, arity_NEG)
+{
+ luci::CircleGreater greater_node;
+
+ ASSERT_NO_THROW(greater_node.arg(1));
+ ASSERT_THROW(greater_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleGreaterTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleGreater greater_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(greater_node.accept(&tv), std::exception);
+}
+
+TEST(CircleGreaterTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleGreater greater_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(greater_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleGreaterEqual.test.cpp b/compiler/luci/lang/src/Nodes/CircleGreaterEqual.test.cpp
new file mode 100644
index 000000000..51c22b707
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleGreaterEqual.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleGreaterEqual.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleGreaterEqualTest, constructor_P)
+{
+ luci::CircleGreaterEqual greater_equal_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), greater_equal_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::GREATER_EQUAL, greater_equal_node.opcode());
+
+ ASSERT_EQ(nullptr, greater_equal_node.x());
+ ASSERT_EQ(nullptr, greater_equal_node.y());
+}
+
+TEST(CircleGreaterEqualTest, input_NEG)
+{
+ luci::CircleGreaterEqual greater_equal_node;
+ luci::CircleGreaterEqual node;
+
+ greater_equal_node.x(&node);
+ greater_equal_node.y(&node);
+ ASSERT_NE(nullptr, greater_equal_node.x());
+ ASSERT_NE(nullptr, greater_equal_node.y());
+
+ greater_equal_node.x(nullptr);
+ greater_equal_node.y(nullptr);
+ ASSERT_EQ(nullptr, greater_equal_node.x());
+ ASSERT_EQ(nullptr, greater_equal_node.y());
+}
+
+TEST(CircleGreaterEqualTest, arity_NEG)
+{
+ luci::CircleGreaterEqual greater_equal_node;
+
+ ASSERT_NO_THROW(greater_equal_node.arg(1));
+ ASSERT_THROW(greater_equal_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleGreaterEqualTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleGreaterEqual greater_equal_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(greater_equal_node.accept(&tv), std::exception);
+}
+
+TEST(CircleGreaterEqualTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleGreaterEqual greater_equal_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(greater_equal_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleIf.test.cpp b/compiler/luci/lang/src/Nodes/CircleIf.test.cpp
new file mode 100644
index 000000000..e3c8c9f60
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleIf.test.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 "luci/IR/Nodes/CircleIf.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleIfTest, constructor)
+{
+ luci::CircleIf if_node(2, 2);
+
+ ASSERT_EQ(luci::CircleDialect::get(), if_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::IF, if_node.opcode());
+
+ ASSERT_EQ(2, if_node.input_count());
+ ASSERT_EQ(2, if_node.output_count());
+
+ ASSERT_EQ(nullptr, if_node.input(0));
+ ASSERT_EQ(nullptr, if_node.input(1));
+
+ ASSERT_EQ(-1, if_node.then_branch());
+ ASSERT_EQ(-1, if_node.else_branch());
+}
+
+TEST(CircleIfTestDeath, invalid_arity_NEG)
+{
+ ASSERT_DEBUG_DEATH(luci::CircleIf very_long_name_if_node(0, 1), "");
+}
+
+TEST(CircleIfTestDeath, invalid_output_count_NEG)
+{
+ ASSERT_DEBUG_DEATH(luci::CircleIf if_node(2, 0), "");
+}
+
+TEST(CircleIfTestDeath, invalid_input_get_index_NEG)
+{
+ luci::CircleIf if_node(2, 2);
+
+ EXPECT_ANY_THROW(if_node.input(100));
+}
+
+TEST(CircleIfTestDeath, invalid_input_set_index_NEG)
+{
+ luci::CircleIf if_node(2, 2);
+
+ EXPECT_ANY_THROW(if_node.input(100, nullptr));
+}
+
+TEST(CircleIfTestDeath, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleIf if_node(2, 2);
+
+ TestVisitor tv;
+ ASSERT_THROW(if_node.accept(&tv), std::exception);
+}
+
+TEST(CircleIfTestDeath, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleIf if_node(2, 2);
+
+ TestVisitor tv;
+ ASSERT_THROW(if_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleIfOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleIfOut.test.cpp
new file mode 100644
index 000000000..5154b6b28
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleIfOut.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleIfOut.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleIfOutTest, constructor)
+{
+ luci::CircleIfOut ifout_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), ifout_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CIRCLEIFOUT, ifout_node.opcode());
+
+ ASSERT_EQ(nullptr, ifout_node.input());
+ ASSERT_EQ(-1, ifout_node.index());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp b/compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp
index b87e81791..88a5b8c6c 100644
--- a/compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleInstanceNorm.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,12 +25,67 @@ TEST(CircleInstanceNormTest, constructor)
{
luci::CircleInstanceNorm instance_norm;
- ASSERT_EQ(instance_norm.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(instance_norm.opcode(), luci::CircleOpcode::INSTANCE_NORM);
+ ASSERT_EQ(luci::CircleDialect::get(), instance_norm.dialect());
+ ASSERT_EQ(luci::CircleOpcode::INSTANCE_NORM, instance_norm.opcode());
- ASSERT_EQ(instance_norm.input(), nullptr);
- ASSERT_EQ(instance_norm.gamma(), nullptr);
- ASSERT_EQ(instance_norm.beta(), nullptr);
+ ASSERT_EQ(nullptr, instance_norm.input());
+ ASSERT_EQ(nullptr, instance_norm.gamma());
+ ASSERT_EQ(nullptr, instance_norm.beta());
ASSERT_FLOAT_EQ(instance_norm.epsilon(), 1e-05);
- ASSERT_EQ(instance_norm.fusedActivationFunction(), luci::FusedActFunc::UNDEFINED);
+ ASSERT_EQ(luci::FusedActFunc::UNDEFINED, instance_norm.fusedActivationFunction());
+}
+
+TEST(CircleInstanceNormTest, input_NEG)
+{
+ luci::CircleInstanceNorm instance_norm;
+ luci::CircleInstanceNorm node;
+
+ instance_norm.input(&node);
+ instance_norm.gamma(&node);
+ instance_norm.beta(&node);
+ ASSERT_NE(nullptr, instance_norm.input());
+ ASSERT_NE(nullptr, instance_norm.gamma());
+ ASSERT_NE(nullptr, instance_norm.beta());
+
+ instance_norm.input(nullptr);
+ instance_norm.gamma(nullptr);
+ instance_norm.beta(nullptr);
+ ASSERT_EQ(nullptr, instance_norm.input());
+ ASSERT_EQ(nullptr, instance_norm.gamma());
+ ASSERT_EQ(nullptr, instance_norm.beta());
+
+ instance_norm.fusedActivationFunction(luci::FusedActFunc::RELU);
+ ASSERT_NE(luci::FusedActFunc::UNDEFINED, instance_norm.fusedActivationFunction());
+}
+
+TEST(CircleInstanceNormTest, arity_NEG)
+{
+ luci::CircleInstanceNorm instance_norm;
+
+ ASSERT_NO_THROW(instance_norm.arg(2));
+ ASSERT_THROW(instance_norm.arg(3), std::out_of_range);
+}
+
+TEST(CircleInstanceNormTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleInstanceNorm instance_norm;
+
+ TestVisitor tv;
+ ASSERT_THROW(instance_norm.accept(&tv), std::exception);
+}
+
+TEST(CircleInstanceNormTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleInstanceNorm instance_norm;
+
+ TestVisitor tv;
+ ASSERT_THROW(instance_norm.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleL2Pool2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleL2Pool2D.test.cpp
new file mode 100644
index 000000000..cb779efa5
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleL2Pool2D.test.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleL2Pool2D.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleL2Pool2DTest, constructor)
+{
+ luci::CircleL2Pool2D l2pool2d_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), l2pool2d_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::L2_POOL_2D, l2pool2d_node.opcode());
+
+ ASSERT_EQ(nullptr, l2pool2d_node.value());
+ ASSERT_EQ(1, l2pool2d_node.filter()->h());
+ ASSERT_EQ(1, l2pool2d_node.filter()->w());
+ ASSERT_EQ(1, l2pool2d_node.stride()->h());
+ ASSERT_EQ(1, l2pool2d_node.stride()->w());
+ ASSERT_EQ(luci::FusedActFunc::UNDEFINED, l2pool2d_node.fusedActivationFunction());
+}
+
+TEST(CircleL2Pool2DTest, input_NEG)
+{
+ luci::CircleL2Pool2D l2pool2d_node;
+ luci::CircleL2Pool2D node;
+
+ l2pool2d_node.value(&node);
+ ASSERT_NE(nullptr, l2pool2d_node.value());
+
+ l2pool2d_node.value(nullptr);
+ ASSERT_EQ(nullptr, l2pool2d_node.value());
+
+ l2pool2d_node.stride()->h(2);
+ l2pool2d_node.stride()->w(2);
+ ASSERT_EQ(2, l2pool2d_node.stride()->h());
+ ASSERT_EQ(2, l2pool2d_node.stride()->w());
+
+ l2pool2d_node.filter()->h(2);
+ l2pool2d_node.filter()->w(2);
+ ASSERT_EQ(2, l2pool2d_node.filter()->h());
+ ASSERT_EQ(2, l2pool2d_node.filter()->w());
+
+ l2pool2d_node.fusedActivationFunction(luci::FusedActFunc::RELU);
+ ASSERT_NE(luci::FusedActFunc::UNDEFINED, l2pool2d_node.fusedActivationFunction());
+}
+
+TEST(CircleL2Pool2DTest, arity_NEG)
+{
+ luci::CircleL2Pool2D l2pool2d_node;
+
+ ASSERT_NO_THROW(l2pool2d_node.arg(0));
+ ASSERT_THROW(l2pool2d_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleL2Pool2DTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleL2Pool2D l2pool2d_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(l2pool2d_node.accept(&tv), std::exception);
+}
+
+TEST(CircleL2Pool2DTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleL2Pool2D l2pool2d_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(l2pool2d_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleLeakyRelu.test.cpp b/compiler/luci/lang/src/Nodes/CircleLeakyRelu.test.cpp
new file mode 100644
index 000000000..bacb444da
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleLeakyRelu.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleLeakyRelu.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleLeakyReluTest, constructor)
+{
+ luci::CircleLeakyRelu relu_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), relu_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LEAKY_RELU, relu_node.opcode());
+
+ ASSERT_EQ(nullptr, relu_node.features());
+
+ ASSERT_EQ(0.2f, relu_node.alpha());
+}
+
+TEST(CircleLeakyReluTest, input_NEG)
+{
+ luci::CircleLeakyRelu relu_node;
+ luci::CircleLeakyRelu node;
+
+ relu_node.features(&node);
+ ASSERT_NE(nullptr, relu_node.features());
+
+ relu_node.features(nullptr);
+ ASSERT_EQ(nullptr, relu_node.features());
+
+ relu_node.alpha(1.2f);
+ ASSERT_NE(0.2f, relu_node.alpha());
+}
+
+TEST(CircleLeakyReluTest, arity_NEG)
+{
+ luci::CircleLeakyRelu relu_node;
+
+ ASSERT_NO_THROW(relu_node.arg(0));
+ ASSERT_THROW(relu_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleLeakyReluTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLeakyRelu relu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(relu_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLeakyReluTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLeakyRelu relu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(relu_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleLess.test.cpp b/compiler/luci/lang/src/Nodes/CircleLess.test.cpp
new file mode 100644
index 000000000..ec454dfb5
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleLess.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleLess.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleLessTest, constructor_P)
+{
+ luci::CircleLess less_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), less_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LESS, less_node.opcode());
+
+ ASSERT_EQ(nullptr, less_node.x());
+ ASSERT_EQ(nullptr, less_node.y());
+}
+
+TEST(CircleLessTest, input_NEG)
+{
+ luci::CircleLess less_node;
+ luci::CircleLess node;
+
+ less_node.x(&node);
+ less_node.y(&node);
+ ASSERT_NE(nullptr, less_node.x());
+ ASSERT_NE(nullptr, less_node.y());
+
+ less_node.x(nullptr);
+ less_node.y(nullptr);
+ ASSERT_EQ(nullptr, less_node.x());
+ ASSERT_EQ(nullptr, less_node.y());
+}
+
+TEST(CircleLessTest, arity_NEG)
+{
+ luci::CircleLess less_node;
+
+ ASSERT_NO_THROW(less_node.arg(1));
+ ASSERT_THROW(less_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleLessTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLess less_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(less_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLessTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLess less_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(less_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleLessEqual.test.cpp b/compiler/luci/lang/src/Nodes/CircleLessEqual.test.cpp
new file mode 100644
index 000000000..baa9202ae
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleLessEqual.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleLessEqual.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleLessEqualTest, constructor_P)
+{
+ luci::CircleLessEqual less_equal_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), less_equal_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LESS_EQUAL, less_equal_node.opcode());
+
+ ASSERT_EQ(nullptr, less_equal_node.x());
+ ASSERT_EQ(nullptr, less_equal_node.y());
+}
+
+TEST(CircleLessEqualTest, input_NEG)
+{
+ luci::CircleLessEqual less_equal_node;
+ luci::CircleLessEqual node;
+
+ less_equal_node.x(&node);
+ less_equal_node.y(&node);
+ ASSERT_NE(nullptr, less_equal_node.x());
+ ASSERT_NE(nullptr, less_equal_node.y());
+
+ less_equal_node.x(nullptr);
+ less_equal_node.y(nullptr);
+ ASSERT_EQ(nullptr, less_equal_node.x());
+ ASSERT_EQ(nullptr, less_equal_node.y());
+}
+
+TEST(CircleLessEqualTest, arity_NEG)
+{
+ luci::CircleLessEqual less_equal_node;
+
+ ASSERT_NO_THROW(less_equal_node.arg(1));
+ ASSERT_THROW(less_equal_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleLessEqualTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLessEqual less_equal_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(less_equal_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLessEqualTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLessEqual less_equal_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(less_equal_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleLocalResponseNormalization.test.cpp b/compiler/luci/lang/src/Nodes/CircleLocalResponseNormalization.test.cpp
new file mode 100644
index 000000000..1b1bf67bd
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleLocalResponseNormalization.test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleLocalResponseNormalization.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleLocalResponseNormalizationTest, constructor_P)
+{
+ luci::CircleLocalResponseNormalization local_response_normalization_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), local_response_normalization_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LOCAL_RESPONSE_NORMALIZATION,
+ local_response_normalization_node.opcode());
+
+ ASSERT_EQ(nullptr, local_response_normalization_node.input());
+ ASSERT_EQ(5, local_response_normalization_node.radius());
+ ASSERT_EQ(1.0f, local_response_normalization_node.bias());
+ ASSERT_EQ(1.0f, local_response_normalization_node.alpha());
+ ASSERT_EQ(0.5f, local_response_normalization_node.beta());
+}
+
+TEST(CircleLocalResponseNormalizationTest, input_NEG)
+{
+ luci::CircleLocalResponseNormalization local_response_normalization_node;
+ luci::CircleLocalResponseNormalization node;
+
+ local_response_normalization_node.input(&node);
+ ASSERT_NE(nullptr, local_response_normalization_node.input());
+
+ local_response_normalization_node.input(nullptr);
+ ASSERT_EQ(nullptr, local_response_normalization_node.input());
+
+ local_response_normalization_node.radius(100);
+ local_response_normalization_node.bias(100.0f);
+ local_response_normalization_node.alpha(100.0f);
+ local_response_normalization_node.beta(100.0f);
+ ASSERT_NE(5, local_response_normalization_node.radius());
+ ASSERT_NE(1.0f, local_response_normalization_node.bias());
+ ASSERT_NE(1.0f, local_response_normalization_node.alpha());
+ ASSERT_NE(0.5f, local_response_normalization_node.beta());
+}
+
+TEST(CircleLocalResponseNormalizationTest, arity_NEG)
+{
+ luci::CircleLocalResponseNormalization local_response_normalization_node;
+
+ ASSERT_NO_THROW(local_response_normalization_node.arg(0));
+ ASSERT_THROW(local_response_normalization_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleLocalResponseNormalizationTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLocalResponseNormalization local_response_normalization_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(local_response_normalization_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLocalResponseNormalizationTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLocalResponseNormalization local_response_normalization_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(local_response_normalization_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleLog.test.cpp b/compiler/luci/lang/src/Nodes/CircleLog.test.cpp
new file mode 100644
index 000000000..0bb9ee76e
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleLog.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleLog.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleLogTest, constructor)
+{
+ luci::CircleLog log_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), log_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LOG, log_node.opcode());
+
+ ASSERT_EQ(nullptr, log_node.x());
+}
+
+TEST(CircleLogTest, input_NEG)
+{
+ luci::CircleLog log_node;
+ luci::CircleLog node;
+
+ log_node.x(&node);
+ ASSERT_NE(nullptr, log_node.x());
+
+ log_node.x(nullptr);
+ ASSERT_EQ(nullptr, log_node.x());
+}
+
+TEST(CircleLogTest, arity_NEG)
+{
+ luci::CircleLog log_node;
+
+ ASSERT_NO_THROW(log_node.arg(0));
+ ASSERT_THROW(log_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleLogTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLog log_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(log_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLogTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLog log_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(log_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleLogSoftmax.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogSoftmax.test.cpp
new file mode 100644
index 000000000..70977ae4f
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleLogSoftmax.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleLogSoftmax.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleLogSoftmaxTest, constructor)
+{
+ luci::CircleLogSoftmax log_softmax_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), log_softmax_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LOG_SOFTMAX, log_softmax_node.opcode());
+
+ ASSERT_EQ(nullptr, log_softmax_node.logits());
+}
+
+TEST(CircleLogSoftmaxTest, input_NEG)
+{
+ luci::CircleLogSoftmax log_softmax_node;
+ luci::CircleLogSoftmax node;
+
+ log_softmax_node.logits(&node);
+ ASSERT_NE(nullptr, log_softmax_node.logits());
+
+ log_softmax_node.logits(nullptr);
+ ASSERT_EQ(nullptr, log_softmax_node.logits());
+}
+
+TEST(CircleLogSoftmaxTest, arity_NEG)
+{
+ luci::CircleLogSoftmax log_softmax_node;
+
+ ASSERT_NO_THROW(log_softmax_node.arg(0));
+ ASSERT_THROW(log_softmax_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleLogSoftmaxTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLogSoftmax log_softmax_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(log_softmax_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLogSoftmaxTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLogSoftmax log_softmax_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(log_softmax_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleLogicalAnd.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogicalAnd.test.cpp
new file mode 100644
index 000000000..db378f022
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleLogicalAnd.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleLogicalAnd.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleLogicalAndTest, constructor_P)
+{
+ luci::CircleLogicalAnd and_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), and_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LOGICAL_AND, and_node.opcode());
+
+ ASSERT_EQ(nullptr, and_node.x());
+ ASSERT_EQ(nullptr, and_node.y());
+}
+
+TEST(CircleLogicalAndTest, input_NEG)
+{
+ luci::CircleLogicalAnd and_node;
+ luci::CircleLogicalAnd node;
+
+ and_node.x(&node);
+ and_node.y(&node);
+ ASSERT_NE(nullptr, and_node.x());
+ ASSERT_NE(nullptr, and_node.y());
+
+ and_node.x(nullptr);
+ and_node.y(nullptr);
+ ASSERT_EQ(nullptr, and_node.x());
+ ASSERT_EQ(nullptr, and_node.y());
+}
+
+TEST(CircleLogicalAndTest, arity_NEG)
+{
+ luci::CircleLogicalAnd and_node;
+
+ ASSERT_NO_THROW(and_node.arg(1));
+ ASSERT_THROW(and_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleLogicalAndTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLogicalAnd and_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(and_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLogicalAndTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLogicalAnd and_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(and_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp
index 360dd4711..0c2c02938 100644
--- a/compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleLogicalNot.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,8 +25,52 @@ TEST(CircleLogicalNotTest, constructor_P)
{
luci::CircleLogicalNot not_node;
- ASSERT_EQ(not_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(not_node.opcode(), luci::CircleOpcode::LOGICAL_NOT);
+ ASSERT_EQ(luci::CircleDialect::get(), not_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LOGICAL_NOT, not_node.opcode());
- ASSERT_EQ(not_node.x(), nullptr);
+ ASSERT_EQ(nullptr, not_node.x());
+}
+
+TEST(CircleLogicalNotTest, input_NEG)
+{
+ luci::CircleLogicalNot not_node;
+ luci::CircleLogicalNot node;
+
+ not_node.x(&node);
+ ASSERT_NE(nullptr, not_node.x());
+
+ not_node.x(nullptr);
+ ASSERT_EQ(nullptr, not_node.x());
+}
+
+TEST(CircleLogicalNotTest, arity_NEG)
+{
+ luci::CircleLogicalNot not_node;
+
+ ASSERT_NO_THROW(not_node.arg(0));
+ ASSERT_THROW(not_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleLogicalNotTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLogicalNot not_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(not_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLogicalNotTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLogicalNot not_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(not_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp
index 039db4afc..a08b863c7 100644
--- a/compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleLogicalOr.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CircleLogicalOrTest, constructor_P)
{
luci::CircleLogicalOr or_node;
- ASSERT_EQ(or_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(or_node.opcode(), luci::CircleOpcode::LOGICAL_OR);
+ ASSERT_EQ(luci::CircleDialect::get(), or_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LOGICAL_OR, or_node.opcode());
- ASSERT_EQ(or_node.x(), nullptr);
- ASSERT_EQ(or_node.y(), nullptr);
+ ASSERT_EQ(nullptr, or_node.x());
+ ASSERT_EQ(nullptr, or_node.y());
+}
+
+TEST(CircleLogicalOrTest, input_NEG)
+{
+ luci::CircleLogicalOr or_node;
+ luci::CircleLogicalOr node;
+
+ or_node.x(&node);
+ or_node.y(&node);
+ ASSERT_NE(nullptr, or_node.x());
+ ASSERT_NE(nullptr, or_node.y());
+
+ or_node.x(nullptr);
+ or_node.y(nullptr);
+ ASSERT_EQ(nullptr, or_node.x());
+ ASSERT_EQ(nullptr, or_node.y());
+}
+
+TEST(CircleLogicalOrTest, arity_NEG)
+{
+ luci::CircleLogicalOr or_node;
+
+ ASSERT_NO_THROW(or_node.arg(1));
+ ASSERT_THROW(or_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleLogicalOrTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLogicalOr or_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(or_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLogicalOrTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLogicalOr or_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(or_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleLogistic.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogistic.test.cpp
new file mode 100644
index 000000000..18efd869d
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleLogistic.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleLogistic.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleLogisticTest, constructor)
+{
+ luci::CircleLogistic logistic_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), logistic_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::LOGISTIC, logistic_node.opcode());
+
+ ASSERT_EQ(nullptr, logistic_node.x());
+}
+
+TEST(CircleLogisticTest, input_NEG)
+{
+ luci::CircleLogistic logistic_node;
+ luci::CircleLogistic node;
+
+ logistic_node.x(&node);
+ ASSERT_NE(nullptr, logistic_node.x());
+
+ logistic_node.x(nullptr);
+ ASSERT_EQ(nullptr, logistic_node.x());
+}
+
+TEST(CircleLogisticTest, arity_NEG)
+{
+ luci::CircleLogistic logistic_node;
+
+ ASSERT_NO_THROW(logistic_node.arg(0));
+ ASSERT_THROW(logistic_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleLogisticTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleLogistic logistic_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(logistic_node.accept(&tv), std::exception);
+}
+
+TEST(CircleLogisticTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleLogistic logistic_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(logistic_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleMatrixDiag.test.cpp b/compiler/luci/lang/src/Nodes/CircleMatrixDiag.test.cpp
new file mode 100644
index 000000000..9209cf1a4
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleMatrixDiag.test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleMatrixDiag.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleMatrixDiagTest, constructor_P)
+{
+ luci::CircleMatrixDiag matrix_diag_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), matrix_diag_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::MATRIX_DIAG, matrix_diag_node.opcode());
+
+ ASSERT_EQ(nullptr, matrix_diag_node.diagonal());
+}
+
+TEST(CircleMatrixDiagTest, input_NEG)
+{
+ luci::CircleMatrixDiag matrix_diag_node;
+ luci::CircleMatrixDiag node;
+
+ matrix_diag_node.diagonal(&node);
+
+ ASSERT_NE(nullptr, matrix_diag_node.diagonal());
+
+ matrix_diag_node.diagonal(nullptr);
+
+ ASSERT_EQ(nullptr, matrix_diag_node.diagonal());
+}
+
+TEST(CircleMatrixDiagTest, arity_NEG)
+{
+ luci::CircleMatrixDiag matrix_diag_node;
+
+ ASSERT_NO_THROW(matrix_diag_node.arg(0));
+ ASSERT_THROW(matrix_diag_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleMatrixDiagTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleMatrixDiag matrix_diag_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(matrix_diag_node.accept(&tv), std::exception);
+}
+
+TEST(CircleMatrixDiagTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleMatrixDiag matrix_diag_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(matrix_diag_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleMatrixSetDiag.test.cpp b/compiler/luci/lang/src/Nodes/CircleMatrixSetDiag.test.cpp
new file mode 100644
index 000000000..9dea9852e
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleMatrixSetDiag.test.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 "luci/IR/Nodes/CircleMatrixSetDiag.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleMatrixSetDiagTest, constructor_P)
+{
+ luci::CircleMatrixSetDiag matrix_set_diag_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), matrix_set_diag_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::MATRIX_SET_DIAG, matrix_set_diag_node.opcode());
+
+ ASSERT_EQ(nullptr, matrix_set_diag_node.input());
+ ASSERT_EQ(nullptr, matrix_set_diag_node.diagonal());
+}
+
+TEST(CircleMatrixSetDiagTest, input_NEG)
+{
+ luci::CircleMatrixSetDiag matrix_set_diag_node;
+ luci::CircleMatrixSetDiag node;
+
+ matrix_set_diag_node.input(&node);
+ matrix_set_diag_node.diagonal(&node);
+
+ ASSERT_NE(nullptr, matrix_set_diag_node.input());
+ ASSERT_NE(nullptr, matrix_set_diag_node.diagonal());
+
+ matrix_set_diag_node.input(nullptr);
+ matrix_set_diag_node.diagonal(nullptr);
+
+ ASSERT_EQ(nullptr, matrix_set_diag_node.input());
+ ASSERT_EQ(nullptr, matrix_set_diag_node.diagonal());
+}
+
+TEST(CircleMatrixSetDiagTest, arity_NEG)
+{
+ luci::CircleMatrixSetDiag matrix_set_diag_node;
+
+ ASSERT_NO_THROW(matrix_set_diag_node.arg(0));
+ ASSERT_NO_THROW(matrix_set_diag_node.arg(1));
+ ASSERT_THROW(matrix_set_diag_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleMatrixSetDiagTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleMatrixSetDiag matrix_set_diag_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(matrix_set_diag_node.accept(&tv), std::exception);
+}
+
+TEST(CircleMatrixSetDiagTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleMatrixSetDiag matrix_set_diag_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(matrix_set_diag_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp
index 874ecec0e..cb6c016e3 100644
--- a/compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleMaxPool2D.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,10 +25,66 @@ TEST(CircleMaxPool2DTest, constructor_P)
{
luci::CircleMaxPool2D maxpool2d_node;
- ASSERT_EQ(maxpool2d_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(maxpool2d_node.opcode(), luci::CircleOpcode::MAX_POOL_2D);
+ ASSERT_EQ(luci::CircleDialect::get(), maxpool2d_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::MAX_POOL_2D, maxpool2d_node.opcode());
- ASSERT_EQ(maxpool2d_node.value(), nullptr);
- ASSERT_NE(maxpool2d_node.filter(), nullptr);
- ASSERT_NE(maxpool2d_node.stride(), nullptr);
+ ASSERT_EQ(nullptr, maxpool2d_node.value());
+ ASSERT_EQ(luci::Padding::UNDEFINED, maxpool2d_node.padding());
+ ASSERT_EQ(1, maxpool2d_node.filter()->h());
+ ASSERT_EQ(1, maxpool2d_node.filter()->w());
+ ASSERT_EQ(1, maxpool2d_node.stride()->h());
+ ASSERT_EQ(1, maxpool2d_node.stride()->w());
+}
+
+TEST(CircleMaxPool2DTest, input_NEG)
+{
+ luci::CircleMaxPool2D maxpool2d_node;
+ luci::CircleMaxPool2D node;
+
+ maxpool2d_node.value(&node);
+ ASSERT_NE(nullptr, maxpool2d_node.value());
+
+ maxpool2d_node.value(nullptr);
+ ASSERT_EQ(nullptr, maxpool2d_node.value());
+
+ maxpool2d_node.filter()->h(2);
+ maxpool2d_node.filter()->w(2);
+ maxpool2d_node.stride()->h(2);
+ maxpool2d_node.stride()->w(2);
+ ASSERT_NE(1, maxpool2d_node.filter()->h());
+ ASSERT_NE(1, maxpool2d_node.filter()->w());
+ ASSERT_NE(1, maxpool2d_node.stride()->h());
+ ASSERT_NE(1, maxpool2d_node.stride()->w());
+}
+
+TEST(CircleMaxPool2DTest, arity_NEG)
+{
+ luci::CircleMaxPool2D maxpool2d_node;
+
+ ASSERT_NO_THROW(maxpool2d_node.arg(0));
+ ASSERT_THROW(maxpool2d_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleMaxPool2DTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleMaxPool2D maxpool2d_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(maxpool2d_node.accept(&tv), std::exception);
+}
+
+TEST(CircleMaxPool2DTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleMaxPool2D maxpool2d_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(maxpool2d_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp b/compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp
index efe62f11a..3fc6f1114 100644
--- a/compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleMaximum.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CircleMaximumTest, constructor_P)
{
luci::CircleMaximum max_node;
- ASSERT_EQ(max_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(max_node.opcode(), luci::CircleOpcode::MAXIMUM);
+ ASSERT_EQ(luci::CircleDialect::get(), max_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::MAXIMUM, max_node.opcode());
- ASSERT_EQ(max_node.x(), nullptr);
- ASSERT_EQ(max_node.y(), nullptr);
+ ASSERT_EQ(nullptr, max_node.x());
+ ASSERT_EQ(nullptr, max_node.y());
+}
+
+TEST(CircleMaximumTest, input_NEG)
+{
+ luci::CircleMaximum max_node;
+ luci::CircleMaximum node;
+
+ max_node.x(&node);
+ max_node.y(&node);
+ ASSERT_NE(nullptr, max_node.x());
+ ASSERT_NE(nullptr, max_node.y());
+
+ max_node.x(nullptr);
+ max_node.y(nullptr);
+ ASSERT_EQ(nullptr, max_node.x());
+ ASSERT_EQ(nullptr, max_node.y());
+}
+
+TEST(CircleMaximumTest, arity_NEG)
+{
+ luci::CircleMaximum max_node;
+
+ ASSERT_NO_THROW(max_node.arg(1));
+ ASSERT_THROW(max_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleMaximumTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleMaximum max_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(max_node.accept(&tv), std::exception);
+}
+
+TEST(CircleMaximumTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleMaximum max_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(max_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleMean.test.cpp b/compiler/luci/lang/src/Nodes/CircleMean.test.cpp
new file mode 100644
index 000000000..743063968
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleMean.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleMean.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleMeanTest, constructor)
+{
+ luci::CircleMean mean_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), mean_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::MEAN, mean_node.opcode());
+
+ ASSERT_EQ(nullptr, mean_node.input());
+ ASSERT_EQ(nullptr, mean_node.reduction_indices());
+
+ ASSERT_FALSE(mean_node.keep_dims());
+}
+
+TEST(CircleMeanTest, input_NEG)
+{
+ luci::CircleMean mean_node;
+ luci::CircleMean node;
+
+ mean_node.input(&node);
+ mean_node.reduction_indices(&node);
+ ASSERT_NE(nullptr, mean_node.input());
+ ASSERT_NE(nullptr, mean_node.reduction_indices());
+
+ mean_node.input(nullptr);
+ mean_node.reduction_indices(nullptr);
+ ASSERT_EQ(nullptr, mean_node.input());
+ ASSERT_EQ(nullptr, mean_node.reduction_indices());
+
+ mean_node.keep_dims(true);
+ ASSERT_TRUE(mean_node.keep_dims());
+}
+
+TEST(CircleMeanTest, arity_NEG)
+{
+ luci::CircleMean mean_node;
+
+ ASSERT_NO_THROW(mean_node.arg(1));
+ ASSERT_THROW(mean_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleMeanTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleMean mean_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(mean_node.accept(&tv), std::exception);
+}
+
+TEST(CircleMeanTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleMean mean_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(mean_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleMinimum.test.cpp b/compiler/luci/lang/src/Nodes/CircleMinimum.test.cpp
new file mode 100644
index 000000000..19fe69fb7
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleMinimum.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleMinimum.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleMinimumTest, constructor_P)
+{
+ luci::CircleMinimum min_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), min_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::MINIMUM, min_node.opcode());
+
+ ASSERT_EQ(nullptr, min_node.x());
+ ASSERT_EQ(nullptr, min_node.y());
+}
+
+TEST(CircleMinimumTest, input_NEG)
+{
+ luci::CircleMinimum min_node;
+ luci::CircleMinimum node;
+
+ min_node.x(&node);
+ min_node.y(&node);
+ ASSERT_NE(nullptr, min_node.x());
+ ASSERT_NE(nullptr, min_node.y());
+
+ min_node.x(nullptr);
+ min_node.y(nullptr);
+ ASSERT_EQ(nullptr, min_node.x());
+ ASSERT_EQ(nullptr, min_node.y());
+}
+
+TEST(CircleMinimumTest, arity_NEG)
+{
+ luci::CircleMinimum min_node;
+
+ ASSERT_NO_THROW(min_node.arg(1));
+ ASSERT_THROW(min_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleMinimumTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleMinimum min_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(min_node.accept(&tv), std::exception);
+}
+
+TEST(CircleMinimumTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleMinimum min_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(min_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleMirrorPad.test.cpp b/compiler/luci/lang/src/Nodes/CircleMirrorPad.test.cpp
new file mode 100644
index 000000000..9ba6bf58a
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleMirrorPad.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleMirrorPad.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleMirrorPadTest, constructor_P)
+{
+ luci::CircleMirrorPad pad_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), pad_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::MIRROR_PAD, pad_node.opcode());
+
+ ASSERT_EQ(nullptr, pad_node.input());
+ ASSERT_EQ(nullptr, pad_node.paddings());
+
+ ASSERT_EQ(luci::MirrorPadMode::REFLECT, pad_node.mode());
+}
+
+TEST(CircleMirrorPadTest, input_NEG)
+{
+ luci::CircleMirrorPad pad_node;
+ luci::CircleMirrorPad node;
+
+ pad_node.input(&node);
+ pad_node.paddings(&node);
+ ASSERT_NE(nullptr, pad_node.input());
+ ASSERT_NE(nullptr, pad_node.paddings());
+
+ pad_node.input(nullptr);
+ pad_node.paddings(nullptr);
+ ASSERT_EQ(nullptr, pad_node.input());
+ ASSERT_EQ(nullptr, pad_node.paddings());
+
+ pad_node.mode(luci::MirrorPadMode::SYMMETRIC);
+ ASSERT_NE(luci::MirrorPadMode::REFLECT, pad_node.mode());
+}
+
+TEST(CircleMirrorPadTest, arity_NEG)
+{
+ luci::CircleMirrorPad pad_node;
+
+ ASSERT_NO_THROW(pad_node.arg(1));
+ ASSERT_THROW(pad_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleMirrorPadTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleMirrorPad pad_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(pad_node.accept(&tv), std::exception);
+}
+
+TEST(CircleMirrorPadTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleMirrorPad pad_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(pad_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleMul.test.cpp b/compiler/luci/lang/src/Nodes/CircleMul.test.cpp
index f9eca42f9..3c26d08ca 100644
--- a/compiler/luci/lang/src/Nodes/CircleMul.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleMul.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleMul.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CircleMulTest, constructor_P)
{
luci::CircleMul mul_node;
- ASSERT_EQ(mul_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(mul_node.opcode(), luci::CircleOpcode::MUL);
+ ASSERT_EQ(luci::CircleDialect::get(), mul_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::MUL, mul_node.opcode());
- ASSERT_EQ(mul_node.x(), nullptr);
- ASSERT_EQ(mul_node.y(), nullptr);
+ ASSERT_EQ(nullptr, mul_node.x());
+ ASSERT_EQ(nullptr, mul_node.y());
+}
+
+TEST(CircleMulTest, input_NEG)
+{
+ luci::CircleMul mul_node;
+ luci::CircleMul node;
+
+ mul_node.x(&node);
+ mul_node.y(&node);
+ ASSERT_NE(nullptr, mul_node.x());
+ ASSERT_NE(nullptr, mul_node.y());
+
+ mul_node.x(nullptr);
+ mul_node.y(nullptr);
+ ASSERT_EQ(nullptr, mul_node.x());
+ ASSERT_EQ(nullptr, mul_node.y());
+}
+
+TEST(CircleMulTest, arity_NEG)
+{
+ luci::CircleMul mul_node;
+
+ ASSERT_NO_THROW(mul_node.arg(1));
+ ASSERT_THROW(mul_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleMulTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleMul mul_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(mul_node.accept(&tv), std::exception);
+}
+
+TEST(CircleMulTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleMul mul_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(mul_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleNeg.test.cpp b/compiler/luci/lang/src/Nodes/CircleNeg.test.cpp
new file mode 100644
index 000000000..4bcfa48a6
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleNeg.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleNeg.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleNegTest, constructor)
+{
+ luci::CircleNeg neg_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), neg_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::NEG, neg_node.opcode());
+
+ ASSERT_EQ(nullptr, neg_node.x());
+}
+
+TEST(CircleNegTest, input_NEG)
+{
+ luci::CircleNeg neg_node;
+ luci::CircleNeg node;
+
+ neg_node.x(&node);
+ ASSERT_NE(nullptr, neg_node.x());
+
+ neg_node.x(nullptr);
+ ASSERT_EQ(nullptr, neg_node.x());
+}
+
+TEST(CircleNegTest, arity_NEG)
+{
+ luci::CircleNeg neg_node;
+
+ ASSERT_NO_THROW(neg_node.arg(0));
+ ASSERT_THROW(neg_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleNegTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleNeg neg_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(neg_node.accept(&tv), std::exception);
+}
+
+TEST(CircleNegTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleNeg neg_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(neg_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleNotEqual.test.cpp b/compiler/luci/lang/src/Nodes/CircleNotEqual.test.cpp
new file mode 100644
index 000000000..e464a7b96
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleNotEqual.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleNotEqual.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleNotEqualTest, constructor_P)
+{
+ luci::CircleNotEqual not_equal_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), not_equal_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::NOT_EQUAL, not_equal_node.opcode());
+
+ ASSERT_EQ(nullptr, not_equal_node.x());
+ ASSERT_EQ(nullptr, not_equal_node.y());
+}
+
+TEST(CircleNotEqualTest, input_NEG)
+{
+ luci::CircleNotEqual not_equal_node;
+ luci::CircleNotEqual node;
+
+ not_equal_node.x(&node);
+ not_equal_node.y(&node);
+ ASSERT_NE(nullptr, not_equal_node.x());
+ ASSERT_NE(nullptr, not_equal_node.y());
+
+ not_equal_node.x(nullptr);
+ not_equal_node.y(nullptr);
+ ASSERT_EQ(nullptr, not_equal_node.x());
+ ASSERT_EQ(nullptr, not_equal_node.y());
+}
+
+TEST(CircleNotEqualTest, arity_NEG)
+{
+ luci::CircleNotEqual not_equal_node;
+
+ ASSERT_NO_THROW(not_equal_node.arg(1));
+ ASSERT_THROW(not_equal_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleNotEqualTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleNotEqual not_equal_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(not_equal_node.accept(&tv), std::exception);
+}
+
+TEST(CircleNotEqualTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleNotEqual not_equal_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(not_equal_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleOneHot.test.cpp b/compiler/luci/lang/src/Nodes/CircleOneHot.test.cpp
new file mode 100644
index 000000000..18e1045cc
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleOneHot.test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleOneHot.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleOneHotTest, constructor)
+{
+ luci::CircleOneHot one_hot_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), one_hot_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ONE_HOT, one_hot_node.opcode());
+
+ ASSERT_EQ(nullptr, one_hot_node.indices());
+ ASSERT_EQ(nullptr, one_hot_node.depth());
+ ASSERT_EQ(nullptr, one_hot_node.on_value());
+ ASSERT_EQ(nullptr, one_hot_node.off_value());
+ ASSERT_EQ(-1, one_hot_node.axis());
+}
+
+TEST(CircleOneHotTest, input_NEG)
+{
+ luci::CircleOneHot one_hot_node;
+ luci::CircleOneHot node;
+
+ one_hot_node.indices(&node);
+ one_hot_node.depth(&node);
+ one_hot_node.on_value(&node);
+ one_hot_node.off_value(&node);
+ ASSERT_NE(nullptr, one_hot_node.indices());
+ ASSERT_NE(nullptr, one_hot_node.depth());
+ ASSERT_NE(nullptr, one_hot_node.on_value());
+ ASSERT_NE(nullptr, one_hot_node.off_value());
+
+ one_hot_node.indices(nullptr);
+ one_hot_node.depth(nullptr);
+ one_hot_node.on_value(nullptr);
+ one_hot_node.off_value(nullptr);
+ ASSERT_EQ(nullptr, one_hot_node.indices());
+ ASSERT_EQ(nullptr, one_hot_node.depth());
+ ASSERT_EQ(nullptr, one_hot_node.on_value());
+ ASSERT_EQ(nullptr, one_hot_node.off_value());
+
+ one_hot_node.axis(1);
+ ASSERT_NE(-1, one_hot_node.axis());
+}
+
+TEST(CircleOneHotTest, arity_NEG)
+{
+ luci::CircleOneHot one_hot_node;
+
+ ASSERT_NO_THROW(one_hot_node.arg(3));
+ ASSERT_THROW(one_hot_node.arg(4), std::out_of_range);
+}
+
+TEST(CircleOneHotTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleOneHot one_hot_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(one_hot_node.accept(&tv), std::exception);
+}
+
+TEST(CircleOneHotTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleOneHot one_hot_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(one_hot_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CirclePRelu.test.cpp b/compiler/luci/lang/src/Nodes/CirclePRelu.test.cpp
new file mode 100644
index 000000000..8355c6d97
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CirclePRelu.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CirclePRelu.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CirclePReluTest, constructor_P)
+{
+ luci::CirclePRelu prelu_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), prelu_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::PRELU, prelu_node.opcode());
+
+ ASSERT_EQ(nullptr, prelu_node.input());
+ ASSERT_EQ(nullptr, prelu_node.alpha());
+}
+
+TEST(CirclePReluTest, input_NEG)
+{
+ luci::CirclePRelu prelu_node;
+ luci::CirclePRelu node;
+
+ prelu_node.input(&node);
+ prelu_node.alpha(&node);
+ ASSERT_NE(nullptr, prelu_node.input());
+ ASSERT_NE(nullptr, prelu_node.alpha());
+
+ prelu_node.input(nullptr);
+ prelu_node.alpha(nullptr);
+ ASSERT_EQ(nullptr, prelu_node.input());
+ ASSERT_EQ(nullptr, prelu_node.alpha());
+}
+
+TEST(CirclePReluTest, arity_NEG)
+{
+ luci::CirclePRelu prelu_node;
+
+ ASSERT_NO_THROW(prelu_node.arg(1));
+ ASSERT_THROW(prelu_node.arg(2), std::out_of_range);
+}
+
+TEST(CirclePReluTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CirclePRelu prelu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(prelu_node.accept(&tv), std::exception);
+}
+
+TEST(CirclePReluTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CirclePRelu prelu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(prelu_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CirclePack.test.cpp b/compiler/luci/lang/src/Nodes/CirclePack.test.cpp
index 5c9a96f7c..5e64f0d89 100644
--- a/compiler/luci/lang/src/Nodes/CirclePack.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CirclePack.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CirclePack.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,12 +25,60 @@ TEST(CirclePackTest, constructor)
{
luci::CirclePack pack_node(3);
- ASSERT_EQ(pack_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(pack_node.opcode(), luci::CircleOpcode::PACK);
+ ASSERT_EQ(luci::CircleDialect::get(), pack_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::PACK, pack_node.opcode());
- ASSERT_EQ(pack_node.axis(), 0);
- ASSERT_EQ(pack_node.values_count(), 3);
- ASSERT_EQ(pack_node.values(0), nullptr);
- ASSERT_EQ(pack_node.values(1), nullptr);
- ASSERT_EQ(pack_node.values(2), nullptr);
+ ASSERT_EQ(0, pack_node.axis());
+ ASSERT_EQ(3, pack_node.values_count());
+ ASSERT_EQ(nullptr, pack_node.values(0));
+ ASSERT_EQ(nullptr, pack_node.values(1));
+ ASSERT_EQ(nullptr, pack_node.values(2));
+}
+
+TEST(CirclePackTest, input_NEG)
+{
+ luci::CirclePack pack_node(2);
+ luci::CirclePack node(2);
+
+ pack_node.values(0, &node);
+ pack_node.values(1, &node);
+ ASSERT_NE(nullptr, pack_node.values(0));
+ ASSERT_NE(nullptr, pack_node.values(1));
+
+ pack_node.values(0, nullptr);
+ pack_node.values(1, nullptr);
+ ASSERT_EQ(nullptr, pack_node.values(0));
+ ASSERT_EQ(nullptr, pack_node.values(1));
+}
+
+TEST(CirclePackTest, arity_NEG)
+{
+ luci::CirclePack pack_node(5);
+
+ ASSERT_NO_THROW(pack_node.arg(4));
+ ASSERT_THROW(pack_node.arg(5), std::out_of_range);
+}
+
+TEST(CirclePackTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CirclePack pack_node(2);
+
+ TestVisitor tv;
+ ASSERT_THROW(pack_node.accept(&tv), std::exception);
+}
+
+TEST(CirclePackTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CirclePack pack_node(2);
+
+ TestVisitor tv;
+ ASSERT_THROW(pack_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CirclePad.test.cpp b/compiler/luci/lang/src/Nodes/CirclePad.test.cpp
index 3a23fa0f0..12c66b7ea 100644
--- a/compiler/luci/lang/src/Nodes/CirclePad.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CirclePad.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CirclePad.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CirclePadTest, constructor_P)
{
luci::CirclePad pad_node;
- ASSERT_EQ(pad_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(pad_node.opcode(), luci::CircleOpcode::PAD);
+ ASSERT_EQ(luci::CircleDialect::get(), pad_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::PAD, pad_node.opcode());
- ASSERT_EQ(pad_node.input(), nullptr);
- ASSERT_EQ(pad_node.paddings(), nullptr);
+ ASSERT_EQ(nullptr, pad_node.input());
+ ASSERT_EQ(nullptr, pad_node.paddings());
+}
+
+TEST(CirclePadTest, input_NEG)
+{
+ luci::CirclePad pad_node;
+ luci::CirclePad node;
+
+ pad_node.input(&node);
+ pad_node.paddings(&node);
+ ASSERT_NE(nullptr, pad_node.input());
+ ASSERT_NE(nullptr, pad_node.paddings());
+
+ pad_node.input(nullptr);
+ pad_node.paddings(nullptr);
+ ASSERT_EQ(nullptr, pad_node.input());
+ ASSERT_EQ(nullptr, pad_node.paddings());
+}
+
+TEST(CirclePadTest, arity_NEG)
+{
+ luci::CirclePad pad_node;
+
+ ASSERT_NO_THROW(pad_node.arg(1));
+ ASSERT_THROW(pad_node.arg(2), std::out_of_range);
+}
+
+TEST(CirclePadTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CirclePad pad_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(pad_node.accept(&tv), std::exception);
+}
+
+TEST(CirclePadTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CirclePad pad_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(pad_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CirclePow.test.cpp b/compiler/luci/lang/src/Nodes/CirclePow.test.cpp
new file mode 100644
index 000000000..67ba0882b
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CirclePow.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CirclePow.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CirclePowTest, constructor_P)
+{
+ luci::CirclePow pow_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), pow_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::POW, pow_node.opcode());
+
+ ASSERT_EQ(nullptr, pow_node.x());
+ ASSERT_EQ(nullptr, pow_node.y());
+}
+
+TEST(CirclePowTest, input_NEG)
+{
+ luci::CirclePow pow_node;
+ luci::CirclePow node;
+
+ pow_node.x(&node);
+ pow_node.y(&node);
+ ASSERT_NE(nullptr, pow_node.x());
+ ASSERT_NE(nullptr, pow_node.y());
+
+ pow_node.x(nullptr);
+ pow_node.y(nullptr);
+ ASSERT_EQ(nullptr, pow_node.x());
+ ASSERT_EQ(nullptr, pow_node.y());
+}
+
+TEST(CirclePowTest, arity_NEG)
+{
+ luci::CirclePow pow_node;
+
+ ASSERT_NO_THROW(pow_node.arg(1));
+ ASSERT_THROW(pow_node.arg(2), std::out_of_range);
+}
+
+TEST(CirclePowTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CirclePow pow_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(pow_node.accept(&tv), std::exception);
+}
+
+TEST(CirclePowTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CirclePow pow_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(pow_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleRange.test.cpp b/compiler/luci/lang/src/Nodes/CircleRange.test.cpp
new file mode 100644
index 000000000..dd54dfd6e
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleRange.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleRange.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleRangeTest, constructor)
+{
+ luci::CircleRange range_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), range_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RANGE, range_node.opcode());
+
+ ASSERT_EQ(nullptr, range_node.start());
+ ASSERT_EQ(nullptr, range_node.limit());
+ ASSERT_EQ(nullptr, range_node.delta());
+}
+
+TEST(CircleRangeTest, input_NEG)
+{
+ luci::CircleRange range_node;
+ luci::CircleRange node;
+
+ range_node.start(&node);
+ range_node.limit(&node);
+ range_node.delta(&node);
+ ASSERT_NE(nullptr, range_node.start());
+ ASSERT_NE(nullptr, range_node.limit());
+ ASSERT_NE(nullptr, range_node.delta());
+
+ range_node.start(nullptr);
+ range_node.limit(nullptr);
+ range_node.delta(nullptr);
+ ASSERT_EQ(nullptr, range_node.start());
+ ASSERT_EQ(nullptr, range_node.limit());
+ ASSERT_EQ(nullptr, range_node.delta());
+}
+
+TEST(CircleRangeTest, arity_NEG)
+{
+ luci::CircleRange range_node;
+
+ ASSERT_NO_THROW(range_node.arg(2));
+ ASSERT_THROW(range_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleRangeTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleRange range_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(range_node.accept(&tv), std::exception);
+}
+
+TEST(CircleRangeTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleRange range_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(range_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleRank.test.cpp b/compiler/luci/lang/src/Nodes/CircleRank.test.cpp
new file mode 100644
index 000000000..e64eae235
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleRank.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 "luci/IR/Nodes/CircleRank.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleRankTest, constructor_P)
+{
+ luci::CircleRank rank_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), rank_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RANK, rank_node.opcode());
+
+ ASSERT_EQ(nullptr, rank_node.input());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleReduceAny.test.cpp b/compiler/luci/lang/src/Nodes/CircleReduceAny.test.cpp
new file mode 100644
index 000000000..cd5c6b746
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleReduceAny.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleReduceAny.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleReduceAnyTest, constructor)
+{
+ luci::CircleReduceAny reduce_any_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), reduce_any_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::REDUCE_ANY, reduce_any_node.opcode());
+
+ ASSERT_EQ(nullptr, reduce_any_node.input());
+ ASSERT_EQ(nullptr, reduce_any_node.reduction_indices());
+
+ ASSERT_FALSE(reduce_any_node.keep_dims());
+}
+
+TEST(CircleReduceAnyTest, input_NEG)
+{
+ luci::CircleReduceAny reduce_any_node;
+ luci::CircleReduceAny node;
+
+ reduce_any_node.input(&node);
+ reduce_any_node.reduction_indices(&node);
+ ASSERT_NE(nullptr, reduce_any_node.input());
+ ASSERT_NE(nullptr, reduce_any_node.reduction_indices());
+
+ reduce_any_node.input(nullptr);
+ reduce_any_node.reduction_indices(nullptr);
+ ASSERT_EQ(nullptr, reduce_any_node.input());
+ ASSERT_EQ(nullptr, reduce_any_node.reduction_indices());
+
+ reduce_any_node.keep_dims(true);
+ ASSERT_TRUE(reduce_any_node.keep_dims());
+}
+
+TEST(CircleReduceAnyTest, arity_NEG)
+{
+ luci::CircleReduceAny reduce_any_node;
+
+ ASSERT_NO_THROW(reduce_any_node.arg(1));
+ ASSERT_THROW(reduce_any_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleReduceAnyTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleReduceAny reduce_any_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reduce_any_node.accept(&tv), std::exception);
+}
+
+TEST(CircleReduceAnyTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleReduceAny reduce_any_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reduce_any_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleReduceMax.test.cpp b/compiler/luci/lang/src/Nodes/CircleReduceMax.test.cpp
new file mode 100644
index 000000000..bdd1818e0
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleReduceMax.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleReduceMax.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleReduceMaxTest, constructor_P)
+{
+ luci::CircleReduceMax reduce_max_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), reduce_max_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::REDUCE_MAX, reduce_max_node.opcode());
+
+ ASSERT_EQ(nullptr, reduce_max_node.input());
+ ASSERT_EQ(nullptr, reduce_max_node.reduction_indices());
+
+ ASSERT_FALSE(reduce_max_node.keep_dims());
+}
+
+TEST(CircleReduceMaxTest, input_NEG)
+{
+ luci::CircleReduceMax reduce_max_node;
+ luci::CircleReduceMax node;
+
+ reduce_max_node.input(&node);
+ reduce_max_node.reduction_indices(&node);
+ ASSERT_NE(nullptr, reduce_max_node.input());
+ ASSERT_NE(nullptr, reduce_max_node.reduction_indices());
+
+ reduce_max_node.input(nullptr);
+ reduce_max_node.reduction_indices(nullptr);
+ ASSERT_EQ(nullptr, reduce_max_node.input());
+ ASSERT_EQ(nullptr, reduce_max_node.reduction_indices());
+
+ reduce_max_node.keep_dims(true);
+ ASSERT_TRUE(reduce_max_node.keep_dims());
+}
+
+TEST(CircleReduceMaxTest, arity_NEG)
+{
+ luci::CircleReduceMax reduce_max_node;
+
+ ASSERT_NO_THROW(reduce_max_node.arg(1));
+ ASSERT_THROW(reduce_max_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleReduceMaxTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleReduceMax reduce_max_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reduce_max_node.accept(&tv), std::exception);
+}
+
+TEST(CircleReduceMaxTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleReduceMax reduce_max_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reduce_max_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleReduceMin.test.cpp b/compiler/luci/lang/src/Nodes/CircleReduceMin.test.cpp
new file mode 100644
index 000000000..ba99ae648
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleReduceMin.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleReduceMin.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleReduceMinTest, constructor_P)
+{
+ luci::CircleReduceMin reduce_min_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), reduce_min_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::REDUCE_MIN, reduce_min_node.opcode());
+
+ ASSERT_EQ(nullptr, reduce_min_node.input());
+ ASSERT_EQ(nullptr, reduce_min_node.reduction_indices());
+
+ ASSERT_FALSE(reduce_min_node.keep_dims());
+}
+
+TEST(CircleReduceMinTest, input_NEG)
+{
+ luci::CircleReduceMin reduce_min_node;
+ luci::CircleReduceMin node;
+
+ reduce_min_node.input(&node);
+ reduce_min_node.reduction_indices(&node);
+ ASSERT_NE(nullptr, reduce_min_node.input());
+ ASSERT_NE(nullptr, reduce_min_node.reduction_indices());
+
+ reduce_min_node.input(nullptr);
+ reduce_min_node.reduction_indices(nullptr);
+ ASSERT_EQ(nullptr, reduce_min_node.input());
+ ASSERT_EQ(nullptr, reduce_min_node.reduction_indices());
+
+ reduce_min_node.keep_dims(true);
+ ASSERT_TRUE(reduce_min_node.keep_dims());
+}
+
+TEST(CircleReduceMinTest, arity_NEG)
+{
+ luci::CircleReduceMin reduce_min_node;
+
+ ASSERT_NO_THROW(reduce_min_node.arg(1));
+ ASSERT_THROW(reduce_min_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleReduceMinTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleReduceMin reduce_min_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reduce_min_node.accept(&tv), std::exception);
+}
+
+TEST(CircleReduceMinTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleReduceMin reduce_min_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reduce_min_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleReduceProd.test.cpp b/compiler/luci/lang/src/Nodes/CircleReduceProd.test.cpp
new file mode 100644
index 000000000..f60b2905b
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleReduceProd.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleReduceProd.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleReduceProdTest, constructor)
+{
+ luci::CircleReduceProd reduce_prod_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), reduce_prod_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::REDUCE_PROD, reduce_prod_node.opcode());
+
+ ASSERT_EQ(nullptr, reduce_prod_node.input());
+ ASSERT_EQ(nullptr, reduce_prod_node.reduction_indices());
+
+ ASSERT_FALSE(reduce_prod_node.keep_dims());
+}
+
+TEST(CircleReduceProdTest, input_NEG)
+{
+ luci::CircleReduceProd reduce_prod_node;
+ luci::CircleReduceProd node;
+
+ reduce_prod_node.input(&node);
+ reduce_prod_node.reduction_indices(&node);
+ ASSERT_NE(nullptr, reduce_prod_node.input());
+ ASSERT_NE(nullptr, reduce_prod_node.reduction_indices());
+
+ reduce_prod_node.input(nullptr);
+ reduce_prod_node.reduction_indices(nullptr);
+ ASSERT_EQ(nullptr, reduce_prod_node.input());
+ ASSERT_EQ(nullptr, reduce_prod_node.reduction_indices());
+
+ reduce_prod_node.keep_dims(true);
+ ASSERT_TRUE(reduce_prod_node.keep_dims());
+}
+
+TEST(CircleReduceProdTest, arity_NEG)
+{
+ luci::CircleReduceProd reduce_prod_node;
+
+ ASSERT_NO_THROW(reduce_prod_node.arg(1));
+ ASSERT_THROW(reduce_prod_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleReduceProdTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleReduceProd reduce_prod_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reduce_prod_node.accept(&tv), std::exception);
+}
+
+TEST(CircleReduceProdTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleReduceProd reduce_prod_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reduce_prod_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleRelu.test.cpp b/compiler/luci/lang/src/Nodes/CircleRelu.test.cpp
index 19ea88aa6..35796509c 100644
--- a/compiler/luci/lang/src/Nodes/CircleRelu.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleRelu.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleRelu.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,8 +25,52 @@ TEST(CircleReluTest, constructor_P)
{
luci::CircleRelu relu_node;
- ASSERT_EQ(relu_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(relu_node.opcode(), luci::CircleOpcode::RELU);
+ ASSERT_EQ(luci::CircleDialect::get(), relu_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RELU, relu_node.opcode());
- ASSERT_EQ(relu_node.features(), nullptr);
+ ASSERT_EQ(nullptr, relu_node.features());
+}
+
+TEST(CircleReluTest, input_NEG)
+{
+ luci::CircleRelu relu_node;
+ luci::CircleRelu node;
+
+ relu_node.features(&node);
+ ASSERT_NE(nullptr, relu_node.features());
+
+ relu_node.features(nullptr);
+ ASSERT_EQ(nullptr, relu_node.features());
+}
+
+TEST(CircleReluTest, arity_NEG)
+{
+ luci::CircleRelu relu_node;
+
+ ASSERT_NO_THROW(relu_node.arg(0));
+ ASSERT_THROW(relu_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleReluTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleRelu relu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(relu_node.accept(&tv), std::exception);
+}
+
+TEST(CircleReluTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleRelu relu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(relu_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp b/compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp
index 74bf2e86a..647a5d7ba 100644
--- a/compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleRelu6.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,8 +25,52 @@ TEST(CircleRelu6Test, constructor_P)
{
luci::CircleRelu6 relu6_node;
- ASSERT_EQ(relu6_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(relu6_node.opcode(), luci::CircleOpcode::RELU6);
+ ASSERT_EQ(luci::CircleDialect::get(), relu6_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RELU6, relu6_node.opcode());
- ASSERT_EQ(relu6_node.features(), nullptr);
+ ASSERT_EQ(nullptr, relu6_node.features());
+}
+
+TEST(CircleRelu6Test, input_NEG)
+{
+ luci::CircleRelu6 relu6_node;
+ luci::CircleRelu6 node;
+
+ relu6_node.features(&node);
+ ASSERT_NE(nullptr, relu6_node.features());
+
+ relu6_node.features(nullptr);
+ ASSERT_EQ(nullptr, relu6_node.features());
+}
+
+TEST(CircleRelu6Test, arity_NEG)
+{
+ luci::CircleRelu6 relu6_node;
+
+ ASSERT_NO_THROW(relu6_node.arg(0));
+ ASSERT_THROW(relu6_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleRelu6Test, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleRelu6 relu6_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(relu6_node.accept(&tv), std::exception);
+}
+
+TEST(CircleRelu6Test, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleRelu6 relu6_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(relu6_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleReluN1To1.test.cpp b/compiler/luci/lang/src/Nodes/CircleReluN1To1.test.cpp
new file mode 100644
index 000000000..8de84ac42
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleReluN1To1.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleReluN1To1.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleReluN1To1Test, constructor)
+{
+ luci::CircleReluN1To1 relu_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), relu_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RELU_N1_TO_1, relu_node.opcode());
+
+ ASSERT_EQ(nullptr, relu_node.features());
+}
+
+TEST(CircleReluN1To1Test, input_NEG)
+{
+ luci::CircleReluN1To1 relu_node;
+ luci::CircleReluN1To1 node;
+
+ relu_node.features(&node);
+ ASSERT_NE(nullptr, relu_node.features());
+
+ relu_node.features(nullptr);
+ ASSERT_EQ(nullptr, relu_node.features());
+}
+
+TEST(CircleReluN1To1Test, arity_NEG)
+{
+ luci::CircleReluN1To1 relu_node;
+
+ ASSERT_NO_THROW(relu_node.arg(0));
+ ASSERT_THROW(relu_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleReluN1To1Test, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleReluN1To1 relu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(relu_node.accept(&tv), std::exception);
+}
+
+TEST(CircleReluN1To1Test, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleReluN1To1 relu_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(relu_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleReshape.test.cpp b/compiler/luci/lang/src/Nodes/CircleReshape.test.cpp
index 7bc2d32a4..236fde28b 100644
--- a/compiler/luci/lang/src/Nodes/CircleReshape.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleReshape.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleReshape.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,12 +25,12 @@ TEST(CircleReshapeTest, constructor_P)
{
luci::CircleReshape reshape;
- ASSERT_EQ(reshape.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(reshape.opcode(), luci::CircleOpcode::RESHAPE);
+ ASSERT_EQ(luci::CircleDialect::get(), reshape.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RESHAPE, reshape.opcode());
- ASSERT_EQ(reshape.tensor(), nullptr);
- ASSERT_EQ(reshape.shape(), nullptr);
- ASSERT_EQ(reshape.newShape()->rank(), 0);
+ ASSERT_EQ(nullptr, reshape.tensor());
+ ASSERT_EQ(nullptr, reshape.shape());
+ ASSERT_EQ(0, reshape.newShape()->rank());
}
TEST(CircleReshapeTest, alloc_new_shape_P)
@@ -37,12 +38,60 @@ TEST(CircleReshapeTest, alloc_new_shape_P)
luci::CircleReshape reshape;
reshape.newShape()->rank(2);
- ASSERT_EQ(reshape.newShape()->rank(), 2);
+ ASSERT_EQ(2, reshape.newShape()->rank());
reshape.newShape()->dim(0) = 0;
reshape.newShape()->dim(1) = 1;
auto &const_reshape = const_cast<const luci::CircleReshape &>(reshape);
- ASSERT_EQ(const_reshape.newShape()->dim(0), 0);
- ASSERT_EQ(const_reshape.newShape()->dim(1), 1);
+ ASSERT_EQ(0, const_reshape.newShape()->dim(0));
+ ASSERT_EQ(1, const_reshape.newShape()->dim(1));
+}
+
+TEST(CircleReshapeTest, input_NEG)
+{
+ luci::CircleReshape reshape_node;
+ luci::CircleReshape node;
+
+ reshape_node.tensor(&node);
+ reshape_node.shape(&node);
+ ASSERT_NE(nullptr, reshape_node.tensor());
+ ASSERT_NE(nullptr, reshape_node.shape());
+
+ reshape_node.tensor(nullptr);
+ reshape_node.shape(nullptr);
+ ASSERT_EQ(nullptr, reshape_node.tensor());
+ ASSERT_EQ(nullptr, reshape_node.shape());
+}
+
+TEST(CircleReshapeTest, arity_NEG)
+{
+ luci::CircleReshape reshape_node;
+
+ ASSERT_NO_THROW(reshape_node.arg(1));
+ ASSERT_THROW(reshape_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleReshapeTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleReshape reshape_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reshape_node.accept(&tv), std::exception);
+}
+
+TEST(CircleReshapeTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleReshape reshape_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(reshape_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleResizeBilinear.test.cpp b/compiler/luci/lang/src/Nodes/CircleResizeBilinear.test.cpp
new file mode 100644
index 000000000..a1481a640
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleResizeBilinear.test.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleResizeBilinear.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleResizeBilinearTest, constructor)
+{
+ luci::CircleResizeBilinear resize;
+
+ ASSERT_EQ(luci::CircleDialect::get(), resize.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RESIZE_BILINEAR, resize.opcode());
+
+ ASSERT_EQ(nullptr, resize.input());
+ ASSERT_EQ(nullptr, resize.size());
+ ASSERT_FALSE(resize.align_corners());
+ ASSERT_FALSE(resize.half_pixel_centers());
+}
+
+TEST(CircleResizeBilinearTest, input_NEG)
+{
+ luci::CircleResizeBilinear resize_node;
+ luci::CircleResizeBilinear node;
+
+ resize_node.input(&node);
+ resize_node.size(&node);
+ ASSERT_NE(nullptr, resize_node.input());
+ ASSERT_NE(nullptr, resize_node.size());
+
+ resize_node.input(nullptr);
+ resize_node.size(nullptr);
+ ASSERT_EQ(nullptr, resize_node.input());
+ ASSERT_EQ(nullptr, resize_node.size());
+
+ resize_node.align_corners(true);
+ ASSERT_TRUE(resize_node.align_corners());
+ resize_node.half_pixel_centers(true);
+ ASSERT_TRUE(resize_node.half_pixel_centers());
+}
+
+TEST(CircleResizeBilinearTest, arity_NEG)
+{
+ luci::CircleResizeBilinear resize_node;
+
+ ASSERT_NO_THROW(resize_node.arg(1));
+ ASSERT_THROW(resize_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleResizeBilinearTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleResizeBilinear resize_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(resize_node.accept(&tv), std::exception);
+}
+
+TEST(CircleResizeBilinearTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleResizeBilinear resize_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(resize_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleResizeNearestNeighbor.test.cpp b/compiler/luci/lang/src/Nodes/CircleResizeNearestNeighbor.test.cpp
new file mode 100644
index 000000000..00e0ae9ea
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleResizeNearestNeighbor.test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleResizeNearestNeighbor.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleResizeNearestNeightborTest, constructor)
+{
+ luci::CircleResizeNearestNeighbor resize;
+
+ ASSERT_EQ(luci::CircleDialect::get(), resize.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RESIZE_NEAREST_NEIGHBOR, resize.opcode());
+
+ ASSERT_EQ(nullptr, resize.input());
+ ASSERT_EQ(nullptr, resize.size());
+ ASSERT_FALSE(resize.align_corners());
+}
+
+TEST(CircleResizeNearestNeightborTest, input_NEG)
+{
+ luci::CircleResizeNearestNeighbor resize_node;
+ luci::CircleResizeNearestNeighbor node;
+
+ resize_node.input(&node);
+ resize_node.size(&node);
+ ASSERT_NE(nullptr, resize_node.input());
+ ASSERT_NE(nullptr, resize_node.size());
+
+ resize_node.input(nullptr);
+ resize_node.size(nullptr);
+ ASSERT_EQ(nullptr, resize_node.input());
+ ASSERT_EQ(nullptr, resize_node.size());
+
+ resize_node.align_corners(true);
+ ASSERT_TRUE(resize_node.align_corners());
+}
+
+TEST(CircleResizeNearestNeightborTest, arity_NEG)
+{
+ luci::CircleResizeNearestNeighbor resize_node;
+
+ ASSERT_NO_THROW(resize_node.arg(1));
+ ASSERT_THROW(resize_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleResizeNearestNeightborTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleResizeNearestNeighbor resize_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(resize_node.accept(&tv), std::exception);
+}
+
+TEST(CircleResizeNearestNeightborTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleResizeNearestNeighbor resize_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(resize_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleReverseSequence.test.cpp b/compiler/luci/lang/src/Nodes/CircleReverseSequence.test.cpp
new file mode 100644
index 000000000..b1cc6d6d6
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleReverseSequence.test.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleReverseSequence.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleReverseSequenceTest, constructor_P)
+{
+ luci::CircleReverseSequence std_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), std_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::REVERSE_SEQUENCE, std_node.opcode());
+
+ ASSERT_EQ(nullptr, std_node.input());
+ ASSERT_EQ(nullptr, std_node.seq_lengths());
+
+ ASSERT_EQ(0, std_node.seq_axis());
+ ASSERT_EQ(0, std_node.batch_axis());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleReverseV2.test.cpp b/compiler/luci/lang/src/Nodes/CircleReverseV2.test.cpp
new file mode 100644
index 000000000..cc568e81a
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleReverseV2.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleReverseV2.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleReverseV2, constructor_P)
+{
+ luci::CircleReverseV2 std_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), std_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::REVERSE_V2, std_node.opcode());
+
+ ASSERT_EQ(nullptr, std_node.tensor());
+ ASSERT_EQ(nullptr, std_node.axis());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleRound.test.cpp b/compiler/luci/lang/src/Nodes/CircleRound.test.cpp
new file mode 100644
index 000000000..2f4518daf
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleRound.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleRound.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleRoundTest, constructor_P)
+{
+ luci::CircleRound round_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), round_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ROUND, round_node.opcode());
+
+ ASSERT_EQ(nullptr, round_node.x());
+}
+
+TEST(CircleRoundTest, input_NEG)
+{
+ luci::CircleRound round_node;
+ luci::CircleRound node;
+
+ round_node.x(&node);
+ ASSERT_NE(nullptr, round_node.x());
+
+ round_node.x(nullptr);
+ ASSERT_EQ(nullptr, round_node.x());
+}
+
+TEST(CircleRoundTest, arity_NEG)
+{
+ luci::CircleRound round_node;
+
+ ASSERT_NO_THROW(round_node.arg(0));
+ ASSERT_THROW(round_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleRoundTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleRound round_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(round_node.accept(&tv), std::exception);
+}
+
+TEST(CircleRoundTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleRound round_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(round_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp b/compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp
index 51f6bab36..d038979c1 100644
--- a/compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleRsqrt.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,8 +25,52 @@ TEST(CircleRsqrtTest, constructor)
{
luci::CircleRsqrt rsqrt_node;
- ASSERT_EQ(rsqrt_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(rsqrt_node.opcode(), luci::CircleOpcode::RSQRT);
+ ASSERT_EQ(luci::CircleDialect::get(), rsqrt_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::RSQRT, rsqrt_node.opcode());
- ASSERT_EQ(rsqrt_node.x(), nullptr);
+ ASSERT_EQ(nullptr, rsqrt_node.x());
+}
+
+TEST(CircleRsqrtTest, input_NEG)
+{
+ luci::CircleRsqrt rsqrt_node;
+ luci::CircleRsqrt node;
+
+ rsqrt_node.x(&node);
+ ASSERT_NE(nullptr, rsqrt_node.x());
+
+ rsqrt_node.x(nullptr);
+ ASSERT_EQ(nullptr, rsqrt_node.x());
+}
+
+TEST(CircleRsqrtTest, arity_NEG)
+{
+ luci::CircleRsqrt rsqrt_node;
+
+ ASSERT_NO_THROW(rsqrt_node.arg(0));
+ ASSERT_THROW(rsqrt_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleRsqrtTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleRsqrt rsqrt_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(rsqrt_node.accept(&tv), std::exception);
+}
+
+TEST(CircleRsqrtTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleRsqrt rsqrt_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(rsqrt_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleScatterNd.test.cpp b/compiler/luci/lang/src/Nodes/CircleScatterNd.test.cpp
new file mode 100644
index 000000000..165f26b44
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleScatterNd.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleScatterNd.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleScatterNdTest, constructor_P)
+{
+ luci::CircleScatterNd scatter_nd_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), scatter_nd_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SCATTER_ND, scatter_nd_node.opcode());
+
+ ASSERT_EQ(nullptr, scatter_nd_node.indices());
+ ASSERT_EQ(nullptr, scatter_nd_node.updates());
+ ASSERT_EQ(nullptr, scatter_nd_node.shape());
+}
+
+TEST(CircleScatterNdTest, input_NEG)
+{
+ luci::CircleScatterNd scatter_nd_node;
+ luci::CircleScatterNd node;
+
+ scatter_nd_node.indices(&node);
+ scatter_nd_node.updates(&node);
+ scatter_nd_node.shape(&node);
+ ASSERT_NE(nullptr, scatter_nd_node.indices());
+ ASSERT_NE(nullptr, scatter_nd_node.updates());
+ ASSERT_NE(nullptr, scatter_nd_node.shape());
+
+ scatter_nd_node.indices(nullptr);
+ scatter_nd_node.updates(nullptr);
+ scatter_nd_node.shape(nullptr);
+ ASSERT_EQ(nullptr, scatter_nd_node.indices());
+ ASSERT_EQ(nullptr, scatter_nd_node.updates());
+ ASSERT_EQ(nullptr, scatter_nd_node.shape());
+}
+
+TEST(CircleScatterNdTest, arity_NEG)
+{
+ luci::CircleScatterNd scatter_nd_node;
+
+ ASSERT_NO_THROW(scatter_nd_node.arg(2));
+ ASSERT_THROW(scatter_nd_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleScatterNdTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleScatterNd scatter_nd_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(scatter_nd_node.accept(&tv), std::exception);
+}
+
+TEST(CircleScatterNdTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleScatterNd scatter_nd_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(scatter_nd_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSegmentSum.test.cpp b/compiler/luci/lang/src/Nodes/CircleSegmentSum.test.cpp
new file mode 100644
index 000000000..90469b7e2
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSegmentSum.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSegmentSum.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSegmentSumTest, constructor)
+{
+ luci::CircleSegmentSum segment_sum_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), segment_sum_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SEGMENT_SUM, segment_sum_node.opcode());
+
+ ASSERT_EQ(nullptr, segment_sum_node.input());
+ ASSERT_EQ(nullptr, segment_sum_node.segment_ids());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSelect.test.cpp b/compiler/luci/lang/src/Nodes/CircleSelect.test.cpp
new file mode 100644
index 000000000..7eeb538af
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSelect.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSelect.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSelectTest, constructor)
+{
+ luci::CircleSelect select_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), select_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SELECT, select_node.opcode());
+
+ ASSERT_EQ(nullptr, select_node.condition());
+ ASSERT_EQ(nullptr, select_node.t());
+ ASSERT_EQ(nullptr, select_node.e());
+}
+
+TEST(CircleSelectTest, input_NEG)
+{
+ luci::CircleSelect select_node;
+ luci::CircleSelect node;
+
+ select_node.condition(&node);
+ select_node.t(&node);
+ select_node.e(&node);
+ ASSERT_NE(nullptr, select_node.condition());
+ ASSERT_NE(nullptr, select_node.t());
+ ASSERT_NE(nullptr, select_node.e());
+
+ select_node.condition(nullptr);
+ select_node.t(nullptr);
+ select_node.e(nullptr);
+ ASSERT_EQ(nullptr, select_node.condition());
+ ASSERT_EQ(nullptr, select_node.t());
+ ASSERT_EQ(nullptr, select_node.e());
+}
+
+TEST(CircleSelectTest, arity_NEG)
+{
+ luci::CircleSelect select_node;
+
+ ASSERT_NO_THROW(select_node.arg(2));
+ ASSERT_THROW(select_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleSelectTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSelect select_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(select_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSelectTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSelect select_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(select_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSelectV2.test.cpp b/compiler/luci/lang/src/Nodes/CircleSelectV2.test.cpp
new file mode 100644
index 000000000..eea5fb83f
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSelectV2.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSelectV2.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSelectV2Test, constructor)
+{
+ luci::CircleSelectV2 select_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), select_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SELECT_V2, select_node.opcode());
+
+ ASSERT_EQ(nullptr, select_node.condition());
+ ASSERT_EQ(nullptr, select_node.t());
+ ASSERT_EQ(nullptr, select_node.e());
+}
+
+TEST(CircleSelectV2Test, input_NEG)
+{
+ luci::CircleSelectV2 select_v2_node;
+ luci::CircleSelectV2 node;
+
+ select_v2_node.condition(&node);
+ select_v2_node.t(&node);
+ select_v2_node.e(&node);
+ ASSERT_NE(nullptr, select_v2_node.condition());
+ ASSERT_NE(nullptr, select_v2_node.t());
+ ASSERT_NE(nullptr, select_v2_node.e());
+
+ select_v2_node.condition(nullptr);
+ select_v2_node.t(nullptr);
+ select_v2_node.e(nullptr);
+ ASSERT_EQ(nullptr, select_v2_node.condition());
+ ASSERT_EQ(nullptr, select_v2_node.t());
+ ASSERT_EQ(nullptr, select_v2_node.e());
+}
+
+TEST(CircleSelectV2Test, arity_NEG)
+{
+ luci::CircleSelectV2 select_v2_node;
+
+ ASSERT_NO_THROW(select_v2_node.arg(2));
+ ASSERT_THROW(select_v2_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleSelectV2Test, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSelectV2 select_v2_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(select_v2_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSelectV2Test, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSelectV2 select_v2_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(select_v2_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleShape.test.cpp b/compiler/luci/lang/src/Nodes/CircleShape.test.cpp
new file mode 100644
index 000000000..18271d2b2
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleShape.test.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleShape.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleShapeTest, constructor)
+{
+ luci::CircleShape shape_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), shape_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SHAPE, shape_node.opcode());
+
+ ASSERT_EQ(nullptr, shape_node.input());
+ ASSERT_EQ(loco::DataType::S32, shape_node.out_type());
+}
+
+TEST(CircleShapeTest, input_NEG)
+{
+ luci::CircleShape shape_node;
+ luci::CircleShape node;
+
+ shape_node.input(&node);
+ ASSERT_NE(nullptr, shape_node.input());
+
+ shape_node.input(nullptr);
+ ASSERT_EQ(nullptr, shape_node.input());
+
+ shape_node.out_type(loco::DataType::U8);
+ ASSERT_NE(loco::DataType::S32, shape_node.out_type());
+}
+
+TEST(CircleShapeTest, arity_NEG)
+{
+ luci::CircleShape shape_node;
+
+ ASSERT_NO_THROW(shape_node.arg(0));
+ ASSERT_THROW(shape_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleShapeTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleShape shape_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(shape_node.accept(&tv), std::exception);
+}
+
+TEST(CircleShapeTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleShape shape_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(shape_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSin.test.cpp b/compiler/luci/lang/src/Nodes/CircleSin.test.cpp
new file mode 100644
index 000000000..e01932d4f
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSin.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSin.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSinTest, constructor)
+{
+ luci::CircleSin sin_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), sin_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SIN, sin_node.opcode());
+
+ ASSERT_EQ(nullptr, sin_node.x());
+}
+
+TEST(CircleSinTest, input_NEG)
+{
+ luci::CircleSin sin_node;
+ luci::CircleSin node;
+
+ sin_node.x(&node);
+ ASSERT_NE(nullptr, sin_node.x());
+
+ sin_node.x(nullptr);
+ ASSERT_EQ(nullptr, sin_node.x());
+}
+
+TEST(CircleSinTest, arity_NEG)
+{
+ luci::CircleSin sin_node;
+
+ ASSERT_NO_THROW(sin_node.arg(0));
+ ASSERT_THROW(sin_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleSinTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSin sin_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sin_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSinTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSin sin_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sin_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSlice.test.cpp b/compiler/luci/lang/src/Nodes/CircleSlice.test.cpp
new file mode 100644
index 000000000..5563a34b9
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSlice.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSlice.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSliceTest, constructor)
+{
+ luci::CircleSlice s_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), s_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SLICE, s_node.opcode());
+
+ ASSERT_EQ(nullptr, s_node.input());
+ ASSERT_EQ(nullptr, s_node.begin());
+ ASSERT_EQ(nullptr, s_node.size());
+}
+
+TEST(CircleSliceTest, input_NEG)
+{
+ luci::CircleSlice s_node;
+ luci::CircleSlice node;
+
+ s_node.input(&node);
+ s_node.begin(&node);
+ s_node.size(&node);
+ ASSERT_NE(nullptr, s_node.input());
+ ASSERT_NE(nullptr, s_node.begin());
+ ASSERT_NE(nullptr, s_node.size());
+
+ s_node.input(nullptr);
+ s_node.begin(nullptr);
+ s_node.size(nullptr);
+ ASSERT_EQ(nullptr, s_node.input());
+ ASSERT_EQ(nullptr, s_node.begin());
+ ASSERT_EQ(nullptr, s_node.size());
+}
+
+TEST(CircleSliceTest, arity_NEG)
+{
+ luci::CircleSlice s_node;
+
+ ASSERT_NO_THROW(s_node.arg(2));
+ ASSERT_THROW(s_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleSliceTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSlice s_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(s_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSliceTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSlice s_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(s_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp b/compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp
index 7e994490c..b15c009f2 100644
--- a/compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleSoftmax.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,8 +25,52 @@ TEST(CircleSoftmaxTest, constructor_P)
{
luci::CircleSoftmax softmax_node;
- ASSERT_EQ(softmax_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(softmax_node.opcode(), luci::CircleOpcode::SOFTMAX);
+ ASSERT_EQ(luci::CircleDialect::get(), softmax_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SOFTMAX, softmax_node.opcode());
- ASSERT_EQ(softmax_node.logits(), nullptr);
+ ASSERT_EQ(nullptr, softmax_node.logits());
+}
+
+TEST(CircleSoftmaxTest, input_NEG)
+{
+ luci::CircleSoftmax softmax_node;
+ luci::CircleSoftmax node;
+
+ softmax_node.logits(&node);
+ ASSERT_NE(nullptr, softmax_node.logits());
+
+ softmax_node.logits(nullptr);
+ ASSERT_EQ(nullptr, softmax_node.logits());
+}
+
+TEST(CircleSoftmaxTest, arity_NEG)
+{
+ luci::CircleSoftmax softmax_node;
+
+ ASSERT_NO_THROW(softmax_node.arg(0));
+ ASSERT_THROW(softmax_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleSoftmaxTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSoftmax softmax_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(softmax_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSoftmaxTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSoftmax softmax_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(softmax_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleSpaceToBatchND.test.cpp b/compiler/luci/lang/src/Nodes/CircleSpaceToBatchND.test.cpp
new file mode 100644
index 000000000..8b4ac8f2b
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSpaceToBatchND.test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSpaceToBatchND.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSpaceToBatchNDTest, constructor)
+{
+ luci::CircleSpaceToBatchND stb_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), stb_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SPACE_TO_BATCH_ND, stb_node.opcode());
+
+ ASSERT_EQ(nullptr, stb_node.input());
+ ASSERT_EQ(nullptr, stb_node.block_shape());
+ ASSERT_EQ(nullptr, stb_node.paddings());
+}
+
+TEST(CircleSpaceToBatchNDTest, input_NEG)
+{
+ luci::CircleSpaceToBatchND stb_node;
+ luci::CircleSpaceToBatchND node;
+
+ stb_node.input(&node);
+ stb_node.block_shape(&node);
+ stb_node.paddings(&node);
+ ASSERT_NE(nullptr, stb_node.input());
+ ASSERT_NE(nullptr, stb_node.block_shape());
+ ASSERT_NE(nullptr, stb_node.paddings());
+
+ stb_node.input(nullptr);
+ stb_node.block_shape(nullptr);
+ stb_node.paddings(nullptr);
+ ASSERT_EQ(nullptr, stb_node.input());
+ ASSERT_EQ(nullptr, stb_node.block_shape());
+ ASSERT_EQ(nullptr, stb_node.paddings());
+}
+
+TEST(CircleSpaceToBatchNDTest, arity_NEG)
+{
+ luci::CircleSpaceToBatchND stb_node;
+
+ ASSERT_NO_THROW(stb_node.arg(2));
+ ASSERT_THROW(stb_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleSpaceToBatchNDTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSpaceToBatchND stb_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(stb_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSpaceToBatchNDTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSpaceToBatchND stb_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(stb_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSpaceToDepth.test.cpp b/compiler/luci/lang/src/Nodes/CircleSpaceToDepth.test.cpp
new file mode 100644
index 000000000..d49a2ce85
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSpaceToDepth.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSpaceToDepth.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSpaceToDepthTest, constructor)
+{
+ luci::CircleSpaceToDepth std_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), std_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SPACE_TO_DEPTH, std_node.opcode());
+
+ ASSERT_EQ(nullptr, std_node.input());
+}
+
+TEST(CircleSpaceToDepthTest, input_NEG)
+{
+ luci::CircleSpaceToDepth std_node;
+ luci::CircleSpaceToDepth node;
+
+ std_node.input(&node);
+ ASSERT_NE(nullptr, std_node.input());
+
+ std_node.input(nullptr);
+ ASSERT_EQ(nullptr, std_node.input());
+}
+
+TEST(CircleSpaceToDepthTest, arity_NEG)
+{
+ luci::CircleSpaceToDepth std_node;
+
+ ASSERT_NO_THROW(std_node.arg(0));
+ ASSERT_THROW(std_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleSpaceToDepthTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSpaceToDepth std_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(std_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSpaceToDepthTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSpaceToDepth std_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(std_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSparseToDense.test.cpp b/compiler/luci/lang/src/Nodes/CircleSparseToDense.test.cpp
new file mode 100644
index 000000000..de3cf6e9a
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSparseToDense.test.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSparseToDense.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSparseToDenseTest, constructor)
+{
+ luci::CircleSparseToDense stb_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), stb_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SPARSE_TO_DENSE, stb_node.opcode());
+
+ ASSERT_EQ(nullptr, stb_node.indices());
+ ASSERT_EQ(nullptr, stb_node.output_shape());
+ ASSERT_EQ(nullptr, stb_node.values());
+ ASSERT_EQ(nullptr, stb_node.default_value());
+
+ ASSERT_EQ(true, stb_node.validate_indices());
+}
+
+TEST(CircleSparseToDenseTest, input_NEG)
+{
+ luci::CircleSparseToDense stb_node;
+ luci::CircleSparseToDense node;
+
+ stb_node.indices(&node);
+ stb_node.output_shape(&node);
+ stb_node.values(&node);
+ stb_node.default_value(&node);
+ ASSERT_NE(nullptr, stb_node.indices());
+ ASSERT_NE(nullptr, stb_node.output_shape());
+ ASSERT_NE(nullptr, stb_node.values());
+ ASSERT_NE(nullptr, stb_node.default_value());
+
+ stb_node.indices(nullptr);
+ stb_node.output_shape(nullptr);
+ stb_node.values(nullptr);
+ stb_node.default_value(nullptr);
+ ASSERT_EQ(nullptr, stb_node.indices());
+ ASSERT_EQ(nullptr, stb_node.output_shape());
+ ASSERT_EQ(nullptr, stb_node.values());
+ ASSERT_EQ(nullptr, stb_node.default_value());
+}
+
+TEST(CircleSparseToDenseTest, arity_NEG)
+{
+ luci::CircleSparseToDense stb_node;
+
+ ASSERT_NO_THROW(stb_node.arg(3));
+ ASSERT_THROW(stb_node.arg(4), std::out_of_range);
+}
+
+TEST(CircleSparseToDenseTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSparseToDense stb_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(stb_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSparseToDenseTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSparseToDense stb_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(stb_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSplit.test.cpp b/compiler/luci/lang/src/Nodes/CircleSplit.test.cpp
new file mode 100644
index 000000000..acf8c4410
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSplit.test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSplit.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSplitTest, constructor)
+{
+ luci::CircleSplit split_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), split_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SPLIT, split_node.opcode());
+
+ ASSERT_EQ(nullptr, split_node.input());
+ ASSERT_EQ(nullptr, split_node.split_dim());
+ ASSERT_EQ(0, split_node.num_split());
+}
+
+TEST(CircleSplitTest, input_NEG)
+{
+ luci::CircleSplit split_node;
+ luci::CircleSplit node;
+
+ split_node.input(&node);
+ split_node.split_dim(&node);
+ ASSERT_NE(nullptr, split_node.input());
+ ASSERT_NE(nullptr, split_node.split_dim());
+
+ split_node.input(nullptr);
+ split_node.split_dim(nullptr);
+ ASSERT_EQ(nullptr, split_node.input());
+ ASSERT_EQ(nullptr, split_node.split_dim());
+
+ split_node.num_split(100);
+ ASSERT_NE(0, split_node.num_split());
+}
+
+TEST(CircleSplitTest, arity_NEG)
+{
+ luci::CircleSplit split_node;
+
+ ASSERT_NO_THROW(split_node.arg(1));
+ ASSERT_THROW(split_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleSplitTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSplit split_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(split_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSplitTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSplit split_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(split_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSplitOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleSplitOut.test.cpp
new file mode 100644
index 000000000..e93715825
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSplitOut.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSplitOut.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSplitOutTest, constructor)
+{
+ luci::CircleSplitOut vout_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), vout_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CIRCLESPLITOUT, vout_node.opcode());
+
+ ASSERT_EQ(nullptr, vout_node.input());
+ ASSERT_EQ(-1, vout_node.index());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSplitV.test.cpp b/compiler/luci/lang/src/Nodes/CircleSplitV.test.cpp
new file mode 100644
index 000000000..1f01608a3
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSplitV.test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSplitV.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSplitVTest, constructor)
+{
+ luci::CircleSplitV splitv_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), splitv_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SPLIT_V, splitv_node.opcode());
+
+ ASSERT_EQ(nullptr, splitv_node.input());
+ ASSERT_EQ(nullptr, splitv_node.size_splits());
+ ASSERT_EQ(nullptr, splitv_node.split_dim());
+ ASSERT_EQ(0, splitv_node.num_split());
+}
+
+TEST(CircleSplitVTest, input_NEG)
+{
+ luci::CircleSplitV splitv_node;
+ luci::CircleSplitV node;
+
+ splitv_node.input(&node);
+ splitv_node.size_splits(&node);
+ splitv_node.split_dim(&node);
+ ASSERT_NE(nullptr, splitv_node.input());
+ ASSERT_NE(nullptr, splitv_node.size_splits());
+ ASSERT_NE(nullptr, splitv_node.split_dim());
+
+ splitv_node.input(nullptr);
+ splitv_node.size_splits(nullptr);
+ splitv_node.split_dim(nullptr);
+ ASSERT_EQ(nullptr, splitv_node.input());
+ ASSERT_EQ(nullptr, splitv_node.size_splits());
+ ASSERT_EQ(nullptr, splitv_node.split_dim());
+
+ splitv_node.num_split(100);
+ ASSERT_NE(0, splitv_node.num_split());
+}
+
+TEST(CircleSplitVTest, arity_NEG)
+{
+ luci::CircleSplitV splitv_node;
+
+ ASSERT_NO_THROW(splitv_node.arg(2));
+ ASSERT_THROW(splitv_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleSplitVTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSplitV splitv_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(splitv_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSplitVTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSplitV splitv_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(splitv_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSplitVOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleSplitVOut.test.cpp
new file mode 100644
index 000000000..2a4fe3267
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSplitVOut.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSplitVOut.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSplitVOutTest, constructor)
+{
+ luci::CircleSplitVOut vout_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), vout_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CIRCLESPLITVOUT, vout_node.opcode());
+
+ ASSERT_EQ(nullptr, vout_node.input());
+ ASSERT_EQ(-1, vout_node.index());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp b/compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp
index 6cfb3bc94..f4222fd67 100644
--- a/compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleSqrt.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,8 +25,52 @@ TEST(CircleSqrtTest, constructor_P)
{
luci::CircleSqrt sqrt_node;
- ASSERT_EQ(sqrt_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(sqrt_node.opcode(), luci::CircleOpcode::SQRT);
+ ASSERT_EQ(luci::CircleDialect::get(), sqrt_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SQRT, sqrt_node.opcode());
- ASSERT_EQ(sqrt_node.x(), nullptr);
+ ASSERT_EQ(nullptr, sqrt_node.x());
+}
+
+TEST(CircleSqrtTest, input_NEG)
+{
+ luci::CircleSqrt sqrt_node;
+ luci::CircleSqrt node;
+
+ sqrt_node.x(&node);
+ ASSERT_NE(nullptr, sqrt_node.x());
+
+ sqrt_node.x(nullptr);
+ ASSERT_EQ(nullptr, sqrt_node.x());
+}
+
+TEST(CircleSqrtTest, arity_NEG)
+{
+ luci::CircleSqrt sqrt_node;
+
+ ASSERT_NO_THROW(sqrt_node.arg(0));
+ ASSERT_THROW(sqrt_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleSqrtTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSqrt sqrt_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sqrt_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSqrtTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSqrt sqrt_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sqrt_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleSquare.test.cpp b/compiler/luci/lang/src/Nodes/CircleSquare.test.cpp
new file mode 100644
index 000000000..3b0a86eed
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSquare.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSquare.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSquareTest, constructor_P)
+{
+ luci::CircleSquare square_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), square_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SQUARE, square_node.opcode());
+
+ ASSERT_EQ(nullptr, square_node.x());
+}
+
+TEST(CircleSquareTest, input_NEG)
+{
+ luci::CircleSquare square_node;
+ luci::CircleSquare node;
+
+ square_node.x(&node);
+ ASSERT_NE(nullptr, square_node.x());
+
+ square_node.x(nullptr);
+ ASSERT_EQ(nullptr, square_node.x());
+}
+
+TEST(CircleSquareTest, arity_NEG)
+{
+ luci::CircleSquare square_node;
+
+ ASSERT_NO_THROW(square_node.arg(0));
+ ASSERT_THROW(square_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleSquareTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSquare square_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(square_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSquareTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSquare square_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(square_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp b/compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp
index 71df189b9..ea632218b 100644
--- a/compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleSquaredDifference.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CircleSquaredDifferenceTest, constructor_P)
{
luci::CircleSquaredDifference sd_node;
- ASSERT_EQ(sd_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(sd_node.opcode(), luci::CircleOpcode::SQUARED_DIFFERENCE);
+ ASSERT_EQ(luci::CircleDialect::get(), sd_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SQUARED_DIFFERENCE, sd_node.opcode());
- ASSERT_EQ(sd_node.x(), nullptr);
- ASSERT_EQ(sd_node.y(), nullptr);
+ ASSERT_EQ(nullptr, sd_node.x());
+ ASSERT_EQ(nullptr, sd_node.y());
+}
+
+TEST(CircleSquaredDifferenceTest, input_NEG)
+{
+ luci::CircleSquaredDifference sd_node;
+ luci::CircleSquaredDifference node;
+
+ sd_node.x(&node);
+ sd_node.y(&node);
+ ASSERT_NE(nullptr, sd_node.x());
+ ASSERT_NE(nullptr, sd_node.y());
+
+ sd_node.x(nullptr);
+ sd_node.y(nullptr);
+ ASSERT_EQ(nullptr, sd_node.x());
+ ASSERT_EQ(nullptr, sd_node.y());
+}
+
+TEST(CircleSquaredDifferenceTest, arity_NEG)
+{
+ luci::CircleSquaredDifference sd_node;
+
+ ASSERT_NO_THROW(sd_node.arg(1));
+ ASSERT_THROW(sd_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleSquaredDifferenceTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSquaredDifference sd_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sd_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSquaredDifferenceTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSquaredDifference sd_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sd_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleSqueeze.test.cpp b/compiler/luci/lang/src/Nodes/CircleSqueeze.test.cpp
new file mode 100644
index 000000000..6dc3d03cd
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSqueeze.test.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 "luci/IR/Nodes/CircleSqueeze.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSqueezeTest, constructor_P)
+{
+ luci::CircleSqueeze squeeze;
+
+ ASSERT_EQ(luci::CircleDialect::get(), squeeze.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SQUEEZE, squeeze.opcode());
+
+ ASSERT_EQ(nullptr, squeeze.input());
+ ASSERT_EQ(0, squeeze.squeeze_dims().size());
+}
+
+TEST(CircleSqueezeTest, squeeze_dims)
+{
+ luci::CircleSqueeze squeeze;
+
+ squeeze.squeeze_dims({1, 2});
+
+ ASSERT_EQ(1, squeeze.squeeze_dims().at(0));
+ ASSERT_EQ(2, squeeze.squeeze_dims().at(1));
+}
+
+TEST(CircleSqueezeTest, input_NEG)
+{
+ luci::CircleSqueeze squeeze_node;
+ luci::CircleSqueeze node;
+
+ squeeze_node.input(&node);
+ ASSERT_NE(nullptr, squeeze_node.input());
+
+ squeeze_node.input(nullptr);
+ ASSERT_EQ(nullptr, squeeze_node.input());
+}
+
+TEST(CircleSqueezeTest, arity_NEG)
+{
+ luci::CircleSqueeze squeeze_node;
+
+ ASSERT_NO_THROW(squeeze_node.arg(0));
+ ASSERT_THROW(squeeze_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleSqueezeTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSqueeze squeeze_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(squeeze_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSqueezeTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSqueeze squeeze_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(squeeze_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleStridedSlice.test.cpp b/compiler/luci/lang/src/Nodes/CircleStridedSlice.test.cpp
new file mode 100644
index 000000000..1982e7b38
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleStridedSlice.test.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleStridedSlice.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleStridedSliceTest, constructor)
+{
+ luci::CircleStridedSlice ss_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), ss_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::STRIDED_SLICE, ss_node.opcode());
+
+ ASSERT_EQ(nullptr, ss_node.input());
+ ASSERT_EQ(nullptr, ss_node.begin());
+ ASSERT_EQ(nullptr, ss_node.end());
+ ASSERT_EQ(nullptr, ss_node.strides());
+
+ ASSERT_EQ(0, ss_node.begin_mask());
+ ASSERT_EQ(0, ss_node.end_mask());
+ ASSERT_EQ(0, ss_node.ellipsis_mask());
+ ASSERT_EQ(0, ss_node.new_axis_mask());
+ ASSERT_EQ(0, ss_node.shrink_axis_mask());
+}
+
+TEST(CircleStridedSliceTest, input_NEG)
+{
+ luci::CircleStridedSlice ss_node;
+ luci::CircleStridedSlice node;
+
+ ss_node.input(&node);
+ ss_node.begin(&node);
+ ss_node.end(&node);
+ ss_node.strides(&node);
+ ASSERT_NE(nullptr, ss_node.input());
+ ASSERT_NE(nullptr, ss_node.begin());
+ ASSERT_NE(nullptr, ss_node.end());
+ ASSERT_NE(nullptr, ss_node.strides());
+
+ ss_node.input(nullptr);
+ ss_node.begin(nullptr);
+ ss_node.end(nullptr);
+ ss_node.strides(nullptr);
+ ASSERT_EQ(nullptr, ss_node.input());
+ ASSERT_EQ(nullptr, ss_node.begin());
+ ASSERT_EQ(nullptr, ss_node.end());
+ ASSERT_EQ(nullptr, ss_node.strides());
+
+ ss_node.begin_mask(1);
+ ss_node.end_mask(1);
+ ss_node.ellipsis_mask(1);
+ ss_node.new_axis_mask(1);
+ ss_node.shrink_axis_mask(1);
+ ASSERT_NE(0, ss_node.begin_mask());
+ ASSERT_NE(0, ss_node.end_mask());
+ ASSERT_NE(0, ss_node.ellipsis_mask());
+ ASSERT_NE(0, ss_node.new_axis_mask());
+ ASSERT_NE(0, ss_node.shrink_axis_mask());
+}
+
+TEST(CircleStridedSliceTest, arity_NEG)
+{
+ luci::CircleStridedSlice ss_node;
+
+ ASSERT_NO_THROW(ss_node.arg(3));
+ ASSERT_THROW(ss_node.arg(4), std::out_of_range);
+}
+
+TEST(CircleStridedSliceTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleStridedSlice ss_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(ss_node.accept(&tv), std::exception);
+}
+
+TEST(CircleStridedSliceTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleStridedSlice ss_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(ss_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleSub.test.cpp b/compiler/luci/lang/src/Nodes/CircleSub.test.cpp
index ebb29446a..92c674bd0 100644
--- a/compiler/luci/lang/src/Nodes/CircleSub.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleSub.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleSub.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CircleSubTest, constructor_P)
{
luci::CircleSub sub_node;
- ASSERT_EQ(sub_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(sub_node.opcode(), luci::CircleOpcode::SUB);
+ ASSERT_EQ(luci::CircleDialect::get(), sub_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SUB, sub_node.opcode());
- ASSERT_EQ(sub_node.x(), nullptr);
- ASSERT_EQ(sub_node.y(), nullptr);
+ ASSERT_EQ(nullptr, sub_node.x());
+ ASSERT_EQ(nullptr, sub_node.y());
+}
+
+TEST(CircleSubTest, input_NEG)
+{
+ luci::CircleSub sub_node;
+ luci::CircleSub node;
+
+ sub_node.x(&node);
+ sub_node.y(&node);
+ ASSERT_NE(nullptr, sub_node.x());
+ ASSERT_NE(nullptr, sub_node.y());
+
+ sub_node.x(nullptr);
+ sub_node.y(nullptr);
+ ASSERT_EQ(nullptr, sub_node.x());
+ ASSERT_EQ(nullptr, sub_node.y());
+}
+
+TEST(CircleSubTest, arity_NEG)
+{
+ luci::CircleSub sub_node;
+
+ ASSERT_NO_THROW(sub_node.arg(1));
+ ASSERT_THROW(sub_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleSubTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSub sub_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sub_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSubTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSub sub_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sub_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleSum.test.cpp b/compiler/luci/lang/src/Nodes/CircleSum.test.cpp
new file mode 100644
index 000000000..84b51d671
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleSum.test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleSum.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleSumTest, constructor_P)
+{
+ luci::CircleSum sum_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), sum_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::SUM, sum_node.opcode());
+
+ ASSERT_EQ(nullptr, sum_node.input());
+ ASSERT_EQ(nullptr, sum_node.reduction_indices());
+ ASSERT_EQ(false, sum_node.keep_dims());
+}
+
+TEST(CircleSumTest, input_NEG)
+{
+ luci::CircleSum sum_node;
+ luci::CircleSum node;
+
+ sum_node.input(&node);
+ sum_node.reduction_indices(&node);
+ ASSERT_NE(nullptr, sum_node.input());
+ ASSERT_NE(nullptr, sum_node.reduction_indices());
+
+ sum_node.input(nullptr);
+ sum_node.reduction_indices(nullptr);
+ ASSERT_EQ(nullptr, sum_node.input());
+ ASSERT_EQ(nullptr, sum_node.reduction_indices());
+
+ sum_node.keep_dims(true);
+ ASSERT_TRUE(sum_node.keep_dims());
+}
+
+TEST(CircleSumTest, arity_NEG)
+{
+ luci::CircleSum sum_node;
+
+ ASSERT_NO_THROW(sum_node.arg(1));
+ ASSERT_THROW(sum_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleSumTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleSum sum_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sum_node.accept(&tv), std::exception);
+}
+
+TEST(CircleSumTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleSum sum_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(sum_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleTanh.test.cpp b/compiler/luci/lang/src/Nodes/CircleTanh.test.cpp
new file mode 100644
index 000000000..257ecb24d
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleTanh.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleTanh.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleTanhTest, constructor)
+{
+ luci::CircleTanh tanh_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), tanh_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::TANH, tanh_node.opcode());
+
+ ASSERT_EQ(nullptr, tanh_node.x());
+}
+
+TEST(CircleTanhTest, input_NEG)
+{
+ luci::CircleTanh neg_node;
+ luci::CircleTanh node;
+
+ neg_node.x(&node);
+ ASSERT_NE(nullptr, neg_node.x());
+
+ neg_node.x(nullptr);
+ ASSERT_EQ(nullptr, neg_node.x());
+}
+
+TEST(CircleTanhTest, arity_NEG)
+{
+ luci::CircleTanh neg_node;
+
+ ASSERT_NO_THROW(neg_node.arg(0));
+ ASSERT_THROW(neg_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleTanhTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleTanh neg_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(neg_node.accept(&tv), std::exception);
+}
+
+TEST(CircleTanhTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleTanh neg_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(neg_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleTile.test.cpp b/compiler/luci/lang/src/Nodes/CircleTile.test.cpp
new file mode 100644
index 000000000..1695165cc
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleTile.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleTile.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleTileTest, constructor)
+{
+ luci::CircleTile tile_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), tile_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::TILE, tile_node.opcode());
+
+ ASSERT_EQ(nullptr, tile_node.input());
+ ASSERT_EQ(nullptr, tile_node.multiples());
+}
+
+TEST(CircleTileTest, input_NEG)
+{
+ luci::CircleTile tile_node;
+ luci::CircleTile node;
+
+ tile_node.input(&node);
+ tile_node.multiples(&node);
+ ASSERT_NE(nullptr, tile_node.input());
+ ASSERT_NE(nullptr, tile_node.multiples());
+
+ tile_node.input(nullptr);
+ tile_node.multiples(nullptr);
+ ASSERT_EQ(nullptr, tile_node.input());
+ ASSERT_EQ(nullptr, tile_node.multiples());
+}
+
+TEST(CircleTileTest, arity_NEG)
+{
+ luci::CircleTile tile_node;
+
+ ASSERT_NO_THROW(tile_node.arg(1));
+ ASSERT_THROW(tile_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleTileTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleTile tile_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(tile_node.accept(&tv), std::exception);
+}
+
+TEST(CircleTileTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleTile tile_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(tile_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleTopKV2.test.cpp b/compiler/luci/lang/src/Nodes/CircleTopKV2.test.cpp
new file mode 100644
index 000000000..31478d3af
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleTopKV2.test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleTopKV2.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleTopKV2Test, constructor)
+{
+ luci::CircleTopKV2 topkv2_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), topkv2_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::TOPK_V2, topkv2_node.opcode());
+
+ ASSERT_EQ(nullptr, topkv2_node.input());
+ ASSERT_EQ(nullptr, topkv2_node.k());
+}
+
+TEST(CircleTopKV2Test, input_NEG)
+{
+ luci::CircleTopKV2 topkv2_node;
+ luci::CircleTopKV2 node;
+
+ topkv2_node.input(&node);
+ topkv2_node.k(&node);
+ ASSERT_NE(nullptr, topkv2_node.input());
+ ASSERT_NE(nullptr, topkv2_node.k());
+
+ topkv2_node.input(nullptr);
+ topkv2_node.k(nullptr);
+ ASSERT_EQ(nullptr, topkv2_node.input());
+ ASSERT_EQ(nullptr, topkv2_node.k());
+}
+
+TEST(CircleTopKV2Test, arity_NEG)
+{
+ luci::CircleTopKV2 topkv2_node;
+
+ ASSERT_NO_THROW(topkv2_node.arg(1));
+ ASSERT_THROW(topkv2_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleTopKV2Test, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleTopKV2 topkv2_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(topkv2_node.accept(&tv), std::exception);
+}
+
+TEST(CircleTopKV2Test, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleTopKV2 topkv2_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(topkv2_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleTopKV2Out.test.cpp b/compiler/luci/lang/src/Nodes/CircleTopKV2Out.test.cpp
new file mode 100644
index 000000000..d0835a27d
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleTopKV2Out.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleTopKV2Out.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleTopKV2OutTest, constructor)
+{
+ luci::CircleTopKV2Out topout_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), topout_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CIRCLETOPKV2OUT, topout_node.opcode());
+
+ ASSERT_EQ(nullptr, topout_node.input());
+ ASSERT_EQ(-1, topout_node.index());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp b/compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp
index 7233869e6..f4db3f37b 100644
--- a/compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleTranspose.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,9 +25,57 @@ TEST(CircleTransposeTest, constructor_P)
{
luci::CircleTranspose tr_node;
- ASSERT_EQ(tr_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(tr_node.opcode(), luci::CircleOpcode::TRANSPOSE);
+ ASSERT_EQ(luci::CircleDialect::get(), tr_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::TRANSPOSE, tr_node.opcode());
- ASSERT_EQ(tr_node.a(), nullptr);
- ASSERT_EQ(tr_node.perm(), nullptr);
+ ASSERT_EQ(nullptr, tr_node.a());
+ ASSERT_EQ(nullptr, tr_node.perm());
+}
+
+TEST(CircleTransposeTest, input_NEG)
+{
+ luci::CircleTranspose tr_node;
+ luci::CircleTranspose node;
+
+ tr_node.a(&node);
+ tr_node.perm(&node);
+ ASSERT_NE(nullptr, tr_node.a());
+ ASSERT_NE(nullptr, tr_node.perm());
+
+ tr_node.a(nullptr);
+ tr_node.perm(nullptr);
+ ASSERT_EQ(nullptr, tr_node.a());
+ ASSERT_EQ(nullptr, tr_node.perm());
+}
+
+TEST(CircleTransposeTest, arity_NEG)
+{
+ luci::CircleTranspose tr_node;
+
+ ASSERT_NO_THROW(tr_node.arg(1));
+ ASSERT_THROW(tr_node.arg(2), std::out_of_range);
+}
+
+TEST(CircleTransposeTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleTranspose tr_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(tr_node.accept(&tv), std::exception);
+}
+
+TEST(CircleTransposeTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleTranspose tr_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(tr_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp b/compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp
index 9615082d9..429169744 100644
--- a/compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp
+++ b/compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp
@@ -17,6 +17,7 @@
#include "luci/IR/Nodes/CircleTransposeConv.h"
#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
#include <gtest/gtest.h>
@@ -24,10 +25,74 @@ TEST(CircleTransposeConvTest, constructor_P)
{
luci::CircleTransposeConv trc_node;
- ASSERT_EQ(trc_node.dialect(), luci::CircleDialect::get());
- ASSERT_EQ(trc_node.opcode(), luci::CircleOpcode::TRANSPOSE_CONV);
+ ASSERT_EQ(luci::CircleDialect::get(), trc_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::TRANSPOSE_CONV, trc_node.opcode());
- ASSERT_EQ(trc_node.inputSizes(), nullptr);
- ASSERT_EQ(trc_node.filter(), nullptr);
- ASSERT_EQ(trc_node.outBackprop(), nullptr);
+ ASSERT_EQ(nullptr, trc_node.inputSizes());
+ ASSERT_EQ(nullptr, trc_node.filter());
+ ASSERT_EQ(nullptr, trc_node.outBackprop());
+
+ ASSERT_EQ(luci::Padding::UNDEFINED, trc_node.padding());
+ ASSERT_EQ(1, trc_node.stride()->h());
+ ASSERT_EQ(1, trc_node.stride()->w());
+}
+
+TEST(CircleTransposeConvTest, input_NEG)
+{
+ luci::CircleTransposeConv trc_node;
+ luci::CircleTransposeConv node;
+
+ trc_node.inputSizes(&node);
+ trc_node.filter(&node);
+ trc_node.outBackprop(&node);
+ ASSERT_NE(nullptr, trc_node.inputSizes());
+ ASSERT_NE(nullptr, trc_node.filter());
+ ASSERT_NE(nullptr, trc_node.outBackprop());
+
+ trc_node.inputSizes(nullptr);
+ trc_node.filter(nullptr);
+ trc_node.outBackprop(nullptr);
+ ASSERT_EQ(nullptr, trc_node.inputSizes());
+ ASSERT_EQ(nullptr, trc_node.filter());
+ ASSERT_EQ(nullptr, trc_node.outBackprop());
+
+ trc_node.padding(luci::Padding::SAME);
+ ASSERT_NE(luci::Padding::UNDEFINED, trc_node.padding());
+
+ trc_node.stride()->h(2);
+ trc_node.stride()->w(2);
+ ASSERT_EQ(2, trc_node.stride()->h());
+ ASSERT_EQ(2, trc_node.stride()->w());
+}
+
+TEST(CircleTransposeConvTest, arity_NEG)
+{
+ luci::CircleTransposeConv trc_node;
+
+ ASSERT_NO_THROW(trc_node.arg(2));
+ ASSERT_THROW(trc_node.arg(3), std::out_of_range);
+}
+
+TEST(CircleTransposeConvTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleTransposeConv trc_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(trc_node.accept(&tv), std::exception);
+}
+
+TEST(CircleTransposeConvTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleTransposeConv trc_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(trc_node.accept(&tv), std::exception);
}
diff --git a/compiler/luci/lang/src/Nodes/CircleUnpack.test.cpp b/compiler/luci/lang/src/Nodes/CircleUnpack.test.cpp
new file mode 100644
index 000000000..4323028e4
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleUnpack.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 "luci/IR/Nodes/CircleUnpack.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleUnpackTest, constructor)
+{
+ luci::CircleUnpack unpack_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), unpack_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::UNPACK, unpack_node.opcode());
+
+ ASSERT_EQ(nullptr, unpack_node.value());
+ ASSERT_EQ(0, unpack_node.num());
+ ASSERT_EQ(0, unpack_node.axis());
+}
+
+TEST(CircleUnpackTest, input_NEG)
+{
+ luci::CircleUnpack unpack_node;
+ luci::CircleUnpack node;
+
+ unpack_node.value(&node);
+ ASSERT_NE(nullptr, unpack_node.value());
+
+ unpack_node.value(nullptr);
+ ASSERT_EQ(nullptr, unpack_node.value());
+
+ unpack_node.num(1);
+ unpack_node.axis(1);
+ ASSERT_NE(0, unpack_node.num());
+ ASSERT_NE(0, unpack_node.axis());
+}
+
+TEST(CircleUnpackTest, arity_NEG)
+{
+ luci::CircleUnpack unpack_node;
+
+ ASSERT_NO_THROW(unpack_node.arg(0));
+ ASSERT_THROW(unpack_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleUnpackTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleUnpack unpack_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(unpack_node.accept(&tv), std::exception);
+}
+
+TEST(CircleUnpackTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleUnpack unpack_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(unpack_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleUnpackOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleUnpackOut.test.cpp
new file mode 100644
index 000000000..7b8a41bf7
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleUnpackOut.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleUnpackOut.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleUnpackOutTest, constructor)
+{
+ luci::CircleUnpackOut unpackout_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), unpackout_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CIRCLEUNPACKOUT, unpackout_node.opcode());
+
+ ASSERT_EQ(nullptr, unpackout_node.input());
+ ASSERT_EQ(0, unpackout_node.index());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleWhere.test.cpp b/compiler/luci/lang/src/Nodes/CircleWhere.test.cpp
new file mode 100644
index 000000000..287eda460
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleWhere.test.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleWhere.h"
+#include "luci/IR/Nodes/CircleInput.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleWhereTest, constructor_P)
+{
+ luci::CircleWhere where_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), where_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::WHERE, where_node.opcode());
+
+ ASSERT_EQ(1, where_node.arity());
+ ASSERT_EQ(nullptr, where_node.condition());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp b/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp
new file mode 100644
index 000000000..19290c0a2
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleWhile.test.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 "luci/IR/Nodes/CircleWhile.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleWhileTest, constructor)
+{
+ luci::CircleWhile while_node(2, 2);
+
+ ASSERT_EQ(luci::CircleDialect::get(), while_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::WHILE, while_node.opcode());
+
+ ASSERT_EQ(2, while_node.input_count());
+ ASSERT_EQ(2, while_node.output_count());
+
+ ASSERT_EQ(nullptr, while_node.input(0));
+ ASSERT_EQ(nullptr, while_node.input(1));
+
+ ASSERT_EQ(-1, while_node.cond_branch());
+ ASSERT_EQ(-1, while_node.body_branch());
+}
+
+TEST(CircleWhileTestDeath, invalid_arity_NEG)
+{
+ ASSERT_DEBUG_DEATH(luci::CircleWhile very_long_name_while_node(0, 1), "");
+}
+
+TEST(CircleWhileTestDeath, invalid_output_count_NEG)
+{
+ ASSERT_DEBUG_DEATH(luci::CircleWhile while_node(2, 0), "");
+}
+
+TEST(CircleWhileTestDeath, invalid_input_get_index_NEG)
+{
+ luci::CircleWhile while_node(2, 2);
+
+ EXPECT_ANY_THROW(while_node.input(100));
+}
+
+TEST(CircleWhileTestDeath, invalid_input_set_index_NEG)
+{
+ luci::CircleWhile while_node(2, 2);
+
+ EXPECT_ANY_THROW(while_node.input(100, nullptr));
+}
+
+TEST(CircleWhileTestDeath, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleWhile while_node(2, 2);
+
+ TestVisitor tv;
+ ASSERT_THROW(while_node.accept(&tv), std::exception);
+}
+
+TEST(CircleWhileTestDeath, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleWhile while_node(2, 2);
+
+ TestVisitor tv;
+ ASSERT_THROW(while_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleWhileOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleWhileOut.test.cpp
new file mode 100644
index 000000000..1800e4098
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleWhileOut.test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleWhileOut.h"
+
+#include "luci/IR/CircleDialect.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleWhileOutTest, constructor)
+{
+ luci::CircleWhileOut whileout_node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), whileout_node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::CIRCLEWHILEOUT, whileout_node.opcode());
+
+ ASSERT_EQ(nullptr, whileout_node.input());
+ ASSERT_EQ(-1, whileout_node.index());
+}
diff --git a/compiler/luci/lang/src/Nodes/CircleZerosLike.test.cpp b/compiler/luci/lang/src/Nodes/CircleZerosLike.test.cpp
new file mode 100644
index 000000000..3368c8e3f
--- /dev/null
+++ b/compiler/luci/lang/src/Nodes/CircleZerosLike.test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/IR/Nodes/CircleZerosLike.h"
+
+#include "luci/IR/CircleDialect.h"
+#include "luci/IR/CircleNodeVisitor.h"
+
+#include <gtest/gtest.h>
+
+TEST(CircleZerosLikeTest, constructor_P)
+{
+ luci::CircleZerosLike node;
+
+ ASSERT_EQ(luci::CircleDialect::get(), node.dialect());
+ ASSERT_EQ(luci::CircleOpcode::ZEROS_LIKE, node.opcode());
+
+ ASSERT_EQ(nullptr, node.input());
+}
+
+TEST(CircleZerosLikeTest, input_NEG)
+{
+ luci::CircleZerosLike zeros_node;
+ luci::CircleZerosLike node;
+
+ zeros_node.input(&node);
+ ASSERT_NE(nullptr, zeros_node.input());
+
+ zeros_node.input(nullptr);
+ ASSERT_EQ(nullptr, zeros_node.input());
+}
+
+TEST(CircleZerosLikeTest, arity_NEG)
+{
+ luci::CircleZerosLike zeros_node;
+
+ ASSERT_NO_THROW(zeros_node.arg(0));
+ ASSERT_THROW(zeros_node.arg(1), std::out_of_range);
+}
+
+TEST(CircleZerosLikeTest, visit_mutable_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeMutableVisitor<void>
+ {
+ };
+
+ luci::CircleZerosLike zeros_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(zeros_node.accept(&tv), std::exception);
+}
+
+TEST(CircleZerosLikeTest, visit_NEG)
+{
+ struct TestVisitor final : public luci::CircleNodeVisitor<void>
+ {
+ };
+
+ luci::CircleZerosLike zeros_node;
+
+ TestVisitor tv;
+ ASSERT_THROW(zeros_node.accept(&tv), std::exception);
+}
diff --git a/compiler/luci/log/CMakeLists.txt b/compiler/luci/log/CMakeLists.txt
index af2e7a768..5e822871b 100644
--- a/compiler/luci/log/CMakeLists.txt
+++ b/compiler/luci/log/CMakeLists.txt
@@ -6,4 +6,5 @@ target_include_directories(luci_log PUBLIC include)
target_link_libraries(luci_log PUBLIC hermes)
target_link_libraries(luci_log PRIVATE hermes_std)
target_link_libraries(luci_log PRIVATE nncc_common)
+target_link_libraries(luci_log PRIVATE luci_env)
install(TARGETS luci_log DESTINATION lib)
diff --git a/compiler/luci/log/include/luci/Log.h b/compiler/luci/log/include/luci/Log.h
index 51299a082..e148810d8 100644
--- a/compiler/luci/log/include/luci/Log.h
+++ b/compiler/luci/log/include/luci/Log.h
@@ -35,7 +35,7 @@ public:
/**
* @brief Logger Configuration
*
- * Users are able to turn logging on/off via MOCO_LOG environment variable.
+ * Users are able to turn logging on/off via LUCI_LOG environment variable.
*/
class LoggerConfig final : public hermes::Config
{
@@ -47,7 +47,9 @@ public:
void configure(const Logger *, hermes::Source::Setting &) const;
private:
- bool _enabled;
+ bool _show_warn = true;
+ bool _show_info = false;
+ int _show_verbose = 0;
};
} // namespace luci
@@ -64,8 +66,10 @@ private:
*/
#define LOGGER(name) ::luci::Logger name{::luci::LoggingContext::get()};
-// TODO Support FATAL, ERROR, WARN, and VERBOSE
+// TODO Support FATAL, ERROR
#define INFO(name) HERMES_INFO(name)
+#define WARN(name) HERMES_WARN(name)
+#define VERBOSE(name, lv) HERMES_VERBOSE(name, lv)
// WARNING!
//
diff --git a/compiler/luci/log/src/Log.cpp b/compiler/luci/log/src/Log.cpp
index 7e1634009..c26bf307b 100644
--- a/compiler/luci/log/src/Log.cpp
+++ b/compiler/luci/log/src/Log.cpp
@@ -16,6 +16,8 @@
#include "luci/Log.h"
+#include <luci/UserSettings.h>
+
#include <cassert>
#include <cstdlib>
#include <iostream>
@@ -36,6 +38,11 @@ template <> bool safecast<bool>(const char *s, const bool &value)
return (s == nullptr) ? value : (std::stoi(s) != 0);
}
+template <> int safecast<int>(const char *s, const int &value)
+{
+ return (s == nullptr) ? value : std::stoi(s);
+}
+
} // namespace
//
@@ -57,8 +64,16 @@ namespace luci
LoggerConfig::LoggerConfig()
{
- // Turn on logging if LUCI_LOG is set as non-zero value
- _enabled = safecast<bool>(std::getenv("LUCI_LOG"), false);
+ auto settings = luci::UserSettings::settings();
+
+ _show_warn = !settings->get(luci::UserSettings::Key::MuteWarnings);
+
+ // Turn on info logging if LUCI_LOG is set as non-zero value
+ _show_info = safecast<bool>(std::getenv("LUCI_LOG"), false);
+
+ // Turn on verbose logging if LUCI_LOG is set to some level
+ // VERBOSE(l, 1) will be visible with LUCI_LOG=2 and VERBOSE(l, 2) with LUCI_LOG=3 and so on
+ _show_verbose = safecast<int>(std::getenv("LUCI_LOG"), 0);
}
void LoggerConfig::configure(const hermes::Source *source, hermes::Source::Setting &setting) const
@@ -72,15 +87,24 @@ void LoggerConfig::configure(const hermes::Source *source, hermes::Source::Setti
void LoggerConfig::configure(const Logger *, hermes::Source::Setting &setting) const
{
- if (_enabled)
+ setting.filter(hermes::SeverityCategory::FATAL).reject_all();
+ setting.filter(hermes::SeverityCategory::ERROR).reject_all();
+ setting.filter(hermes::SeverityCategory::WARN).reject_all();
+ setting.filter(hermes::SeverityCategory::INFO).reject_all();
+ setting.filter(hermes::SeverityCategory::VERBOSE).reject_all();
+
+ // TODO enable FATAL and ERROR
+ if (_show_warn)
+ {
+ setting.filter(hermes::SeverityCategory::WARN).accept_all();
+ }
+ if (_show_info)
{
- // Enable all catagories
- setting.accept_all();
+ setting.filter(hermes::SeverityCategory::INFO).accept_all();
}
- else
+ if (_show_verbose)
{
- // Disable all catagories
- setting.reject_all();
+ setting.filter(hermes::SeverityCategory::VERBOSE).accept_upto(_show_verbose);
}
}
diff --git a/compiler/luci/logex/src/FormattedGraph.cpp b/compiler/luci/logex/src/FormattedGraph.cpp
index 894ebc151..4725ee3df 100644
--- a/compiler/luci/logex/src/FormattedGraph.cpp
+++ b/compiler/luci/logex/src/FormattedGraph.cpp
@@ -78,6 +78,8 @@ const char *to_str(loco::DataType type)
}
}
+const char *to_str(bool value) { return value ? "true" : "false"; }
+
const char *to_str(luci::FusedActFunc fused)
{
switch (fused)
@@ -108,6 +110,19 @@ const char *to_str(luci::Padding padding)
}
}
+const char *to_str(luci::MirrorPadMode mode)
+{
+ switch (mode)
+ {
+ case luci::MirrorPadMode::REFLECT:
+ return "REFLECT";
+ case luci::MirrorPadMode::SYMMETRIC:
+ return "SYMMETRIC";
+ default:
+ return "Error";
+ }
+}
+
std::string to_str(const luci::Stride *stride)
{
return pepper::str(stride->h(), ",", stride->w());
@@ -180,43 +195,187 @@ private:
#define IMPLEMENT(CLASS) bool summary(const CLASS *, locop::NodeSummary &) const final;
IMPLEMENT(luci::CircleAbs)
IMPLEMENT(luci::CircleAdd)
+ IMPLEMENT(luci::CircleAddN)
IMPLEMENT(luci::CircleArgMax)
+ IMPLEMENT(luci::CircleArgMin)
IMPLEMENT(luci::CircleAveragePool2D)
+ IMPLEMENT(luci::CircleBatchMatMul)
IMPLEMENT(luci::CircleBatchToSpaceND)
+ IMPLEMENT(luci::CircleCast)
+ IMPLEMENT(luci::CircleCeil)
IMPLEMENT(luci::CircleConcatenation)
IMPLEMENT(luci::CircleConst)
IMPLEMENT(luci::CircleConv2D)
IMPLEMENT(luci::CircleCos)
+ IMPLEMENT(luci::CircleCustom)
+ IMPLEMENT(luci::CircleDepthToSpace)
IMPLEMENT(luci::CircleDepthwiseConv2D)
IMPLEMENT(luci::CircleDiv)
+ IMPLEMENT(luci::CircleElu)
IMPLEMENT(luci::CircleExp)
+ IMPLEMENT(luci::CircleExpandDims)
+ IMPLEMENT(luci::CircleFill)
+ IMPLEMENT(luci::CircleFloor)
+ IMPLEMENT(luci::CircleFloorDiv)
+ IMPLEMENT(luci::CircleFloorMod)
IMPLEMENT(luci::CircleFullyConnected)
+ IMPLEMENT(luci::CircleGather)
+ IMPLEMENT(luci::CircleGatherNd)
+ IMPLEMENT(luci::CircleGreater)
+ IMPLEMENT(luci::CircleGreaterEqual)
+ IMPLEMENT(luci::CircleIf)
+ IMPLEMENT(luci::CircleL2Normalize)
+ IMPLEMENT(luci::CircleLeakyRelu)
+ IMPLEMENT(luci::CircleLess)
+ IMPLEMENT(luci::CircleLessEqual)
+ IMPLEMENT(luci::CircleLocalResponseNormalization)
+ IMPLEMENT(luci::CircleLog)
+ IMPLEMENT(luci::CircleLogicalAnd)
IMPLEMENT(luci::CircleLogicalNot)
IMPLEMENT(luci::CircleLogicalOr)
+ IMPLEMENT(luci::CircleLogistic)
+ IMPLEMENT(luci::CircleLogSoftmax)
+ IMPLEMENT(luci::CircleMatrixDiag)
+ IMPLEMENT(luci::CircleMatrixSetDiag)
IMPLEMENT(luci::CircleMaximum)
IMPLEMENT(luci::CircleMaxPool2D)
IMPLEMENT(luci::CircleMean)
+ IMPLEMENT(luci::CircleMinimum)
+ IMPLEMENT(luci::CircleMirrorPad)
IMPLEMENT(luci::CircleMul)
+ IMPLEMENT(luci::CircleNeg)
+ IMPLEMENT(luci::CircleNotEqual)
+ IMPLEMENT(luci::CircleOneHot)
IMPLEMENT(luci::CirclePack)
IMPLEMENT(luci::CirclePad)
+ IMPLEMENT(luci::CirclePow)
+ IMPLEMENT(luci::CirclePRelu)
+ IMPLEMENT(luci::CircleRange)
+ IMPLEMENT(luci::CircleRank)
+ IMPLEMENT(luci::CircleReduceAny)
+ IMPLEMENT(luci::CircleReduceMax)
+ IMPLEMENT(luci::CircleReduceMin)
+ IMPLEMENT(luci::CircleReduceProd)
IMPLEMENT(luci::CircleRelu)
IMPLEMENT(luci::CircleRelu6)
+ IMPLEMENT(luci::CircleReluN1To1)
IMPLEMENT(luci::CircleReshape)
+ IMPLEMENT(luci::CircleResizeBilinear)
+ IMPLEMENT(luci::CircleResizeNearestNeighbor)
+ IMPLEMENT(luci::CircleReverseSequence)
+ IMPLEMENT(luci::CircleReverseV2)
+ IMPLEMENT(luci::CircleRound)
IMPLEMENT(luci::CircleRsqrt)
+ IMPLEMENT(luci::CircleScatterNd)
+ IMPLEMENT(luci::CircleSegmentSum)
+ IMPLEMENT(luci::CircleSelect)
+ IMPLEMENT(luci::CircleSelectV2)
+ IMPLEMENT(luci::CircleShape)
+ IMPLEMENT(luci::CircleSin)
+ IMPLEMENT(luci::CircleSlice)
IMPLEMENT(luci::CircleSoftmax)
+ IMPLEMENT(luci::CircleSpaceToBatchND)
+ IMPLEMENT(luci::CircleSpaceToDepth)
+ IMPLEMENT(luci::CircleSparseToDense)
+ IMPLEMENT(luci::CircleSplit)
+ IMPLEMENT(luci::CircleSplitV)
IMPLEMENT(luci::CircleSqrt)
+ IMPLEMENT(luci::CircleSquare)
IMPLEMENT(luci::CircleSquaredDifference)
+ IMPLEMENT(luci::CircleSqueeze)
+ IMPLEMENT(luci::CircleStridedSlice)
IMPLEMENT(luci::CircleSub)
+ IMPLEMENT(luci::CircleSum)
+ IMPLEMENT(luci::CircleTanh)
+ IMPLEMENT(luci::CircleTile)
+ IMPLEMENT(luci::CircleTopKV2)
IMPLEMENT(luci::CircleTranspose)
IMPLEMENT(luci::CircleTransposeConv)
+ IMPLEMENT(luci::CircleUnpack)
+ IMPLEMENT(luci::CircleWhere)
+ IMPLEMENT(luci::CircleWhile)
+ IMPLEMENT(luci::CircleZerosLike)
// Circle Only
+ IMPLEMENT(luci::CircleBCQFullyConnected)
+ IMPLEMENT(luci::CircleBCQGather)
IMPLEMENT(luci::CircleInstanceNorm)
// Virtual nodes
IMPLEMENT(luci::CircleInput)
IMPLEMENT(luci::CircleOutput)
+ IMPLEMENT(luci::CircleIfOut)
+ IMPLEMENT(luci::CircleSplitOut)
+ IMPLEMENT(luci::CircleSplitVOut)
+ IMPLEMENT(luci::CircleTopKV2Out)
+ IMPLEMENT(luci::CircleUnpackOut)
+ IMPLEMENT(luci::CircleWhileOut)
#undef IMPLEMENT
};
+template <class CIRCLENODE>
+bool use_x(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s)
+{
+ s.args().append("x", tbl->lookup(node->x()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+template <class CIRCLENODE>
+bool use_input(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s)
+{
+ s.args().append("input", tbl->lookup(node->input()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+template <class CIRCLENODE>
+bool use_features(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s)
+{
+ s.args().append("features", tbl->lookup(node->features()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+template <class CIRCLENODE>
+bool use_xy(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s)
+{
+ s.args().append("x", tbl->lookup(node->x()));
+ s.args().append("y", tbl->lookup(node->y()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+template <class CIRCLENODE>
+bool use_xy_act(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s)
+{
+ assert(node->fusedActivationFunction() != luci::FusedActFunc::UNDEFINED);
+
+ s.args().append("x", tbl->lookup(node->x()));
+ s.args().append("y", tbl->lookup(node->y()));
+ s.args().append("fused_activation_function", to_str(node->fusedActivationFunction()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+template <class CIRCLENODE>
+bool use_reducer(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s)
+{
+ s.args().append("input", tbl->lookup(node->input()));
+ s.args().append("reduction_indices", tbl->lookup(node->reduction_indices()));
+ s.args().append("keep_dims", node->keep_dims() ? "true" : "false");
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+template <class CIRCLENODE>
+bool use_ido(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s)
+{
+ s.args().append("input", tbl->lookup(node->input()));
+ s.args().append("dimension", tbl->lookup(node->dimension()));
+ s.args().append("output_type", to_str(node->output_type()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
bool CircleNodeSummaryBuilderBase::build(const loco::Node *node, locop::NodeSummary &s) const
{
if (node->dialect() != luci::CircleDialect::get())
@@ -236,29 +395,31 @@ bool CircleNodeSummaryBuilderBase::build(const loco::Node *node, locop::NodeSumm
bool CircleNodeSummaryBuilder::summary(const luci::CircleAbs *node, locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
- s.state(locop::NodeSummary::State::Complete);
- return true;
+ return use_x(tbl(), node, s);
}
bool CircleNodeSummaryBuilder::summary(const luci::CircleAdd *node, locop::NodeSummary &s) const
{
- assert(node->fusedActivationFunction() != luci::FusedActFunc::UNDEFINED);
+ return use_xy_act(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleAddN *node, locop::NodeSummary &s) const
+{
+ for (uint32_t i = 0; i < node->arity(); ++i)
+ s.args().append("inputs", tbl()->lookup(node->inputs(i)));
- s.args().append("x", tbl()->lookup(node->x()));
- s.args().append("y", tbl()->lookup(node->y()));
- s.args().append("fused_activation_function", to_str(node->fusedActivationFunction()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
bool CircleNodeSummaryBuilder::summary(const luci::CircleArgMax *node, locop::NodeSummary &s) const
{
- s.args().append("input", tbl()->lookup(node->input()));
- s.args().append("dimension", tbl()->lookup(node->dimension()));
- s.args().append("output_type", to_str(node->output_type()));
- s.state(locop::NodeSummary::State::Complete);
- return true;
+ return use_ido(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleArgMin *node, locop::NodeSummary &s) const
+{
+ return use_ido(tbl(), node, s);
}
bool CircleNodeSummaryBuilder::summary(const luci::CircleAveragePool2D *node,
@@ -277,6 +438,17 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleAveragePool2D *node,
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleBatchMatMul *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("x", tbl()->lookup(node->x()));
+ s.args().append("y", tbl()->lookup(node->y()));
+ s.args().append("adj_x", to_str(node->adj_x()));
+ s.args().append("adj_y", to_str(node->adj_y()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleBatchToSpaceND *node,
locop::NodeSummary &s) const
{
@@ -289,6 +461,20 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleBatchToSpaceND *node,
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleCast *node, locop::NodeSummary &s) const
+{
+ s.args().append("x", tbl()->lookup(node->x()));
+ s.args().append("in_data_type", to_str(node->in_data_type()));
+ s.args().append("out_data_type", to_str(node->out_data_type()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleCeil *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleConcatenation *node,
locop::NodeSummary &s) const
{
@@ -318,6 +504,8 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleConv2D *node, locop::No
s.args().append("bias", tbl()->lookup(node->bias()));
s.args().append("stride(h,w)", to_str(node->stride()));
+ s.args().append("dilation(h,w)", to_str(node->dilation()));
+
s.args().append("padding", to_str(node->padding()));
s.args().append("fused", to_str(node->fusedActivationFunction()));
@@ -328,8 +516,28 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleConv2D *node, locop::No
bool CircleNodeSummaryBuilder::summary(const luci::CircleCos *node, locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleCustom *node, locop::NodeSummary &s) const
+{
+ for (uint32_t i = 0; i < node->numInputs(); i++)
+ {
+ s.args().append("input" + std::to_string(i), tbl()->lookup(node->inputs(i)));
+ }
+ s.args().append("custom_code", node->custom_code());
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleDepthToSpace *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("block_size", std::to_string(node->block_size()));
+
s.state(locop::NodeSummary::State::Complete);
+
return true;
}
@@ -344,6 +552,7 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleDepthwiseConv2D *node,
s.args().append("bias", tbl()->lookup(node->bias()));
s.args().append("stride(h,w)", to_str(node->stride()));
+ s.args().append("dilation(h,w)", to_str(node->dilation()));
s.args().append("padding", to_str(node->padding()));
s.args().append("depthMultiplier", std::to_string(node->depthMultiplier()));
s.args().append("fused", to_str(node->fusedActivationFunction()));
@@ -355,15 +564,49 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleDepthwiseConv2D *node,
bool CircleNodeSummaryBuilder::summary(const luci::CircleDiv *node, locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
- s.args().append("y", tbl()->lookup(node->y()));
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleElu *node, locop::NodeSummary &s) const
+{
+ return use_features(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleExp *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleExpandDims *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("axis", tbl()->lookup(node->axis()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
-bool CircleNodeSummaryBuilder::summary(const luci::CircleExp *node, locop::NodeSummary &s) const
+bool CircleNodeSummaryBuilder::summary(const luci::CircleFloor *node, locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleFloorDiv *node,
+ locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleFloorMod *node,
+ locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleFill *node, locop::NodeSummary &s) const
+{
+ s.args().append("dims", tbl()->lookup(node->dims()));
+ s.args().append("value", tbl()->lookup(node->value()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
@@ -383,31 +626,157 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleFullyConnected *node,
return true;
}
-bool CircleNodeSummaryBuilder::summary(const luci::CircleLogicalNot *node,
+bool CircleNodeSummaryBuilder::summary(const luci::CircleGather *node, locop::NodeSummary &s) const
+{
+ s.args().append("params", tbl()->lookup(node->params()));
+ s.args().append("indices", tbl()->lookup(node->indices()));
+ s.args().append("axis", pepper::str(node->axis()));
+
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleGatherNd *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("params", tbl()->lookup(node->params()));
+ s.args().append("indices", tbl()->lookup(node->indices()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleGreater *node, locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleGreaterEqual *node,
+ locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleIf *node, locop::NodeSummary &s) const
+{
+ s.args().append("cond", tbl()->lookup(node->cond()));
+ for (uint32_t i = 0; i < node->input_count(); ++i)
+ s.args().append("input", tbl()->lookup(node->input(i)));
+
+ if (node->then_graph() != nullptr)
+ s.args().append("then_graph", node->then_graph()->name());
+ else
+ s.args().append("then_branch", pepper::str(node->then_branch()));
+
+ if (node->else_graph() != nullptr)
+ s.args().append("else_graph", node->else_graph()->name());
+ else
+ s.args().append("else_branch", pepper::str(node->else_branch()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleL2Normalize *node,
locop::NodeSummary &s) const
{
s.args().append("x", tbl()->lookup(node->x()));
+ s.args().append("fused_activation_function", to_str(node->fusedActivationFunction()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLess *node, locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLessEqual *node,
+ locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLeakyRelu *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("features", tbl()->lookup(node->features()));
+ s.args().append("alpha", std::to_string(node->alpha()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLocalResponseNormalization *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("radius", pepper::str(node->radius()));
+ s.args().append("bias", pepper::str(node->bias()));
+ s.args().append("alpha", pepper::str(node->alpha()));
+ s.args().append("beta", pepper::str(node->beta()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLog *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLogicalAnd *node,
+ locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLogicalNot *node,
+ locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleLogicalOr *node,
locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
- s.args().append("y", tbl()->lookup(node->y()));
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLogistic *node,
+ locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleLogSoftmax *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("logits", tbl()->lookup(node->logits()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
-bool CircleNodeSummaryBuilder::summary(const luci::CircleMaximum *node, locop::NodeSummary &s) const
+bool CircleNodeSummaryBuilder::summary(const luci::CircleMatrixDiag *node,
+ locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
- s.args().append("y", tbl()->lookup(node->y()));
+ s.args().append("diagonal", tbl()->lookup(node->diagonal()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleMatrixSetDiag *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("diagonal", tbl()->lookup(node->diagonal()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleMaximum *node, locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleMaxPool2D *node,
locop::NodeSummary &s) const
{
@@ -426,20 +795,48 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleMaxPool2D *node,
bool CircleNodeSummaryBuilder::summary(const luci::CircleMean *node, locop::NodeSummary &s) const
{
+ return use_reducer(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleMinimum *node, locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleMirrorPad *node,
+ locop::NodeSummary &s) const
+{
s.args().append("input", tbl()->lookup(node->input()));
- s.args().append("reduction_indices", tbl()->lookup(node->reduction_indices()));
- s.args().append("keep_dims", node->keep_dims() ? "true" : "false");
+ s.args().append("paddings", tbl()->lookup(node->paddings()));
+ s.args().append("mode", to_str(node->mode()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
bool CircleNodeSummaryBuilder::summary(const luci::CircleMul *node, locop::NodeSummary &s) const
{
- assert(node->fusedActivationFunction() != luci::FusedActFunc::UNDEFINED);
+ return use_xy_act(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleNeg *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleNotEqual *node,
+ locop::NodeSummary &s) const
+{
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleOneHot *node, locop::NodeSummary &s) const
+{
+ s.args().append("indices", tbl()->lookup(node->indices()));
+ s.args().append("depth", tbl()->lookup(node->depth()));
+ s.args().append("on_value", tbl()->lookup(node->on_value()));
+ s.args().append("off_value", tbl()->lookup(node->off_value()));
+ s.args().append("axis", pepper::str(node->axis()));
- s.args().append("x", tbl()->lookup(node->x()));
- s.args().append("y", tbl()->lookup(node->y()));
- s.args().append("fused_activation_function", to_str(node->fusedActivationFunction()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
@@ -462,20 +859,74 @@ bool CircleNodeSummaryBuilder::summary(const luci::CirclePad *node, locop::NodeS
return true;
}
-bool CircleNodeSummaryBuilder::summary(const luci::CircleRelu *node, locop::NodeSummary &s) const
+bool CircleNodeSummaryBuilder::summary(const luci::CirclePow *node, locop::NodeSummary &s) const
{
- s.args().append("features", tbl()->lookup(node->features()));
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CirclePRelu *node, locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("alpha", tbl()->lookup(node->alpha()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
-bool CircleNodeSummaryBuilder::summary(const luci::CircleRelu6 *node, locop::NodeSummary &s) const
+bool CircleNodeSummaryBuilder::summary(const luci::CircleRange *node, locop::NodeSummary &s) const
{
- s.args().append("features", tbl()->lookup(node->features()));
+ s.args().append("start", tbl()->lookup(node->start()));
+ s.args().append("limit", tbl()->lookup(node->limit()));
+ s.args().append("delta", tbl()->lookup(node->delta()));
+
s.state(locop::NodeSummary::State::Complete);
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleRank *node, locop::NodeSummary &s) const
+{
+ return use_input(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleReduceAny *node,
+ locop::NodeSummary &s) const
+{
+ return use_reducer(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleReduceMax *node,
+ locop::NodeSummary &s) const
+{
+ return use_reducer(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleReduceMin *node,
+ locop::NodeSummary &s) const
+{
+ return use_reducer(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleReduceProd *node,
+ locop::NodeSummary &s) const
+{
+ return use_reducer(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleRelu *node, locop::NodeSummary &s) const
+{
+ return use_features(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleRelu6 *node, locop::NodeSummary &s) const
+{
+ return use_features(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleReluN1To1 *node,
+ locop::NodeSummary &s) const
+{
+ return use_features(tbl(), node, s);
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleReshape *node, locop::NodeSummary &s) const
{
s.args().append("tensor", tbl()->lookup(node->tensor()));
@@ -485,9 +936,113 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleReshape *node, locop::N
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleResizeBilinear *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("size", tbl()->lookup(node->size()));
+ s.args().append("align_corners", node->align_corners() ? "true" : "false");
+ s.args().append("half_pixel_centers", node->half_pixel_centers() ? "true" : "false");
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleResizeNearestNeighbor *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("size", tbl()->lookup(node->size()));
+ s.args().append("align_corners", node->align_corners() ? "true" : "false");
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleReverseSequence *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("seq_lengths", tbl()->lookup(node->seq_lengths()));
+ s.args().append("seq_axis", std::to_string(node->seq_axis()));
+ s.args().append("batch_axis", std::to_string(node->batch_axis()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleReverseV2 *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("tensor", tbl()->lookup(node->tensor()));
+ s.args().append("axis", tbl()->lookup(node->axis()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleRound *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleRsqrt *node, locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleScatterNd *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("indices", tbl()->lookup(node->indices()));
+ s.args().append("updates", tbl()->lookup(node->updates()));
+ s.args().append("shape", tbl()->lookup(node->shape()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSegmentSum *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("segment_ids", tbl()->lookup(node->segment_ids()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSelect *node, locop::NodeSummary &s) const
+{
+ s.args().append("condition", tbl()->lookup(node->condition()));
+ s.args().append("t", tbl()->lookup(node->t()));
+ s.args().append("e", tbl()->lookup(node->e()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSelectV2 *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("condition", tbl()->lookup(node->condition()));
+ s.args().append("t", tbl()->lookup(node->t()));
+ s.args().append("e", tbl()->lookup(node->e()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleShape *node, locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("out_type", to_str(node->out_type()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSin *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSlice *node, locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("begin", tbl()->lookup(node->begin()));
+ s.args().append("size", tbl()->lookup(node->size()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
@@ -500,31 +1055,151 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleSoftmax *node, locop::N
return true;
}
-bool CircleNodeSummaryBuilder::summary(const luci::CircleSqrt *node, locop::NodeSummary &s) const
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSpaceToBatchND *node,
+ locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("block_shape", tbl()->lookup(node->block_shape()));
+ s.args().append("paddings", tbl()->lookup(node->paddings()));
+
s.state(locop::NodeSummary::State::Complete);
+
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSpaceToDepth *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("block_size", pepper::str(node->block_size()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSparseToDense *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("indices", tbl()->lookup(node->indices()));
+ s.args().append("output_shape", tbl()->lookup(node->output_shape()));
+ s.args().append("values", tbl()->lookup(node->values()));
+ s.args().append("default_value", tbl()->lookup(node->default_value()));
+
+ s.args().append("Validate_indices", pepper::str(node->validate_indices()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSplit *node, locop::NodeSummary &s) const
+{
+ s.args().append("split_dim", tbl()->lookup(node->split_dim()));
+ s.args().append("input", tbl()->lookup(node->input()));
+
+ s.args().append("num_split", pepper::str(node->num_split()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSplitV *node, locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("size_splits", tbl()->lookup(node->size_splits()));
+ s.args().append("split_dim", tbl()->lookup(node->split_dim()));
+
+ s.args().append("num_split", pepper::str(node->num_split()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSqrt *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSquare *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleSquaredDifference *node,
locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
- s.args().append("y", tbl()->lookup(node->y()));
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSqueeze *node, locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+
+ std::stringstream ss{"("};
+ for (size_t i = 0; i < node->squeeze_dims().size(); ++i)
+ {
+ if (i != 0)
+ ss << ", ";
+ ss << node->squeeze_dims()[i];
+ }
+ ss << ")";
+
+ s.args().append("squeeze_dims", ss.str());
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleStridedSlice *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("begin", tbl()->lookup(node->begin()));
+ s.args().append("end", tbl()->lookup(node->end()));
+ s.args().append("strides", tbl()->lookup(node->strides()));
+
+ s.args().append("begin_mask", pepper::str(node->begin_mask()));
+ s.args().append("end_mask", pepper::str(node->end_mask()));
+ s.args().append("ellipsis_mask", pepper::str(node->ellipsis_mask()));
+ s.args().append("new_axis_mask", pepper::str(node->new_axis_mask()));
+ s.args().append("shrink_axis_mask", pepper::str(node->shrink_axis_mask()));
+
s.state(locop::NodeSummary::State::Complete);
return true;
}
bool CircleNodeSummaryBuilder::summary(const luci::CircleSub *node, locop::NodeSummary &s) const
{
- s.args().append("x", tbl()->lookup(node->x()));
- s.args().append("y", tbl()->lookup(node->y()));
+ return use_xy(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSum *node, locop::NodeSummary &s) const
+{
+ return use_reducer(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleTanh *node, locop::NodeSummary &s) const
+{
+ return use_x(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleTile *node, locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("multiples", tbl()->lookup(node->multiples()));
s.state(locop::NodeSummary::State::Complete);
return true;
}
-// TODO TFLTanh
+bool CircleNodeSummaryBuilder::summary(const luci::CircleTopKV2 *node, locop::NodeSummary &s) const
+{
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("k", tbl()->lookup(node->k()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
bool CircleNodeSummaryBuilder::summary(const luci::CircleTranspose *node,
locop::NodeSummary &s) const
@@ -552,6 +1227,97 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleTransposeConv *node,
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleUnpack *node, locop::NodeSummary &s) const
+{
+ s.args().append("value", tbl()->lookup(node->value()));
+
+ s.args().append("num", pepper::str(node->num()));
+ s.args().append("axis", pepper::str(node->axis()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleWhere *node, locop::NodeSummary &s) const
+{
+ s.args().append("condition", tbl()->lookup(node->condition()));
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleWhile *node, locop::NodeSummary &s) const
+{
+ for (uint32_t i = 0; i < node->input_count(); ++i)
+ s.args().append("input", tbl()->lookup(node->input(i)));
+
+ if (node->cond_graph() != nullptr)
+ s.args().append("cond_graph", node->cond_graph()->name());
+ else
+ s.args().append("cond_branch", pepper::str(node->cond_branch()));
+
+ if (node->body_graph() != nullptr)
+ s.args().append("body_graph", node->body_graph()->name());
+ else
+ s.args().append("body_branch", pepper::str(node->body_branch()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleZerosLike *node,
+ locop::NodeSummary &s) const
+{
+ return use_input(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSplitOut *node,
+ locop::NodeSummary &s) const
+{
+ return use_input(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleSplitVOut *node,
+ locop::NodeSummary &s) const
+{
+ return use_input(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleTopKV2Out *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("topkv2", tbl()->lookup(node->input()));
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleUnpackOut *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("unpack", tbl()->lookup(node->input()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleIfOut *node, locop::NodeSummary &s) const
+{
+ return use_input(tbl(), node, s);
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleWhileOut *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("while", tbl()->lookup(node->input()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleInput *, locop::NodeSummary &s) const
{
s.state(locop::NodeSummary::State::Complete);
@@ -566,6 +1332,40 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleOutput *node, locop::No
return true;
}
+bool CircleNodeSummaryBuilder::summary(const luci::CircleBCQFullyConnected *node,
+ locop::NodeSummary &s) const
+{
+ assert(node->fusedActivationFunction() != luci::FusedActFunc::UNDEFINED);
+
+ s.args().append("input", tbl()->lookup(node->input()));
+ s.args().append("weights_scales", tbl()->lookup(node->weights_scales()));
+ s.args().append("weights_binary", tbl()->lookup(node->weights_binary()));
+ s.args().append("bias", tbl()->lookup(node->bias()));
+ s.args().append("weights_clusters", tbl()->lookup(node->weights_clusters()));
+
+ s.args().append("fused", to_str(node->fusedActivationFunction()));
+ s.args().append("weights_hidden_size", pepper::str(node->weights_hidden_size()));
+
+ s.state(locop::NodeSummary::State::Complete);
+
+ return true;
+}
+
+bool CircleNodeSummaryBuilder::summary(const luci::CircleBCQGather *node,
+ locop::NodeSummary &s) const
+{
+ s.args().append("input_scales", tbl()->lookup(node->input_scales()));
+ s.args().append("input_binary", tbl()->lookup(node->input_binary()));
+ s.args().append("indices", tbl()->lookup(node->indices()));
+ s.args().append("input_clusters", tbl()->lookup(node->input_clusters()));
+
+ s.args().append("axis", pepper::str(node->axis()));
+ s.args().append("input_hidden_size", pepper::str(node->input_hidden_size()));
+
+ s.state(locop::NodeSummary::State::Complete);
+ return true;
+}
+
bool CircleNodeSummaryBuilder::summary(const luci::CircleInstanceNorm *node,
locop::NodeSummary &s) const
{
@@ -603,4 +1403,4 @@ bool NodeSummaryBuilder::build(const loco::Node *node, locop::NodeSummary &s) co
return false;
}
-} // namespace exo
+} // namespace luci
diff --git a/compiler/luci/pass/CMakeLists.txt b/compiler/luci/pass/CMakeLists.txt
index 93130ce60..2c5fb3407 100644
--- a/compiler/luci/pass/CMakeLists.txt
+++ b/compiler/luci/pass/CMakeLists.txt
@@ -1,6 +1,6 @@
file(GLOB_RECURSE SOURCES "src/*.cpp")
-#file(GLOB_RECURSE TESTS "src/*.test.cpp")
-#list(REMOVE_ITEM SOURCES ${TESTS})
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
add_library(luci_pass SHARED ${SOURCES})
target_include_directories(luci_pass PRIVATE src)
@@ -16,14 +16,14 @@ target_link_libraries(luci_pass PRIVATE nncc_common)
target_link_libraries(luci_pass PRIVATE oops)
install(TARGETS luci_pass DESTINATION lib)
-# TODO enable for tests
-#if(NOT ENABLE_TEST)
-# return()
-#endif(NOT ENABLE_TEST)
-#
-#nnas_find_package(GTest REQUIRED)
-#
-#GTest_AddTest(luci_pass_test ${TESTS})
-#target_include_directories(luci_pass_test PRIVATE src)
-#target_link_libraries(luci_pass_test luci_pass)
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
+
+GTest_AddTest(luci_pass_test ${TESTS})
+target_include_directories(luci_pass_test PRIVATE src)
+target_link_libraries(luci_pass_test luci_pass)
+target_link_libraries(luci_pass_test luci_lang)
#target_link_libraries(luci_pass_test oops)
diff --git a/compiler/luci/pass/include/luci/CircleOptimizer.h b/compiler/luci/pass/include/luci/CircleOptimizer.h
index a969cca85..312749f83 100644
--- a/compiler/luci/pass/include/luci/CircleOptimizer.h
+++ b/compiler/luci/pass/include/luci/CircleOptimizer.h
@@ -32,11 +32,28 @@ public:
{
enum Algorithm
{
+ FuseBCQ,
FuseInstanceNorm,
+ ResolveCustomOpAdd,
+ ResolveCustomOpBatchMatMul,
+ ResolveCustomOpMatMul,
+ QuantizeDequantizeWeights,
+ QuantizeWithMinMax,
};
+ enum AlgorithmParameters
+ {
+ Quantize_input_dtype,
+ Quantize_output_dtype,
+ Quantize_granularity // layer-wise or channel-wise
+ };
+
+ virtual ~Options() = default;
+
virtual void enable(Algorithm) = 0;
virtual bool query(Algorithm) = 0;
+ virtual void param(AlgorithmParameters, const std::string &) = 0;
+ virtual const std::string param(AlgorithmParameters) const = 0;
};
public:
@@ -46,6 +63,8 @@ public:
public:
void optimize(loco::Graph *) const;
+ void quantize(loco::Graph *) const;
+
private:
std::unique_ptr<Options> _options;
};
diff --git a/compiler/luci/pass/include/luci/Pass/FuseBCQPass.h b/compiler/luci/pass/include/luci/Pass/FuseBCQPass.h
new file mode 100644
index 000000000..4404a9fc9
--- /dev/null
+++ b/compiler/luci/pass/include/luci/Pass/FuseBCQPass.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_FUSE_BCQ_PASS_H__
+#define __LUCI_FUSE_BCQ_PASS_H__
+
+#include <logo/Pass.h>
+
+namespace luci
+{
+
+/**
+ * @brief Class to fuse certain pattern of subgraph into CircleBCQFullyConnected or CircleBCQGather
+ *
+ */
+struct FuseBCQPass final : public logo::Pass
+{
+ const char *name(void) const final { return "luci::FuseBCQPass"; }
+
+ bool run(loco::Graph *g) final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_FUSE_BCQ_PASS_H__
diff --git a/compiler/luci/pass/include/luci/Pass/QuantizationParameters.h b/compiler/luci/pass/include/luci/Pass/QuantizationParameters.h
new file mode 100644
index 000000000..5c9cd427f
--- /dev/null
+++ b/compiler/luci/pass/include/luci/Pass/QuantizationParameters.h
@@ -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.
+ */
+
+#ifndef __LUCI_QUANTIZATION_PARAMETERS_H__
+#define __LUCI_QUANTIZATION_PARAMETERS_H__
+
+namespace luci
+{
+
+enum QuantizationGranularity
+{
+ LayerWise = 0,
+ ChannelWise = 1,
+};
+
+} // namespace luci
+
+#endif // __LUCI_QUANTIZATION_PARAMETERS_H__
diff --git a/compiler/luci/pass/include/luci/Pass/QuantizeDequantizeWeightsPass.h b/compiler/luci/pass/include/luci/Pass/QuantizeDequantizeWeightsPass.h
new file mode 100644
index 000000000..713b88f9d
--- /dev/null
+++ b/compiler/luci/pass/include/luci/Pass/QuantizeDequantizeWeightsPass.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_QUANTIZE_DEQUANTIZE_WEIGHTS_PASS_H__
+#define __LUCI_QUANTIZE_DEQUANTIZE_WEIGHTS_PASS_H__
+
+#include <loco.h>
+
+#include <logo/Pass.h>
+
+#include <luci/Pass/QuantizationParameters.h>
+
+namespace luci
+{
+
+/**
+ * @brief Pass to quantize weights
+ */
+class QuantizeDequantizeWeightsPass : public logo::Pass
+{
+public:
+ QuantizeDequantizeWeightsPass(loco::DataType input_dtype, loco::DataType output_dtype,
+ QuantizationGranularity granularity)
+ : _input_dtype{input_dtype}, _output_dtype{output_dtype}, _granularity{granularity}
+ {
+ // DO NOTHING
+ }
+ virtual const char *name(void) const { return "luci::QuantizeDequantizeWeightsPass"; }
+
+public:
+ bool run(loco::Graph *graph);
+
+private:
+ loco::DataType _input_dtype;
+ loco::DataType _output_dtype;
+ QuantizationGranularity _granularity;
+};
+
+} // namespace luci
+
+#endif //__LUCI_QUANTIZE_DEQUANTIZE_WEIGHTS_PASS_H__
diff --git a/compiler/luci/pass/include/luci/Pass/QuantizeWithMinMaxPass.h b/compiler/luci/pass/include/luci/Pass/QuantizeWithMinMaxPass.h
new file mode 100644
index 000000000..bb0d0ff40
--- /dev/null
+++ b/compiler/luci/pass/include/luci/Pass/QuantizeWithMinMaxPass.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_QUANTIZE_WITH_MINMAX_PASS_H__
+#define __LUCI_QUANTIZE_WITH_MINMAX_PASS_H__
+
+#include <loco.h>
+
+#include <logo/Pass.h>
+
+#include <luci/Pass/QuantizationParameters.h>
+
+namespace luci
+{
+
+/**
+ * @brief Pass to quantize activation, weights, and bias
+ */
+class QuantizeWithMinMaxPass : public logo::Pass
+{
+public:
+ QuantizeWithMinMaxPass(loco::DataType input_dtype, loco::DataType output_dtype,
+ QuantizationGranularity granularity)
+ : _input_dtype{input_dtype}, _output_dtype{output_dtype}, _granularity{granularity}
+ {
+ // DO NOTHING
+ }
+ virtual const char *name(void) const { return "luci::QuantizeWithMinMaxPass"; }
+
+public:
+ bool run(loco::Graph *graph);
+
+private:
+ loco::DataType _input_dtype;
+ loco::DataType _output_dtype;
+ QuantizationGranularity _granularity;
+};
+
+} // namespace luci
+
+#endif //__LUCI_QUANTIZE_WITH_MINMAX_PASS_H__
diff --git a/compiler/luci/pass/include/luci/Pass/ResolveCustomOpAddPass.h b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpAddPass.h
new file mode 100644
index 000000000..35a335028
--- /dev/null
+++ b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpAddPass.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 __LUCI_RESOLVE_CUSTOM_OP_ADD_PASS_H__
+#define __LUCI_RESOLVE_CUSTOM_OP_ADD_PASS_H__
+
+#include <logo/Pass.h>
+
+namespace luci
+{
+
+/**
+ * @brief Class to resolve certain custom op of subgraph into add op in circle schema.
+ */
+struct ResolveCustomOpAddPass final : public logo::Pass
+{
+ const char *name(void) const final { return "luci::ResolveCustomOpAddPass"; }
+
+ bool run(loco::Graph *g) final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_RESOLVE_CUSTOM_OP_ADD_PASS_H__
diff --git a/compiler/luci/pass/include/luci/Pass/ResolveCustomOpBatchMatMulPass.h b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpBatchMatMulPass.h
new file mode 100644
index 000000000..7c48c8d16
--- /dev/null
+++ b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpBatchMatMulPass.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 __LUCI_RESOLVE_CUSTOM_OP_BATCHMATMUL_PASS_H__
+#define __LUCI_RESOLVE_CUSTOM_OP_BATCHMATMUL_PASS_H__
+
+#include <logo/Pass.h>
+
+namespace luci
+{
+
+/**
+ * @brief Class to resolve certain custom op of subgraph into batchmatmul op in circle schema.
+ */
+struct ResolveCustomOpBatchMatMulPass final : public logo::Pass
+{
+ const char *name(void) const final { return "luci::ResolveCustomOpBatchMatMulPass"; }
+
+ bool run(loco::Graph *g) final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_RESOLVE_CUSTOM_OP_BATCHMATMUL_PASS_H__
diff --git a/compiler/luci/pass/include/luci/Pass/ResolveCustomOpMatMulPass.h b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpMatMulPass.h
new file mode 100644
index 000000000..701deba91
--- /dev/null
+++ b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpMatMulPass.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 __LUCI_RESOLVE_CUSTOM_OP_MATMUL_PASS_H__
+#define __LUCI_RESOLVE_CUSTOM_OP_MATMUL_PASS_H__
+
+#include <logo/Pass.h>
+
+namespace luci
+{
+
+/**
+ * @brief Class to resolve certain custom op of subgraph into matmul op in circle schema.
+ */
+struct ResolveCustomOpMatMulPass final : public logo::Pass
+{
+ const char *name(void) const final { return "luci::ResolveCustomOpMatMulPass"; }
+
+ bool run(loco::Graph *g) final;
+};
+
+} // namespace luci
+
+#endif // __LUCI_RESOLVE_CUSTOM_OP_MATMUL_PASS_H__
diff --git a/compiler/luci/pass/src/CircleOptimizer.cpp b/compiler/luci/pass/src/CircleOptimizer.cpp
index dcb05a0b5..90fbe9009 100644
--- a/compiler/luci/pass/src/CircleOptimizer.cpp
+++ b/compiler/luci/pass/src/CircleOptimizer.cpp
@@ -16,16 +16,23 @@
#include "luci/CircleOptimizer.h"
+#include "luci/Pass/FuseBCQPass.h"
#include "luci/Pass/FuseInstanceNormPass.h"
+#include "luci/Pass/ResolveCustomOpAddPass.h"
+#include "luci/Pass/ResolveCustomOpBatchMatMulPass.h"
+#include "luci/Pass/ResolveCustomOpMatMulPass.h"
+#include "luci/Pass/QuantizeWithMinMaxPass.h"
+#include "luci/Pass/QuantizeDequantizeWeightsPass.h"
// TODO add more passes
#include "luci/Pass/ShapeInferencePass.h"
#include "luci/Pass/TypeInferencePass.h"
// logo passes
-#include <logo/RemoveDeadNodePass.h>
+#include <logo/RemoveDeadNodeWithQueryPass.h>
#include "ProgressReporter.h"
+#include "CircleOptimizerUtils.h"
#include <logo/Phase.h>
@@ -36,18 +43,39 @@ namespace
using namespace luci;
-class OptimizeOptionsImpl : public luci::CircleOptimizer::Options
+class OptimizeOptionsImpl final : public luci::CircleOptimizer::Options
{
public:
void enable(Algorithm) final;
+ void param(AlgorithmParameters, const std::string &) final;
+ const std::string param(AlgorithmParameters) const final;
bool query(Algorithm) final;
private:
std::vector<Algorithm> _algorithms;
+ std::map<AlgorithmParameters, const std::string> _algorithm_params;
};
void OptimizeOptionsImpl::enable(Algorithm algo) { _algorithms.push_back(algo); }
+void OptimizeOptionsImpl::param(AlgorithmParameters param, const std::string &str)
+{
+ _algorithm_params.insert(std::pair<AlgorithmParameters, const std::string>(param, str));
+}
+
+const std::string OptimizeOptionsImpl::param(AlgorithmParameters param) const
+{
+ auto param_str = _algorithm_params.find(param);
+ if (param_str != _algorithm_params.end())
+ {
+ return param_str->second;
+ }
+ else
+ {
+ return std::string();
+ }
+}
+
bool OptimizeOptionsImpl::query(Algorithm algo)
{
std::vector<Algorithm>::iterator it = std::find(_algorithms.begin(), _algorithms.end(), algo);
@@ -77,14 +105,31 @@ void CircleOptimizer::optimize(loco::Graph *g) const
logo::Phase phase;
/* TRANSFORM DECLARATION BEGIN */
+ if (_options->query(Options::Algorithm::ResolveCustomOpAdd))
+ {
+ phase.emplace_back(std::make_unique<luci::ResolveCustomOpAddPass>());
+ }
+ if (_options->query(Options::Algorithm::ResolveCustomOpBatchMatMul))
+ {
+ phase.emplace_back(std::make_unique<luci::ResolveCustomOpBatchMatMulPass>());
+ }
+ if (_options->query(Options::Algorithm::ResolveCustomOpMatMul))
+ {
+ phase.emplace_back(std::make_unique<luci::ResolveCustomOpMatMulPass>());
+ }
if (_options->query(Options::Algorithm::FuseInstanceNorm))
{
phase.emplace_back(std::make_unique<FuseInstanceNormPass>());
}
+ if (_options->query(Options::Algorithm::FuseBCQ))
+ {
+ phase.emplace_back(std::make_unique<FuseBCQPass>());
+ }
+
// Shape inference is needed for added nodes doing above transformations
phase.emplace_back(std::make_unique<luci::ShapeInferencePass>());
phase.emplace_back(std::make_unique<luci::TypeInferencePass>());
- phase.emplace_back(std::make_unique<logo::RemoveDeadNodePass>());
+ phase.emplace_back(std::make_unique<logo::RemoveDeadNodeWithQueryPass>());
/* TRANSFORM DECLARATION END */
ProgressReporter prog(g, logo::PhaseStrategy::Saturate);
@@ -93,4 +138,74 @@ void CircleOptimizer::optimize(loco::Graph *g) const
phase_runner.run(phase);
}
+void CircleOptimizer::quantize(loco::Graph *g) const
+{
+ // Fake quantization of weights
+ if (_options->query(Options::Algorithm::QuantizeDequantizeWeights))
+ {
+ static const std::vector<std::string> fakeq_supported_input_dtype{"float32"};
+ static const std::vector<std::string> fakeq_supported_output_dtype{"uint8"};
+ static const std::vector<std::string> fakeq_supported_granularity{"layer"};
+
+ auto input_dtype = _options->param(Options::AlgorithmParameters::Quantize_input_dtype);
+ auto output_dtype = _options->param(Options::AlgorithmParameters::Quantize_output_dtype);
+ auto granularity = _options->param(Options::AlgorithmParameters::Quantize_granularity);
+
+ if (!in_array(to_lower_case(input_dtype), fakeq_supported_input_dtype))
+ throw std::runtime_error("Unsupported input type. List of supported input type: " +
+ to_string(fakeq_supported_input_dtype));
+
+ if (!in_array(to_lower_case(output_dtype), fakeq_supported_output_dtype))
+ throw std::runtime_error("Unsupported output type. List of supported output type: " +
+ to_string(fakeq_supported_output_dtype));
+
+ if (!in_array(to_lower_case(granularity), fakeq_supported_granularity))
+ throw std::runtime_error("Unsupported granularity. List of supported granularity: " +
+ to_string(fakeq_supported_granularity));
+
+ luci::QuantizeDequantizeWeightsPass fake_quantizer(
+ str_to_dtype(input_dtype), str_to_dtype(output_dtype), str_to_granularity(granularity));
+ fake_quantizer.run(g);
+ }
+
+ // Actual quantization of weights, bias, and activation
+ if (_options->query(Options::Algorithm::QuantizeWithMinMax))
+ {
+ static const std::vector<std::string> qwmm_supported_input_dtype{"float32"};
+ static const std::vector<std::string> qwmm_supported_output_dtype{"uint8"};
+ static const std::vector<std::string> qwmm_supported_granularity{"layer"};
+
+ auto input_dtype = _options->param(Options::AlgorithmParameters::Quantize_input_dtype);
+ auto output_dtype = _options->param(Options::AlgorithmParameters::Quantize_output_dtype);
+ auto granularity = _options->param(Options::AlgorithmParameters::Quantize_granularity);
+
+ if (!in_array(to_lower_case(input_dtype), qwmm_supported_input_dtype))
+ throw std::runtime_error("Unsupported input type. List of supported input types: " +
+ to_string(qwmm_supported_input_dtype));
+
+ if (!in_array(to_lower_case(output_dtype), qwmm_supported_output_dtype))
+ throw std::runtime_error("Unsupported output type. List of supported output types: " +
+ to_string(qwmm_supported_output_dtype));
+
+ if (!in_array(to_lower_case(granularity), qwmm_supported_granularity))
+ throw std::runtime_error("Unsupported granularity. List of supported granularity: " +
+ to_string(qwmm_supported_granularity));
+
+ luci::QuantizeWithMinMaxPass quantizer(str_to_dtype(input_dtype), str_to_dtype(output_dtype),
+ str_to_granularity(granularity));
+ quantizer.run(g);
+ }
+
+ logo::Phase phase;
+
+ // Do Shape/Type inference
+ phase.emplace_back(std::make_unique<luci::ShapeInferencePass>());
+ phase.emplace_back(std::make_unique<luci::TypeInferencePass>());
+
+ ProgressReporter prog(g, logo::PhaseStrategy::Saturate);
+ logo::PhaseRunner<logo::PhaseStrategy::Saturate> phase_runner{g};
+ phase_runner.attach(&prog);
+ phase_runner.run(phase);
+}
+
} // namespace luci
diff --git a/compiler/luci/pass/src/CircleOptimizerUtils.cpp b/compiler/luci/pass/src/CircleOptimizerUtils.cpp
new file mode 100644
index 000000000..ffc372392
--- /dev/null
+++ b/compiler/luci/pass/src/CircleOptimizerUtils.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CircleOptimizerUtils.h"
+
+namespace luci
+{
+
+bool in_array(const std::string &str, const std::vector<std::string> &array)
+{
+ return std::find(array.begin(), array.end(), str) != array.end();
+}
+
+std::string to_string(const std::vector<std::string> &strings)
+{
+ assert(!strings.empty());
+
+ std::string res;
+ for (unsigned int i = 0; i < strings.size() - 1; i++)
+ res += strings[i] + ", ";
+
+ res += strings[strings.size() - 1];
+ return res;
+}
+
+std::string to_lower_case(std::string s)
+{
+ std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
+ return s;
+}
+
+loco::DataType str_to_dtype(const std::string &str)
+{
+ if (to_lower_case(str).compare("uint8") == 0)
+ return loco::DataType::U8;
+ if (to_lower_case(str).compare("uint16") == 0)
+ return loco::DataType::U16;
+ if (to_lower_case(str).compare("uint32") == 0)
+ return loco::DataType::U32;
+ if (to_lower_case(str).compare("uint64") == 0)
+ return loco::DataType::U64;
+
+ if (to_lower_case(str).compare("int8") == 0)
+ return loco::DataType::S8;
+ if (to_lower_case(str).compare("int16") == 0)
+ return loco::DataType::S16;
+ if (to_lower_case(str).compare("int32") == 0)
+ return loco::DataType::S32;
+ if (to_lower_case(str).compare("int64") == 0)
+ return loco::DataType::S64;
+
+ if (to_lower_case(str).compare("float16") == 0)
+ return loco::DataType::FLOAT16;
+ if (to_lower_case(str).compare("float32") == 0)
+ return loco::DataType::FLOAT32;
+ if (to_lower_case(str).compare("float64") == 0)
+ return loco::DataType::FLOAT64;
+
+ if (to_lower_case(str).compare("bool") == 0)
+ return loco::DataType::BOOL;
+
+ return loco::DataType::Unknown;
+}
+
+QuantizationGranularity str_to_granularity(const std::string &str)
+{
+ if (to_lower_case(str).compare("layer") == 0)
+ return QuantizationGranularity::LayerWise;
+
+ if (to_lower_case(str).compare("channel") == 0)
+ return QuantizationGranularity::ChannelWise;
+
+ throw std::runtime_error("Quantization granularity must be either 'layer' or 'channel'");
+}
+
+} // namespace luci
diff --git a/compiler/luci/pass/src/CircleOptimizerUtils.h b/compiler/luci/pass/src/CircleOptimizerUtils.h
new file mode 100644
index 000000000..7e577a05f
--- /dev/null
+++ b/compiler/luci/pass/src/CircleOptimizerUtils.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_CIRCLE_OPTIMIZER_UTILS_H__
+#define __LUCI_CIRCLE_OPTIMIZER_UTILS_H__
+
+#include "luci/Pass/QuantizeDequantizeWeightsPass.h"
+#include "luci/Pass/QuantizeWithMinMaxPass.h"
+
+#include <loco.h>
+
+#include <algorithm>
+
+namespace luci
+{
+
+bool in_array(const std::string &, const std::vector<std::string> &);
+
+std::string to_string(const std::vector<std::string> &);
+
+std::string to_lower_case(std::string);
+
+loco::DataType str_to_dtype(const std::string &);
+
+QuantizationGranularity str_to_granularity(const std::string &);
+
+} // namespace luci
+
+#endif // __LUCI_CIRCLE_OPTIMIZER_UTILS_H__
diff --git a/compiler/luci/pass/src/FuseBCQPass.cpp b/compiler/luci/pass/src/FuseBCQPass.cpp
new file mode 100644
index 000000000..b81db8827
--- /dev/null
+++ b/compiler/luci/pass/src/FuseBCQPass.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Pass/FuseBCQPass.h"
+
+#include <luci/IR/CircleNodes.h>
+
+#include <cassert>
+#include <string>
+#include <set>
+
+namespace
+{
+
+/**
+ * @brief Circle nodes including BCQ information and a circle node to which BCQ will be applied
+ * are connected with their name. And their names include common prefix.
+ * However, after pb file is converted to tflite file, some nodes' name are changed.
+ * Thus this function will return original common prefix.
+ *
+ * @note All the re-naming rule of TFLite converter is not figured out.
+ * Therefore, if new naming rule is detected, this function should be updated.
+ */
+const std::string node_name_prefix(luci::NodeName node_name)
+{
+ std::string prefix = node_name;
+
+ if (prefix.find("ReadVariableOp/resource/") != std::string::npos)
+ {
+ const auto start_index = prefix.find("ReadVariableOp/resource/");
+
+ const auto left_prefix = prefix.substr(0, start_index);
+ const auto right_prefix = prefix.substr(start_index + 24);
+
+ prefix = left_prefix + right_prefix;
+ }
+
+ if (prefix.find("Tensordot/") != std::string::npos)
+ {
+ const auto index = prefix.find("Tensordot/");
+ prefix = prefix.substr(0, index - 1);
+ }
+ else if (prefix.find("kernel/") != std::string::npos)
+ {
+ const auto index = prefix.find("kernel/");
+ prefix = prefix.substr(0, index - 1);
+ }
+ else if (prefix.find("/bcqinfo_") != std::string::npos)
+ {
+ const auto index = prefix.find("/bcqinfo_");
+ prefix = prefix.substr(0, index);
+ }
+
+ return prefix;
+}
+
+} // namespace
+
+namespace
+{
+
+class BCQConverter final
+{
+public:
+ void add_BCQ_info_node(luci::CircleConst *node)
+ {
+ const auto node_name = node->name();
+ const auto prefix = node_name_prefix(node_name);
+
+ // If bcqinfo_* nodes are held by Reshape operation,
+ // shape of bcqinfo_* nodes are copied to `shape` input of Reshape operation.
+ // Then the name becomes bcqinfo_*_copy_shape.
+ // We should prevent this node not to added to bcq information.
+ if (node_name.find("_copy_shape") != std::string::npos)
+ return;
+
+ if (node_name.find("bcqinfo_do_w_x") != std::string::npos)
+ _do_w_x[prefix] = node;
+ else if (node_name.find("bcqinfo_alpha") != std::string::npos)
+ _alpha[prefix] = node;
+ else if (node_name.find("bcqinfo_packed_binary_code") != std::string::npos)
+ _packed_binary_code[prefix] = node;
+ else if (node_name.find("bcqinfo_number_of_clusters") != std::string::npos)
+ _number_of_clusters[prefix] = node;
+ else if (node_name.find("bcqinfo_size_of_clusters") != std::string::npos)
+ _size_of_clusters[prefix] = node;
+ else if (node_name.find("bcqinfo_qbits_of_clusters") != std::string::npos)
+ _qbits_of_clusters[prefix] = node;
+ else if (node_name.find("bcqinfo_dequant_weight") != std::string::npos)
+ _dequant_weight[prefix] = node;
+ }
+
+ bool has_BCQ_info(luci::CircleConst *node)
+ {
+ const auto prefix = node_name_prefix(node->name());
+ bool has_info = true;
+
+ has_info &= (_do_w_x.find(prefix) != _do_w_x.end());
+ has_info &= (_alpha.find(prefix) != _alpha.end());
+ has_info &= (_packed_binary_code.find(prefix) != _packed_binary_code.end());
+ has_info &= (_number_of_clusters.find(prefix) != _number_of_clusters.end());
+ has_info &= (_size_of_clusters.find(prefix) != _size_of_clusters.end());
+ has_info &= (_qbits_of_clusters.find(prefix) != _qbits_of_clusters.end());
+ // bcqinfo_dequant_weight is just for validation, so not always exists.
+
+ return has_info;
+ }
+
+ bool do_w_x(luci::CircleConst *node)
+ {
+ const auto prefix = node_name_prefix(node->name());
+
+ if (_do_w_x[prefix]->dtype() == loco::DataType::S32)
+ return _do_w_x[prefix]->at<loco::DataType::S32>(0) == 1;
+ else if (_do_w_x[prefix]->dtype() == loco::DataType::BOOL)
+ return _do_w_x[prefix]->at<loco::DataType::BOOL>(0);
+ else
+ throw std::runtime_error("do_w_x should be int or bool");
+ }
+
+ luci::CircleConst *get_alpha(luci::CircleConst *node)
+ {
+ const auto prefix = node_name_prefix(node->name());
+ return _alpha[prefix];
+ }
+
+ luci::CircleConst *get_packed_binary_code(luci::CircleConst *node)
+ {
+ const auto prefix = node_name_prefix(node->name());
+ return _packed_binary_code[prefix];
+ }
+
+ luci::CircleConst *get_number_of_clusters(luci::CircleConst *node)
+ {
+ const auto prefix = node_name_prefix(node->name());
+ return _number_of_clusters[prefix];
+ }
+
+ luci::CircleConst *get_size_of_clusters(luci::CircleConst *node)
+ {
+ const auto prefix = node_name_prefix(node->name());
+ return _size_of_clusters[prefix];
+ }
+
+ luci::CircleConst *get_qbits_of_clusters(luci::CircleConst *node)
+ {
+ const auto prefix = node_name_prefix(node->name());
+ return _qbits_of_clusters[prefix];
+ }
+
+ luci::CircleConst *packed_clusters(luci::CircleConst *node)
+ {
+ auto graph = node->graph();
+ auto qbits_of_clusters = get_qbits_of_clusters(node);
+ auto size_of_clusters = get_size_of_clusters(node);
+ const auto number_of_clusters = get_number_of_clusters(node)->at<loco::DataType::S32>(0);
+
+ auto packed_clusters = graph->nodes()->create<luci::CircleConst>();
+ packed_clusters->dtype(loco::DataType::S32);
+ packed_clusters->size<loco::DataType::S32>(number_of_clusters * 2);
+ packed_clusters->rank(2);
+ packed_clusters->dim(0) = number_of_clusters;
+ packed_clusters->dim(1) = 2;
+ packed_clusters->shape_status(luci::ShapeStatus::VALID);
+
+ for (int i = 0; i < number_of_clusters; ++i)
+ {
+ packed_clusters->at<loco::DataType::S32>(i * 2) =
+ qbits_of_clusters->at<loco::DataType::S32>(i);
+ packed_clusters->at<loco::DataType::S32>(i * 2 + 1) =
+ size_of_clusters->at<loco::DataType::S32>(i);
+ }
+
+ return packed_clusters;
+ }
+
+ /**
+ * @brief Exclude BCQ information nodes which are used for fusing BCQ operations
+ * from graph output by using CircleOutputExclude
+ */
+ void clear_BCQ_nodes()
+ {
+ auto createNoOp = [](luci::CircleNode *circle_node) {
+ auto graph = circle_node->graph();
+ auto noOp = graph->nodes()->create<luci::CircleOutputExclude>();
+
+ if (circle_node->shape_status() == luci::ShapeStatus::VALID)
+ {
+ noOp->dtype(circle_node->dtype());
+ noOp->rank(circle_node->rank());
+ for (uint32_t i = 0; i < circle_node->rank(); ++i)
+ noOp->dim(i) = circle_node->dim(i);
+ }
+ else
+ {
+ // For type inference
+ noOp->dtype(loco::DataType::FLOAT32);
+ }
+
+ return noOp;
+ };
+
+ auto clear_nodes = [createNoOp](std::map<std::string, luci::CircleConst *> &nodes) {
+ for (auto &n : nodes)
+ {
+ auto node = n.second;
+
+ for (auto s : loco::succs(node))
+ {
+ if (auto outnode = dynamic_cast<luci::CircleOutput *>(s))
+ {
+ outnode->from(createNoOp(node));
+ }
+ else if (auto reshape_node = dynamic_cast<luci::CircleReshape *>(s))
+ {
+ for (auto o : loco::succs(reshape_node))
+ {
+ auto circle_output = loco::must_cast<luci::CircleOutput *>(o);
+ circle_output->from(createNoOp(reshape_node));
+ }
+ }
+ }
+ }
+ };
+
+ clear_nodes(_do_w_x);
+ clear_nodes(_alpha);
+ clear_nodes(_packed_binary_code);
+ clear_nodes(_number_of_clusters);
+ clear_nodes(_size_of_clusters);
+ clear_nodes(_qbits_of_clusters);
+ clear_nodes(_dequant_weight);
+ }
+
+private:
+ std::map<std::string, luci::CircleConst *> _do_w_x;
+ std::map<std::string, luci::CircleConst *> _alpha;
+ std::map<std::string, luci::CircleConst *> _packed_binary_code;
+ std::map<std::string, luci::CircleConst *> _number_of_clusters;
+ std::map<std::string, luci::CircleConst *> _size_of_clusters;
+ std::map<std::string, luci::CircleConst *> _qbits_of_clusters;
+ std::map<std::string, luci::CircleConst *> _dequant_weight;
+};
+
+} // namespace
+
+namespace luci
+{
+
+bool FuseBCQPass::run(loco::Graph *g)
+{
+ BCQConverter converter;
+
+ bool changed = false;
+
+ for (auto node : loco::all_nodes(g))
+ {
+ if (auto circle_const = dynamic_cast<luci::CircleConst *>(node))
+ {
+ converter.add_BCQ_info_node(circle_const);
+ }
+ }
+
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ if (auto gather = dynamic_cast<luci::CircleGather *>(node))
+ {
+ auto params = dynamic_cast<luci::CircleConst *>(gather->params());
+ if (params != nullptr && converter.has_BCQ_info(params))
+ {
+ auto bcq_gather = g->nodes()->create<luci::CircleBCQGather>();
+
+ bcq_gather->input_scales(converter.get_alpha(params));
+ bcq_gather->input_binary(converter.get_packed_binary_code(params));
+ bcq_gather->indices(gather->indices());
+ bcq_gather->input_clusters(converter.packed_clusters(params));
+
+ const auto binary_hidden_size =
+ loco::must_cast<luci::CircleConst *>(bcq_gather->input_binary())->dim(1).value() * 32;
+ bcq_gather->input_hidden_size(binary_hidden_size);
+
+ if (converter.do_w_x(params))
+ {
+ bcq_gather->axis(gather->axis());
+ }
+ else
+ {
+ const auto axis_transpose = (gather->axis() == 0) ? 1 : 0;
+ bcq_gather->axis(axis_transpose);
+ }
+
+ loco::replace(gather).with(bcq_gather);
+
+ changed = true;
+ }
+ }
+ else if (auto fully_connected = dynamic_cast<luci::CircleFullyConnected *>(node))
+ {
+ auto weights = dynamic_cast<luci::CircleConst *>(fully_connected->weights());
+ if (weights != nullptr && converter.has_BCQ_info(weights))
+ {
+ auto bcq_fc = g->nodes()->create<luci::CircleBCQFullyConnected>();
+
+ bcq_fc->weights_scales(converter.get_alpha(weights));
+ bcq_fc->weights_binary(converter.get_packed_binary_code(weights));
+ bcq_fc->bias(fully_connected->bias());
+ bcq_fc->weights_clusters(converter.packed_clusters(weights));
+ bcq_fc->fusedActivationFunction(fully_connected->fusedActivationFunction());
+
+ loco::Node *bcq_input = fully_connected->input();
+ int32_t batch_rank = 0;
+
+ // If input of BCQFullyConnected has more than rank 2, we should reshape it as rank 2
+ const auto original_input = loco::must_cast<luci::CircleNode *>(fully_connected->input());
+ if (original_input->shape_status() == ShapeStatus::VALID && original_input->rank() > 2)
+ {
+ auto new_shape = g->nodes()->create<luci::CircleConst>();
+ new_shape->dtype(loco::DataType::S32);
+ new_shape->size<loco::DataType::S32>(2);
+ new_shape->rank(1);
+ new_shape->dim(0) = 2;
+
+ auto batch_size = 1;
+ for (uint32_t i = 0; i < original_input->rank() - 1; ++i)
+ batch_size *= original_input->dim(i).value();
+
+ new_shape->at<loco::DataType::S32>(0) = batch_size;
+ new_shape->at<loco::DataType::S32>(1) =
+ original_input->dim(original_input->rank() - 1).value();
+ new_shape->shape_status(ShapeStatus::VALID);
+
+ auto reshape = g->nodes()->create<luci::CircleReshape>();
+ reshape->tensor(original_input);
+ reshape->shape(new_shape);
+
+ bcq_input = reshape;
+ batch_rank = original_input->rank() - 2;
+ }
+
+ // If x_w formation, we should insert Transpose in front and back of BCQFullyConnected
+ if (converter.do_w_x(weights))
+ {
+ const auto binary_hidden_size =
+ loco::must_cast<luci::CircleNode *>(fully_connected->input())
+ ->dim(batch_rank)
+ .value();
+ bcq_fc->weights_hidden_size(binary_hidden_size);
+ bcq_fc->input(bcq_input);
+ loco::replace(fully_connected).with(bcq_fc);
+ }
+ else
+ {
+ const auto binary_hidden_size =
+ loco::must_cast<luci::CircleNode *>(fully_connected->input())
+ ->dim(1 + batch_rank)
+ .value();
+ bcq_fc->weights_hidden_size(binary_hidden_size);
+
+ auto perm = g->nodes()->create<luci::CircleConst>();
+ perm->dtype(loco::DataType::S32);
+ perm->size<loco::DataType::S32>(2);
+ perm->rank(1);
+ perm->dim(0) = 2;
+ perm->at<loco::DataType::S32>(0) = 1;
+ perm->at<loco::DataType::S32>(1) = 0;
+ perm->shape_status(ShapeStatus::VALID);
+
+ auto input_transpose = g->nodes()->create<luci::CircleTranspose>();
+ input_transpose->a(bcq_input);
+ input_transpose->perm(perm);
+
+ bcq_fc->input(input_transpose);
+
+ auto output_transpose = g->nodes()->create<luci::CircleTranspose>();
+ output_transpose->a(bcq_fc);
+ output_transpose->perm(perm);
+
+ loco::replace(fully_connected).with(output_transpose);
+ }
+
+ changed = true;
+ }
+ }
+ }
+
+ if (changed)
+ converter.clear_BCQ_nodes();
+
+ return changed;
+}
+
+} // namespace luci
diff --git a/compiler/luci/pass/src/FuseInstanceNormPass.cpp b/compiler/luci/pass/src/FuseInstanceNormPass.cpp
index 180b5bbef..ad8765c41 100644
--- a/compiler/luci/pass/src/FuseInstanceNormPass.cpp
+++ b/compiler/luci/pass/src/FuseInstanceNormPass.cpp
@@ -15,6 +15,7 @@
*/
#include "luci/Pass/FuseInstanceNormPass.h"
+#include "FuseInstanceNormPassInternal.h"
#include <luci/IR/CircleNodes.h>
@@ -114,8 +115,6 @@ bool NodeFiller<ARG_TYPE_1, ARG_TYPE_2>::with_commutative_args_of(const COMM_NOD
} // namespace
// Helper to check detail
-namespace
-{
/// @return true When node has shape of '1 x .. x 1 x depth'
bool is_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth)
@@ -130,7 +129,23 @@ bool is_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth)
return node->dim(axis).value() == depth;
}
-bool is_instance_mean(luci::CircleMean *mean)
+/// @return true if node shape consists of ones, except the one before the last dim: 1,...1,depth,1
+bool is_quasi_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth)
+{
+ auto rank = node->rank();
+ // minimal accepted shape is [1 x depth x 1]
+ if (rank < 3)
+ return false;
+ const auto depth_axis = rank - 2;
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ if (axis != depth_axis && node->dim(axis).value() != 1)
+ return false;
+ }
+ return node->dim(depth_axis).value() == depth;
+}
+
+bool is_instance_mean_v0(luci::CircleMean *mean)
{
//
// CHECK 1) input is rank 4
@@ -175,7 +190,53 @@ bool is_instance_mean(luci::CircleMean *mean)
return mean->keep_dims();
}
-} // namespace
+bool is_instance_mean_v1(luci::CircleMean *mean)
+{
+ //
+ // CHECK 1) input is rank 5 (NHWCX)
+ //
+ auto input = mean->input();
+ if (not loco::shape_known(input))
+ return false;
+ auto input_shape = loco::shape_get(input).as<loco::TensorShape>();
+ if (input_shape.rank() != 5)
+ return false;
+
+ //
+ // CHECK 2) 'reduction indices' is CircleConst of value [1,2,4], that is HWX of NHWCX input shape
+ //
+ // TODO Support equivalent case, like [-3,-2]
+ // TODO Support non-Const case?
+ // TODO What if input is NCHW format in Circle?
+ auto red_indices = dynamic_cast<luci::CircleConst *>(mean->reduction_indices());
+ if (not red_indices)
+ return false;
+ if (red_indices->rank() != 1)
+ return false;
+ std::set<int32_t> red_indices_set;
+
+ // TODO Currently only support S32, support other types
+ if (red_indices->dtype() != loco::DataType::S32)
+ return false;
+ for (uint32_t i = 0; i < red_indices->dim(0).value(); ++i)
+ red_indices_set.insert(red_indices->at<loco::DataType::S32>(i));
+
+ if (red_indices_set.size() != 3)
+ return false;
+ if (red_indices_set.find(1) == red_indices_set.end())
+ return false;
+ if (red_indices_set.find(2) == red_indices_set.end())
+ return false;
+ if (red_indices_set.find(4) == red_indices_set.end())
+ return false;
+
+ //
+ // CHECK 3) keep_dims == true (?)
+ //
+ // We only have case of 'keep_dims == true' so far, but it might be okay with 'keep_dims == false'
+ // TODO Check this fact, and if true, return true regardless of keep_dims
+ return mean->keep_dims();
+}
// Helper to fuse Instance Norm
namespace
@@ -227,14 +288,61 @@ namespace
* |
* V
* [Out]
+ *-------------------------------------------------------------------
+ * [In]
+ * |
+ * V
+ * ifm
+ * |
+ * V
+ * +---------reshape_of_ifm ----+ (reduction indicies)
+ * | | | |
+ * | | V V
+ * | | mean_of_reshape -------------+
+ * | V | |
+ * | sqdiff <--+ (reduction indicies) |
+ * | | | |
+ * | V | |
+ * | mean_as_variance <---+ const_as_epsilon |
+ * | | | |
+ * | V | |
+ * | add_as_variance <--------+ |
+ * | | |
+ * | V |
+ * | rsqrt const_as_gamma |
+ * | | | |
+ * | V | |
+ * | mul_gamma <--+ |
+ * | | | |
+ * V V V |
+ * mul_as_scaled_reshape mul_as_scaled_mean <-----------+
+ * | |
+ * | const_as_beta |
+ * | | V
+ * | +------> sub
+ * V |
+ * add_as_terminal <----------+
+ * |
+ * V
+ * reshape_as_terminal
+ * |
+ * V
+ * [Out]
*/
class InstanceNormPattern final
{
public:
- InstanceNormPattern(luci::CircleAdd *candidate)
+ enum PatternVersion
+ {
+ Version_0,
+ Version_1
+ };
+
+ InstanceNormPattern(luci::CircleAdd *candidate, PatternVersion pv)
{
assert(candidate);
add_as_terminal = candidate;
+ _pv = pv;
}
public:
@@ -244,7 +352,9 @@ public:
public:
// Context
loco::Node *ifm = nullptr;
+ luci::CircleReshape *reshape_of_ifm = nullptr;
luci::CircleMean *mean_of_ifm = nullptr;
+ luci::CircleMean *mean_of_reshape = nullptr;
luci::CircleSquaredDifference *sqdiff = nullptr;
luci::CircleMean *mean_as_variance = nullptr;
luci::CircleConst *const_as_epsilon = nullptr;
@@ -254,12 +364,14 @@ public:
luci::CircleMul *mul_gamma = nullptr;
luci::CircleMul *mul_as_scaled_ifm = nullptr;
luci::CircleMul *mul_as_scaled_mean = nullptr;
+ luci::CircleMul *mul_as_scaled_reshape = nullptr;
luci::CircleConst *const_as_beta = nullptr;
luci::CircleSub *sub = nullptr;
luci::CircleAdd *add_as_terminal = nullptr;
private:
bool _matched = false;
+ PatternVersion _pv;
};
bool InstanceNormPattern::matched()
@@ -273,8 +385,18 @@ bool InstanceNormPattern::matched()
// Check order is DFS
- CHECK_OR_FALSE(fill(&mul_as_scaled_ifm, &sub).with_commutative_args_of(add_as_terminal));
- CHECK_OR_FALSE(fill(&ifm, &mul_gamma).with_commutative_args_of(mul_as_scaled_ifm));
+ if (_pv == PatternVersion::Version_0)
+ {
+ CHECK_OR_FALSE(fill(&mul_as_scaled_ifm, &sub).with_commutative_args_of(add_as_terminal));
+ CHECK_OR_FALSE(fill(&ifm, &mul_gamma).with_commutative_args_of(mul_as_scaled_ifm));
+ }
+ if (_pv == PatternVersion::Version_1)
+ {
+ CHECK_OR_FALSE(fill(&mul_as_scaled_reshape, &sub).with_commutative_args_of(add_as_terminal));
+ CHECK_OR_FALSE(
+ fill(&reshape_of_ifm, &mul_gamma).with_commutative_args_of(mul_as_scaled_reshape));
+ ifm = reshape_of_ifm->tensor();
+ }
CHECK_OR_FALSE(loco::shape_known(ifm));
auto ifm_shape = loco::shape_get(ifm);
@@ -284,7 +406,15 @@ bool InstanceNormPattern::matched()
uint32_t ifm_channel_depth = ifm_tensor_shape.dim(3).value();
CHECK_OR_FALSE(fill(&rsqrt, &const_as_gamma).with_commutative_args_of(mul_gamma));
- CHECK_OR_FALSE(is_1D_with_dummy_dim(const_as_gamma, ifm_channel_depth));
+
+ if (_pv == PatternVersion::Version_0)
+ {
+ CHECK_OR_FALSE(is_1D_with_dummy_dim(const_as_gamma, ifm_channel_depth));
+ }
+ if (_pv == PatternVersion::Version_1)
+ {
+ CHECK_OR_FALSE(is_quasi_1D_with_dummy_dim(const_as_gamma, ifm_channel_depth));
+ }
add_as_variance = dynamic_cast<luci::CircleAdd *>(rsqrt->x());
CHECK_OR_FALSE(add_as_variance);
@@ -296,29 +426,69 @@ bool InstanceNormPattern::matched()
// TODO Support regarding broadcast
CHECK_OR_FALSE(const_as_epsilon->size<loco::DataType::FLOAT32>() == 1);
- CHECK_OR_FALSE(is_instance_mean(mean_as_variance));
+ if (_pv == PatternVersion::Version_0)
+ {
+ CHECK_OR_FALSE(is_instance_mean_v0(mean_as_variance));
+ }
+ if (_pv == PatternVersion::Version_1)
+ {
+ CHECK_OR_FALSE(is_instance_mean_v1(mean_as_variance));
+ }
+
sqdiff = dynamic_cast<luci::CircleSquaredDifference *>(mean_as_variance->input());
CHECK_OR_FALSE(sqdiff);
- loco::Node *ifm_should_be = nullptr;
- CHECK_OR_FALSE(fill(&ifm_should_be, &mean_of_ifm).with_commutative_args_of(sqdiff));
- CHECK_OR_FALSE(ifm == ifm_should_be);
- CHECK_OR_FALSE(is_instance_mean(mean_of_ifm));
- CHECK_OR_FALSE(ifm == mean_of_ifm->input());
+ if (_pv == PatternVersion::Version_0)
+ {
+ loco::Node *ifm_should_be = nullptr;
+ CHECK_OR_FALSE(fill(&ifm_should_be, &mean_of_ifm).with_commutative_args_of(sqdiff));
+ CHECK_OR_FALSE(ifm == ifm_should_be);
+ CHECK_OR_FALSE(is_instance_mean_v0(mean_of_ifm));
+ CHECK_OR_FALSE(ifm == mean_of_ifm->input());
+ }
+ if (_pv == PatternVersion::Version_1)
+ {
+ loco::Node *reshape_should_be = nullptr;
+ CHECK_OR_FALSE(fill(&reshape_should_be, &mean_of_reshape).with_commutative_args_of(sqdiff));
+ CHECK_OR_FALSE(reshape_of_ifm == reshape_should_be);
+ CHECK_OR_FALSE(is_instance_mean_v1(mean_of_reshape));
+ CHECK_OR_FALSE(reshape_of_ifm == mean_of_reshape->input());
+ }
const_as_beta = dynamic_cast<luci::CircleConst *>(sub->x());
CHECK_OR_FALSE(const_as_beta);
- CHECK_OR_FALSE(is_1D_with_dummy_dim(const_as_beta, ifm_channel_depth));
+
+ if (_pv == PatternVersion::Version_0)
+ {
+ CHECK_OR_FALSE(is_1D_with_dummy_dim(const_as_beta, ifm_channel_depth));
+ }
+ if (_pv == PatternVersion::Version_1)
+ {
+ CHECK_OR_FALSE(is_quasi_1D_with_dummy_dim(const_as_beta, ifm_channel_depth));
+ }
mul_as_scaled_mean = dynamic_cast<luci::CircleMul *>(sub->y());
CHECK_OR_FALSE(mul_as_scaled_mean);
luci::CircleMul *mul_gamma_should_be = nullptr;
luci::CircleMean *mean_of_ifm_should_be = nullptr;
- CHECK_OR_FALSE(fill(&mul_gamma_should_be, &mean_of_ifm_should_be)
- .with_commutative_args_of(mul_as_scaled_mean));
- CHECK_OR_FALSE(mul_gamma == mul_gamma_should_be);
- CHECK_OR_FALSE(mean_of_ifm == mean_of_ifm_should_be);
+ luci::CircleMean *mean_of_reshape_should_be = nullptr;
+
+ if (_pv == PatternVersion::Version_0)
+ {
+ CHECK_OR_FALSE(fill(&mul_gamma_should_be, &mean_of_ifm_should_be)
+ .with_commutative_args_of(mul_as_scaled_mean));
+ CHECK_OR_FALSE(mul_gamma == mul_gamma_should_be);
+ CHECK_OR_FALSE(mean_of_ifm == mean_of_ifm_should_be);
+ }
+ if (_pv == PatternVersion::Version_1)
+ {
+ CHECK_OR_FALSE(fill(&mul_gamma_should_be, &mean_of_reshape_should_be)
+ .with_commutative_args_of(mul_as_scaled_mean));
+ CHECK_OR_FALSE(mul_gamma == mul_gamma_should_be);
+ CHECK_OR_FALSE(mean_of_reshape == mean_of_reshape_should_be);
+ }
+
#undef CHECK_OR_FALSE
_matched = true;
return true;
@@ -381,13 +551,28 @@ namespace luci
bool FuseInstanceNormPass::run(loco::Graph *g)
{
bool changed = false;
+ luci::CircleAdd *add;
+ InstanceNormPattern::PatternVersion pv;
+
for (auto node : loco::active_nodes(loco::output_nodes(g)))
{
- auto add = dynamic_cast<luci::CircleAdd *>(node);
- if (not add)
- continue;
+ auto reshape = dynamic_cast<luci::CircleReshape *>(node);
+ if (not reshape)
+ {
+ add = dynamic_cast<luci::CircleAdd *>(node);
+ if (not add)
+ continue;
+ pv = InstanceNormPattern::PatternVersion::Version_0;
+ }
+ else
+ {
+ add = dynamic_cast<luci::CircleAdd *>(reshape->tensor());
+ if (not add)
+ continue;
+ pv = InstanceNormPattern::PatternVersion::Version_1;
+ }
- InstanceNormPattern pattern(add);
+ InstanceNormPattern pattern(add, pv);
if (not pattern.matched())
continue;
diff --git a/compiler/luci/pass/src/FuseInstanceNormPass.test.cpp b/compiler/luci/pass/src/FuseInstanceNormPass.test.cpp
new file mode 100644
index 000000000..3037f3def
--- /dev/null
+++ b/compiler/luci/pass/src/FuseInstanceNormPass.test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FuseInstanceNormPassInternal.h"
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+void setShape(luci::CircleNode &node, const std::vector<int> &v)
+{
+ node.rank(v.size());
+ for (int i = 0; i < v.size(); ++i)
+ {
+ node.dim(i) = v[i];
+ }
+}
+
+} // namespace
+
+TEST(FuseInstanceNormPass, is_quasi_1D_with_dummy_dim)
+{
+ luci::CircleConst const_node;
+
+ setShape(const_node, {});
+ EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8));
+
+ setShape(const_node, {1});
+ EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8));
+
+ setShape(const_node, {8});
+ EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8));
+
+ setShape(const_node, {1, 2, 1, 8, 1});
+ EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8));
+
+ setShape(const_node, {8, 3});
+ EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8));
+
+ setShape(const_node, {8, 1});
+ EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8));
+
+ setShape(const_node, {1, 8, 1});
+ EXPECT_TRUE(is_quasi_1D_with_dummy_dim(&const_node, 8));
+
+ setShape(const_node, {1, 1, 1, 8, 1});
+ EXPECT_TRUE(is_quasi_1D_with_dummy_dim(&const_node, 8));
+}
diff --git a/compiler/luci/pass/src/FuseInstanceNormPassInternal.h b/compiler/luci/pass/src/FuseInstanceNormPassInternal.h
new file mode 100644
index 000000000..32b638ba5
--- /dev/null
+++ b/compiler/luci/pass/src/FuseInstanceNormPassInternal.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_CIRCLE_FUSE_INSTANCE_NORM_PASS_INTERNAL_H__
+#define __LUCI_CIRCLE_FUSE_INSTANCE_NORM_PASS_INTERNAL_H__
+
+#include <luci/IR/CircleNodes.h>
+
+/// @return true When node has shape of '1 x .. x 1 x depth'
+bool is_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth);
+
+/// @return true When node has shape of '1 x .. x depth x 1'
+bool is_quasi_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth);
+
+#endif // __LUCI_CIRCLE_FUSE_INSTANCE_NORM_PASS_INTERNAL_H__
diff --git a/compiler/luci/pass/src/QuantizationUtils.cpp b/compiler/luci/pass/src/QuantizationUtils.cpp
new file mode 100644
index 000000000..6726ce746
--- /dev/null
+++ b/compiler/luci/pass/src/QuantizationUtils.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QuantizationUtils.h"
+
+#include <luci/Log.h>
+
+#include <iostream>
+#include <cmath>
+
+namespace luci
+{
+
+void compute_sym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp,
+ float &nudged_min, float &nudged_max)
+{
+ assert(min != max);
+
+ const int32_t kMaxScale = std::numeric_limits<int16_t>::max();
+ const int32_t kMinScale = -kMaxScale;
+ const double qmin_double = kMinScale;
+ const double qmax_double = kMaxScale;
+ const double rmin = std::fmin(0, min);
+ const double rmax = std::fmax(0, max);
+ double scale_factor_from_min_side{0};
+ double scale_factor_from_max_side{0};
+
+ if ((qmin_double * rmin) > 0)
+ scale_factor_from_min_side = rmin / qmin_double;
+
+ if ((qmax_double * rmax) > 0)
+ scale_factor_from_max_side = rmax / qmax_double;
+
+ scaling_factor = scale_factor_from_min_side > scale_factor_from_max_side
+ ? scale_factor_from_min_side
+ : scale_factor_from_max_side;
+ zp = 0;
+ nudged_min = static_cast<float>(qmin_double * scaling_factor);
+ nudged_max = static_cast<float>(qmax_double * scaling_factor);
+}
+
+void compute_asym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp,
+ float &nudged_min, float &nudged_max)
+{
+ LOGGER(l);
+
+ assert(min <= max);
+ const int32_t kMinScale = 0;
+ const int32_t kMaxScale = 255;
+ const double qmin_double = kMinScale;
+ const double qmax_double = kMaxScale;
+ const double rmin = std::fmin(0, min);
+ const double rmax = std::fmax(0, max);
+
+ double scale = (rmax - rmin) / (qmax_double - qmin_double);
+ double zero_point_double = 0;
+ uint8_t nudged_zero_point = 0;
+ if (scale == 0)
+ {
+ WARN(l) << "The minimum and maximum values are the same." << std::endl;
+ if (min >= 0 && max >= 0)
+ zero_point_double = kMinScale;
+ else
+ zero_point_double = kMaxScale;
+ }
+ else
+ zero_point_double = qmin_double - rmin / scale;
+ if (zero_point_double <= qmin_double)
+ {
+ assert(min >= 0 && max >= 0);
+ nudged_zero_point = kMinScale;
+ scale = max / (qmax_double - qmin_double);
+ if (min > 0 && max > 0)
+ WARN(l) << "The minimum and maximum values are all positive." << std::endl;
+ }
+ else if (zero_point_double >= qmax_double)
+ {
+ assert(min < 0 && max < 0);
+ nudged_zero_point = kMaxScale;
+ scale = -min / (qmax_double - qmin_double);
+ WARN(l) << "The minimum and maximum values are all negative." << std::endl;
+ }
+ else
+ {
+ assert(min < 0 && max >= 0);
+ nudged_zero_point = static_cast<uint8_t>(std::round(zero_point_double));
+ }
+
+ nudged_min = static_cast<float>((qmin_double - nudged_zero_point) * scale);
+ nudged_max = static_cast<float>((qmax_double - nudged_zero_point) * scale);
+
+ scaling_factor = scale;
+ zp = nudged_zero_point;
+}
+
+bool get_channel_dim_index(CircleConst *node, loco::TensorShape &dimension, int &channel_dim_index)
+{
+ auto succs = loco::succs(node);
+ if (succs.size() != 1) // assume weights is used by only one node
+ return false;
+
+ for (auto out : succs)
+ {
+ auto conv = dynamic_cast<CircleConv2D *>(out);
+ auto dw_conv = dynamic_cast<CircleDepthwiseConv2D *>(out);
+ auto tw_conv = dynamic_cast<CircleTransposeConv *>(out);
+ auto fc = dynamic_cast<CircleFullyConnected *>(out);
+
+ // Refer to https://github.com/Samsung/ONE/pull/2448.
+ if ((conv != nullptr && conv->filter() == node) ||
+ (tw_conv != nullptr && tw_conv->filter() == node)) // OHWI
+ {
+ assert(node->rank() == 4);
+ dimension.dim(0).set(node->dim(0).value());
+ dimension.dim(1).set(node->dim(1).value());
+ dimension.dim(2).set(node->dim(2).value());
+ dimension.dim(3).set(node->dim(3).value());
+ channel_dim_index = 0; // Set channel_dim_index based on "O"
+ return true;
+ }
+ else if (dw_conv != nullptr && dw_conv->filter() == node) // IHWC
+ {
+ assert(node->rank() == 4);
+ dimension.dim(0).set(node->dim(0).value());
+ dimension.dim(1).set(node->dim(1).value());
+ dimension.dim(2).set(node->dim(2).value());
+ dimension.dim(3).set(node->dim(3).value());
+ channel_dim_index = 3; // Set channel_dim_index based on "C"
+ return true;
+ }
+ else if (fc != nullptr && fc->weights() == node) // OI
+ {
+ assert(node->rank() == 2);
+ dimension.dim(0).set(node->dim(0).value());
+ dimension.dim(1).set(1); // Set FC layer like CONV
+ dimension.dim(2).set(1);
+ dimension.dim(3).set(node->dim(1).value());
+ channel_dim_index = 0; // Set channel_dim_index based on "O"
+ return true;
+ }
+ else
+ {
+ // node does not support channle-wise quantization
+ assert(false);
+ }
+ }
+
+ return false;
+}
+
+uint32_t cal_offset(loco::TensorShape &dimension, uint32_t *indices)
+{
+ return indices[0] * dimension.dim(1).value() * dimension.dim(2).value() *
+ dimension.dim(3).value() +
+ indices[1] * dimension.dim(2).value() * dimension.dim(3).value() +
+ indices[2] * dimension.dim(3).value() + indices[3];
+}
+
+} // namespace luci
diff --git a/compiler/luci/pass/src/QuantizationUtils.h b/compiler/luci/pass/src/QuantizationUtils.h
new file mode 100644
index 000000000..ec0e86df8
--- /dev/null
+++ b/compiler/luci/pass/src/QuantizationUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LUCI_QUANTIZATION_UTILS_H__
+#define __LUCI_QUANTIZATION_UTILS_H__
+
+#include <luci/IR/CircleNodes.h>
+#include <loco/IR/TensorShape.h>
+
+namespace luci
+{
+
+void compute_sym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp,
+ float &nudged_min, float &nudged_max);
+
+void compute_asym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp,
+ float &nudged_min, float &nudged_max);
+
+bool get_channel_dim_index(CircleConst *node, loco::TensorShape &dimension, int &channel_dim_index);
+
+uint32_t cal_offset(loco::TensorShape &dimension, uint32_t *indices);
+
+} // namespace luci
+
+#endif // __LUCI_QUANTIZATION_UTILS_H__
diff --git a/compiler/luci/pass/src/QuantizeDequantizeWeightsPass.cpp b/compiler/luci/pass/src/QuantizeDequantizeWeightsPass.cpp
new file mode 100644
index 000000000..c492234c7
--- /dev/null
+++ b/compiler/luci/pass/src/QuantizeDequantizeWeightsPass.cpp
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2019 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 "luci/Pass/QuantizeDequantizeWeightsPass.h"
+#include "QuantizationUtils.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/IR/CircleNodeVisitor.h>
+#include <luci/Log.h>
+#include <loco/IR/TensorShape.h>
+
+#include <iostream>
+#include <cmath>
+
+namespace luci
+{
+
+namespace
+{
+
+void cal_minmax_per_channel(CircleConst *node, std::vector<float> &min, std::vector<float> &max)
+{
+ loco::TensorShape dimension;
+ dimension.rank(4);
+ uint32_t indices[4] = {
+ 0,
+ };
+ int channel_dim_index{0};
+ int size{0};
+
+ if (!get_channel_dim_index(node, dimension, channel_dim_index))
+ {
+ assert(false);
+ return;
+ }
+ size = dimension.dim(channel_dim_index).value();
+
+ std::vector<bool> has_min_max_value(size, false);
+ min.resize(size);
+ max.resize(size);
+ for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++)
+ {
+ for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++)
+ {
+ for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++)
+ {
+ for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++)
+ {
+ int channel_idx = indices[channel_dim_index];
+ auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices));
+ if (has_min_max_value[channel_idx])
+ {
+ min[channel_idx] = data < min[channel_idx] ? data : min[channel_idx];
+ max[channel_idx] = data > max[channel_idx] ? data : max[channel_idx];
+ }
+ else
+ {
+ min[channel_idx] = data;
+ max[channel_idx] = data;
+ has_min_max_value[channel_idx] = true;
+ }
+ }
+ }
+ }
+ }
+}
+
+void sym_wquant_per_channel(CircleConst *node, std::vector<float> &min, std::vector<float> &max,
+ std::vector<float> &scaling_factor, std::vector<int64_t> &zp,
+ std::vector<float> &nudged_min, std::vector<float> &nudged_max)
+{
+ assert(node->dtype() == loco::DataType::FLOAT32);
+ const int32_t kMaxScale = std::numeric_limits<int16_t>::max();
+ const int32_t kMinScale = -kMaxScale;
+
+ uint32_t size = node->size<loco::DataType::FLOAT32>();
+ std::vector<int32_t> quantized_values(size);
+
+ for (size_t i = 0; i < min.size(); ++i)
+ {
+ compute_sym_scale_zp(min[i], max[i], scaling_factor[i], zp[i], nudged_min[i], nudged_max[i]);
+ }
+
+ loco::TensorShape dimension;
+ dimension.rank(4);
+ uint32_t indices[4] = {
+ 0,
+ };
+ int channel_dim_index{0};
+
+ if (!get_channel_dim_index(node, dimension, channel_dim_index))
+ {
+ assert(false);
+ return;
+ }
+
+ for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++)
+ {
+ for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++)
+ {
+ for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++)
+ {
+ for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++)
+ {
+ int channel_idx = indices[channel_dim_index];
+ const float scaling_factor_inv = 1.0 / scaling_factor[channel_idx];
+ auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices));
+ data = data < nudged_min[channel_idx] ? nudged_min[channel_idx] : data;
+ data = data > nudged_max[channel_idx] ? nudged_max[channel_idx] : data;
+ quantized_values[cal_offset(dimension, indices)] =
+ static_cast<int32_t>(std::round(data * scaling_factor_inv));
+ }
+ }
+ }
+ }
+
+ node->dtype(loco::DataType::S16); // change the type of tensor
+ node->size<loco::DataType::S16>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::S16>(i) =
+ std::min(kMaxScale, std::max(kMinScale, quantized_values[i]));
+ }
+}
+
+void sym_wdequant_per_channel(CircleConst *node, std::vector<float> &scaling_factor)
+{
+ assert(node->dtype() == loco::DataType::S16);
+ uint32_t size = node->size<loco::DataType::S16>();
+ std::vector<float> dequantized_values(size);
+
+ loco::TensorShape dimension;
+ dimension.rank(4);
+ uint32_t indices[4] = {
+ 0,
+ };
+ int channel_dim_index{0};
+
+ if (!get_channel_dim_index(node, dimension, channel_dim_index))
+ {
+ assert(false);
+ return;
+ }
+
+ for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++)
+ {
+ for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++)
+ {
+ for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++)
+ {
+ for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++)
+ {
+ int channel_idx = indices[channel_dim_index];
+ auto data = node->at<loco::DataType::S16>(cal_offset(dimension, indices));
+ dequantized_values[cal_offset(dimension, indices)] =
+ static_cast<float>(data) * scaling_factor[channel_idx];
+ }
+ }
+ }
+ }
+
+ node->dtype(loco::DataType::FLOAT32); // change the type of tensor
+ node->size<loco::DataType::FLOAT32>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::FLOAT32>(i) = dequantized_values[i];
+ }
+}
+
+void asymmetric_wquant_per_channel(CircleConst *node, std::vector<float> &min,
+ std::vector<float> &max, std::vector<float> &scaling_factor,
+ std::vector<int64_t> &zp, std::vector<float> &nudged_min,
+ std::vector<float> &nudged_max)
+{
+ assert(node->dtype() == loco::DataType::FLOAT32);
+
+ const int32_t kMinScale = 0;
+ const int32_t kMaxScale = 255;
+
+ uint32_t size = node->size<loco::DataType::FLOAT32>();
+ std::vector<int32_t> quantized_values(size);
+
+ for (size_t i = 0; i < min.size(); ++i)
+ {
+ compute_asym_scale_zp(min[i], max[i], scaling_factor[i], zp[i], nudged_min[i], nudged_max[i]);
+ }
+
+ loco::TensorShape dimension;
+ dimension.rank(4);
+ uint32_t indices[4] = {
+ 0,
+ };
+ int channel_dim_index{0};
+
+ if (!get_channel_dim_index(node, dimension, channel_dim_index))
+ {
+ assert(false);
+ return;
+ }
+
+ for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++)
+ {
+ for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++)
+ {
+ for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++)
+ {
+ for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++)
+ {
+ int channel_idx = indices[channel_dim_index];
+ const float scaling_factor_inv = 1.0 / scaling_factor[channel_idx];
+ auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices));
+ data = data < nudged_min[channel_idx] ? nudged_min[channel_idx] : data;
+ data = data > nudged_max[channel_idx] ? nudged_max[channel_idx] : data;
+ quantized_values[cal_offset(dimension, indices)] = static_cast<int32_t>(
+ std::round((data - nudged_min[channel_idx]) * scaling_factor_inv));
+ }
+ }
+ }
+ }
+
+ node->dtype(loco::DataType::U8); // change the type of tensor
+ node->size<loco::DataType::U8>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::U8>(i) = std::min(kMaxScale, std::max(kMinScale, quantized_values[i]));
+ }
+}
+
+void asymmetric_wdequant_per_channel(CircleConst *node, std::vector<float> &scaling_factor,
+ std::vector<float> &nudged_min)
+{
+ assert(node->dtype() == loco::DataType::U8);
+ uint32_t size = node->size<loco::DataType::U8>();
+ std::vector<float> dequantized_values(size);
+
+ loco::TensorShape dimension;
+ dimension.rank(4);
+ uint32_t indices[4] = {
+ 0,
+ };
+ int channel_dim_index{0};
+
+ if (!get_channel_dim_index(node, dimension, channel_dim_index))
+ {
+ assert(false);
+ return;
+ }
+
+ for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++)
+ {
+ for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++)
+ {
+ for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++)
+ {
+ for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++)
+ {
+ int channel_idx = indices[channel_dim_index];
+ auto data = node->at<loco::DataType::U8>(cal_offset(dimension, indices));
+ dequantized_values[cal_offset(dimension, indices)] =
+ static_cast<float>(data) * scaling_factor[channel_idx] + nudged_min[channel_idx];
+ }
+ }
+ }
+ }
+
+ node->dtype(loco::DataType::FLOAT32); // change the type of tensor
+ node->size<loco::DataType::FLOAT32>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::FLOAT32>(i) = dequantized_values[i];
+ }
+}
+
+void asymmetric_wquant_with_minmax_per_layer(CircleConst *node, float min, float max,
+ float &scaling_factor, int64_t &zp, float &nudged_min,
+ float &nudged_max)
+{
+
+ const int32_t kMinScale = 0;
+ const int32_t kMaxScale = 255;
+
+ uint32_t size = node->size<loco::DataType::FLOAT32>();
+ compute_asym_scale_zp(min, max, scaling_factor, zp, nudged_min, nudged_max);
+ const float scaling_factor_inv = 1.0 / scaling_factor;
+ std::vector<int32_t> quantized_values(size);
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ // clipping
+ auto data = node->at<loco::DataType::FLOAT32>(i);
+ data = data < nudged_min ? nudged_min : data;
+ data = data > nudged_max ? nudged_max : data;
+ quantized_values[i] =
+ static_cast<int32_t>(std::round((data - nudged_min) * scaling_factor_inv));
+ }
+
+ node->dtype(loco::DataType::U8); // change the type of tensor
+ node->size<loco::DataType::U8>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::U8>(i) = std::min(kMaxScale, std::max(kMinScale, quantized_values[i]));
+ }
+}
+
+void asymmetric_wdequant_with_minmax_per_layer(CircleConst *node, float scaling_factor,
+ float nudged_min)
+{
+ uint32_t size = node->size<loco::DataType::U8>();
+ std::vector<float> dequantized_values(size);
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ auto data = node->at<loco::DataType::U8>(i);
+ dequantized_values[i] = static_cast<float>(data) * scaling_factor + nudged_min;
+ }
+
+ node->dtype(loco::DataType::FLOAT32); // change the type of tensor
+ node->size<loco::DataType::FLOAT32>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::FLOAT32>(i) = dequantized_values[i];
+ }
+}
+
+bool is_quantized(const CircleNode *node)
+{
+ return node->dtype() == loco::DataType::U8 || // activation, weight
+ node->dtype() == loco::DataType::S16 || // activation, weight
+ node->dtype() == loco::DataType::S32; // bias
+}
+
+// Check if node is weights of conv2d, transepose_conv2d, depthwise_conv2d, or fully_connected layer
+bool is_weights(CircleNode *node)
+{
+ auto circle_const = dynamic_cast<CircleConst *>(node);
+ if (circle_const == nullptr)
+ return false;
+
+ auto succs = loco::succs(node);
+ if (succs.size() != 1) // assume weights is used by only one node
+ return false;
+
+ for (auto out : succs)
+ {
+ auto conv = dynamic_cast<CircleConv2D *>(out);
+ if (conv != nullptr && conv->filter() == circle_const && circle_const->rank() == 4)
+ return true;
+
+ auto dw_conv = dynamic_cast<CircleDepthwiseConv2D *>(out);
+ if (dw_conv != nullptr && dw_conv->filter() == circle_const && circle_const->rank() == 4)
+ return true;
+
+ auto tw_conv = dynamic_cast<CircleTransposeConv *>(out);
+ if (tw_conv != nullptr && tw_conv->filter() == circle_const && circle_const->rank() == 4)
+ return true;
+
+ auto fc = dynamic_cast<CircleFullyConnected *>(out);
+ if (fc != nullptr && fc->weights() == circle_const && circle_const->rank() == 2)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * @brief QuantizeDequantizeWeights quantizes and dequantizes tensors for weights
+ * @details Find min/max values on the fly, quantize the model, and dequantize the model
+ */
+struct QuantizeDequantizeWeights final : public luci::CircleNodeMutableVisitor<bool>
+{
+ QuantizeDequantizeWeights(loco::DataType input, loco::DataType output,
+ QuantizationGranularity granularity)
+ : input_type(input), output_type(output), granularity(granularity)
+ {
+ }
+
+ loco::DataType input_type;
+ loco::DataType output_type;
+ QuantizationGranularity granularity;
+
+ // Quantize and dequantize input tensors of each node
+ bool visit(luci::CircleNode *node)
+ {
+ assert(output_type == loco::DataType::U8 || output_type == loco::DataType::S16);
+ LOGGER(l);
+ INFO(l) << "QuantizeDequantizeWeights visit node: " << node->name() << std::endl;
+ auto arity = node->arity();
+ for (uint32_t i = 0; i < arity; i++)
+ {
+ auto input_node = node->arg(i);
+ auto circle_node = loco::must_cast<luci::CircleNode *>(input_node);
+
+ // Check if this is already quantized
+ if (is_quantized(circle_node))
+ continue;
+
+ if (is_weights(circle_node))
+ {
+ auto circle_const = loco::must_cast<luci::CircleConst *>(circle_node);
+
+ // Find min/max per channel-wise
+ if (granularity == QuantizationGranularity::ChannelWise)
+ {
+ std::vector<float> min;
+ std::vector<float> max;
+
+ cal_minmax_per_channel(circle_const, min, max);
+
+ std::vector<float> nudged_min(min.size());
+ std::vector<float> nudged_max(min.size());
+ std::vector<float> scaling_factor(min.size());
+ std::vector<int64_t> zp(min.size());
+
+ if (output_type == loco::DataType::U8)
+ {
+ asymmetric_wquant_per_channel(circle_const, min, max, scaling_factor, zp, nudged_min,
+ nudged_max);
+ asymmetric_wdequant_per_channel(circle_const, scaling_factor, nudged_min);
+ }
+ else
+ {
+ sym_wquant_per_channel(circle_const, min, max, scaling_factor, zp, nudged_min,
+ nudged_max);
+ sym_wdequant_per_channel(circle_const, scaling_factor);
+ }
+
+ auto quantparam = std::make_unique<CircleQuantParam>();
+ quantparam->min = nudged_min;
+ quantparam->max = nudged_max;
+ quantparam->scale = scaling_factor;
+ quantparam->zerop = zp;
+ circle_node->quantparam(std::move(quantparam));
+ }
+ // Find min/max per layer-wise
+ else
+ {
+ float min = std::numeric_limits<float>::max();
+ float max = std::numeric_limits<float>::lowest();
+ for (uint32_t i = 0; i < circle_const->size<loco::DataType::FLOAT32>(); i++)
+ {
+ auto data = circle_const->at<loco::DataType::FLOAT32>(i);
+ min = data < min ? data : min;
+ max = data > max ? data : max;
+ }
+ float scaling_factor{0};
+ int64_t zp{0};
+ float nudged_min{0};
+ float nudged_max{0};
+
+ asymmetric_wquant_with_minmax_per_layer(circle_const, min, max, scaling_factor, zp,
+ nudged_min, nudged_max);
+ asymmetric_wdequant_with_minmax_per_layer(circle_const, scaling_factor, nudged_min);
+ auto quantparam = std::make_unique<CircleQuantParam>();
+ quantparam->min.push_back(nudged_min);
+ quantparam->max.push_back(nudged_max);
+ quantparam->scale.push_back(scaling_factor);
+ quantparam->zerop.push_back(zp);
+ circle_node->quantparam(std::move(quantparam));
+ }
+ }
+ }
+ return false;
+ }
+};
+
+} // namespace
+
+bool QuantizeDequantizeWeightsPass::run(loco::Graph *g)
+{
+ LOGGER(l);
+ INFO(l) << "QuantizeDequantizeWeightsPass Start" << std::endl;
+
+ // Quantize weights
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ QuantizeDequantizeWeights qw(_input_dtype, _output_dtype, _granularity);
+ auto circle_node = loco::must_cast<luci::CircleNode *>(node);
+ circle_node->accept(&qw);
+ }
+
+ INFO(l) << "QuantizeDequantizeWeightsPass End" << std::endl;
+ return false; // one time run
+}
+
+} // namespace luci
diff --git a/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp b/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp
new file mode 100644
index 000000000..f8abee751
--- /dev/null
+++ b/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2019 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 "luci/Pass/QuantizeWithMinMaxPass.h"
+#include "QuantizationUtils.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/IR/CircleNodeVisitor.h>
+#include <luci/Log.h>
+
+#include <oops/UserExn.h>
+
+#include <iostream>
+#include <cmath>
+
+namespace luci
+{
+
+namespace
+{
+
+// Check if the node is the bias of Conv2D, DepthwiseConv2D, or FullyConnected layer
+// If true, return <input, weight> pair of the successor node (used to quantize bias)
+// If flase, return <nullptr, nullptr>
+std::pair<loco::Node *, loco::Node *> get_input_weight_of_bias(CircleNode *node)
+{
+ auto circle_const = dynamic_cast<CircleConst *>(node);
+ if (circle_const == nullptr)
+ return std::make_pair(nullptr, nullptr);
+
+ auto succs = loco::succs(node);
+ if (succs.size() != 1) // assume bias is used by only one node
+ return std::make_pair(nullptr, nullptr);
+
+ for (auto out : succs)
+ {
+ auto conv = dynamic_cast<CircleConv2D *>(out);
+ if (conv != nullptr && conv->bias() == circle_const)
+ {
+ assert(conv->input() != nullptr);
+ assert(conv->filter() != nullptr);
+ return std::make_pair(conv->input(), conv->filter());
+ }
+ auto dw_conv = dynamic_cast<CircleDepthwiseConv2D *>(out);
+ if (dw_conv != nullptr && dw_conv->bias() == circle_const)
+ {
+ assert(dw_conv->input() != nullptr);
+ assert(dw_conv->filter() != nullptr);
+ return std::make_pair(dw_conv->input(), dw_conv->filter());
+ }
+ auto fc = dynamic_cast<CircleFullyConnected *>(out);
+ if (fc != nullptr && fc->bias() == circle_const)
+ {
+ assert(fc->input() != nullptr);
+ assert(fc->weights() != nullptr);
+ return std::make_pair(fc->input(), fc->weights());
+ }
+ }
+ return std::make_pair(nullptr, nullptr);
+}
+
+void asym_quant_bias_per_layer(CircleConst *node, float input_scale, float weight_scale,
+ float *scaling_factor, int64_t *zp)
+{
+ float scale = input_scale * weight_scale;
+ const float scaling_factor_inv = (scale == 0) ? 0 : 1.0 / scale;
+
+ uint32_t size = node->size<loco::DataType::FLOAT32>();
+ std::vector<int32_t> quantized_values(size);
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ quantized_values[i] =
+ static_cast<int32_t>(std::round(node->at<loco::DataType::FLOAT32>(i) * scaling_factor_inv));
+ }
+
+ node->dtype(loco::DataType::S32); // change the type of tensor
+ node->size<loco::DataType::S32>(size); // resize tensor
+ const int32_t kMinScale = std::numeric_limits<int32_t>::lowest();
+ const int32_t kMaxScale = std::numeric_limits<int32_t>::max();
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::S32>(i) =
+ std::min(kMaxScale, std::max(kMinScale, quantized_values[i]));
+ }
+ *scaling_factor = scale;
+ *zp = 0;
+}
+
+void quant_bias_per_channel(CircleConst *node, float input_scale, std::vector<float> &weight_scale,
+ std::vector<float> &scaling_factor, std::vector<int64_t> &zp)
+{
+ float scaling_factor_inv{0};
+
+ uint32_t size = node->size<loco::DataType::FLOAT32>();
+ std::vector<int32_t> quantized_values(size);
+
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ scaling_factor[i] = input_scale * weight_scale[i];
+ scaling_factor_inv = (scaling_factor[i] == 0) ? 0 : 1.0 / scaling_factor[i];
+ quantized_values[i] =
+ static_cast<int32_t>(std::round(node->at<loco::DataType::FLOAT32>(i) * scaling_factor_inv));
+ zp[i] = 0;
+ }
+
+ node->dtype(loco::DataType::S32); // change the type of tensor
+ node->size<loco::DataType::S32>(size); // resize tensor
+ const int32_t kMinScale = std::numeric_limits<int32_t>::lowest();
+ const int32_t kMaxScale = std::numeric_limits<int32_t>::max();
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::S32>(i) =
+ std::min(kMaxScale, std::max(kMinScale, quantized_values[i]));
+ }
+}
+
+bool has_min_max(const CircleNode *node)
+{
+ return node->quantparam() && !node->quantparam()->min.empty() && !node->quantparam()->max.empty();
+}
+
+bool is_quantized(const CircleNode *node)
+{
+ return node->dtype() == loco::DataType::U8 || // activation, weight
+ node->dtype() == loco::DataType::S32; // bias
+}
+
+void sym_wquant_per_channel(CircleConst *node, std::vector<float> &scaling_factor)
+{
+ assert(node->dtype() == loco::DataType::FLOAT32);
+
+ const int32_t kMaxScale = std::numeric_limits<int16_t>::max();
+ const int32_t kMinScale = -kMaxScale;
+
+ uint32_t size = node->size<loco::DataType::FLOAT32>();
+ std::vector<int32_t> quantized_values(size);
+
+ loco::TensorShape dimension;
+ dimension.rank(4);
+ uint32_t indices[4] = {
+ 0,
+ };
+ int channel_dim_index{0};
+
+ if (!get_channel_dim_index(node, dimension, channel_dim_index))
+ {
+ assert(false);
+ return;
+ }
+
+ for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++)
+ {
+ for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++)
+ {
+ for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++)
+ {
+ for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++)
+ {
+ int channel_idx = indices[channel_dim_index];
+ const float scaling_factor_inv = 1.0 / scaling_factor[channel_idx];
+ auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices));
+ quantized_values[cal_offset(dimension, indices)] =
+ static_cast<int32_t>(std::round(data * scaling_factor_inv));
+ }
+ }
+ }
+ }
+
+ node->dtype(loco::DataType::S16); // change the type of tensor
+ node->size<loco::DataType::S16>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::S16>(i) =
+ std::min(kMaxScale, std::max(kMinScale, quantized_values[i]));
+ }
+}
+
+void asym_wquant_per_channel(CircleConst *node, std::vector<float> &min,
+ std::vector<float> &scaling_factor)
+{
+ assert(node->dtype() == loco::DataType::FLOAT32);
+
+ const int32_t kMinScale = 0;
+ const int32_t kMaxScale = 255;
+
+ uint32_t size = node->size<loco::DataType::FLOAT32>();
+ std::vector<int32_t> quantized_values(size);
+
+ loco::TensorShape dimension;
+ dimension.rank(4);
+ uint32_t indices[4] = {
+ 0,
+ };
+ int channel_dim_index{0};
+
+ if (!get_channel_dim_index(node, dimension, channel_dim_index))
+ {
+ assert(false);
+ return;
+ }
+
+ for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++)
+ {
+ for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++)
+ {
+ for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++)
+ {
+ for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++)
+ {
+ int channel_idx = indices[channel_dim_index];
+ const float scaling_factor_inv = 1.0 / scaling_factor[channel_idx];
+ auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices));
+ quantized_values[cal_offset(dimension, indices)] =
+ static_cast<int32_t>(std::round((data - min[channel_idx]) * scaling_factor_inv));
+ }
+ }
+ }
+ }
+
+ node->dtype(loco::DataType::U8); // change the type of tensor
+ node->size<loco::DataType::U8>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::U8>(i) = std::min(kMaxScale, std::max(kMinScale, quantized_values[i]));
+ }
+}
+
+void asym_wquant_per_layer(CircleConst *node, float min, float scaling_factor)
+{
+ const int32_t kMinScale = 0;
+ const int32_t kMaxScale = 255;
+
+ uint32_t size = node->size<loco::DataType::FLOAT32>();
+
+ const float scaling_factor_inv = 1.0 / scaling_factor;
+ std::vector<int32_t> quantized_values(size);
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ auto data = node->at<loco::DataType::FLOAT32>(i);
+ quantized_values[i] = static_cast<int32_t>(std::round((data - min) * scaling_factor_inv));
+ }
+
+ node->dtype(loco::DataType::U8); // change the type of tensor
+ node->size<loco::DataType::U8>(size); // resize tensor
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ node->at<loco::DataType::U8>(i) = std::min(kMaxScale, std::max(kMinScale, quantized_values[i]));
+ }
+}
+
+// Check if node is weights of conv2d, depthwise_conv2d, or fully_connected layer
+bool is_weights(CircleNode *node)
+{
+ auto circle_const = dynamic_cast<CircleConst *>(node);
+ if (circle_const == nullptr)
+ return false;
+
+ auto succs = loco::succs(node);
+ if (succs.size() != 1) // assume weights is used by only one node
+ return false;
+
+ for (auto out : succs)
+ {
+ auto conv = dynamic_cast<CircleConv2D *>(out);
+ if (conv != nullptr && conv->filter() == circle_const)
+ return true;
+
+ auto dw_conv = dynamic_cast<CircleDepthwiseConv2D *>(out);
+ if (dw_conv != nullptr && dw_conv->filter() == circle_const)
+ return true;
+
+ auto fc = dynamic_cast<CircleFullyConnected *>(out);
+ if (fc != nullptr && fc->weights() == circle_const)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * @brief QuantizeActivation quantizes tensors for activations
+ * @details Quantize using recorded min/max values
+ */
+struct QuantizeActivation final : public luci::CircleNodeMutableVisitor<bool>
+{
+ QuantizeActivation(loco::DataType input, loco::DataType output)
+ : input_type(input), output_type(output)
+ {
+ }
+
+ loco::DataType input_type;
+ loco::DataType output_type;
+
+ // Quantize input tensors of each node
+ bool visit(luci::CircleNode *node)
+ {
+ LOGGER(l);
+ INFO(l) << "QuantizeActivation visit node: " << node->name() << std::endl;
+ auto arity = node->arity();
+ for (uint32_t i = 0; i < arity; i++)
+ {
+ auto input_node = node->arg(i);
+ auto circle_node = loco::must_cast<luci::CircleNode *>(input_node);
+
+ // Check if this is already quantized
+ if (is_quantized(circle_node))
+ continue;
+
+ // Check if this is bias (bias is quantized later)
+ auto iw = get_input_weight_of_bias(circle_node);
+ if (iw.first != nullptr && iw.second != nullptr)
+ continue;
+
+ // Check if this is activation
+ // We assume min/max are recorded only for activations
+ if (has_min_max(circle_node) && !is_weights(circle_node))
+ {
+ // Quantize using recorded min/max
+ auto quantparam = circle_node->quantparam();
+ assert(quantparam->min.size() == 1); // only support layer-wise quant
+ assert(quantparam->max.size() == 1); // only support layer-wise quant
+ auto min = quantparam->min[0];
+ auto max = quantparam->max[0];
+
+ float scaling_factor{0};
+ int64_t zp{0};
+ float nudged_min{0};
+ float nudged_max{0};
+
+ if (output_type == loco::DataType::U8)
+ {
+ compute_asym_scale_zp(min, max, scaling_factor, zp, nudged_min, nudged_max);
+ circle_node->dtype(loco::DataType::U8);
+ }
+ else
+ {
+ compute_sym_scale_zp(min, max, scaling_factor, zp, nudged_min, nudged_max);
+ circle_node->dtype(loco::DataType::S16);
+ }
+
+ circle_node->quantparam()->max[0] = nudged_max;
+ circle_node->quantparam()->min[0] = nudged_min;
+ circle_node->quantparam()->scale.push_back(scaling_factor);
+ circle_node->quantparam()->zerop.push_back(zp);
+ }
+ }
+ return false;
+ }
+};
+
+struct QuantizeBias final : public luci::CircleNodeMutableVisitor<bool>
+{
+ QuantizeBias(loco::DataType input, loco::DataType output, QuantizationGranularity gr)
+ : input_type(input), output_type(output), granularity(gr)
+ {
+ }
+
+ loco::DataType input_type;
+ loco::DataType output_type;
+ QuantizationGranularity granularity;
+
+ // Quantize bias node
+ bool visit(luci::CircleNode *node)
+ {
+ // Check if this is already quantized
+ if (is_quantized(node))
+ return false;
+
+ // Check if this is bias
+ auto iw = get_input_weight_of_bias(node);
+ if (iw.first == nullptr || iw.second == nullptr)
+ return false;
+
+ auto input = loco::must_cast<luci::CircleNode *>(iw.first);
+ auto weight = loco::must_cast<luci::CircleNode *>(iw.second);
+
+ if (granularity == QuantizationGranularity::ChannelWise)
+ {
+ assert(input->quantparam()->scale.size() == 1); // input scale's layer-wise
+ auto input_scale = input->quantparam()->scale[0];
+
+ assert(weight->quantparam() != nullptr); // weight scale's channel-wise
+ auto weight_scale = weight->quantparam()->scale;
+
+ auto circle_const = loco::must_cast<luci::CircleConst *>(node);
+
+ uint32_t size = circle_const->size<loco::DataType::FLOAT32>();
+ assert(size == weight_scale.size());
+ std::vector<float> scaling_factor(size);
+ std::vector<int64_t> zp(size);
+
+ quant_bias_per_channel(circle_const, input_scale, weight_scale, scaling_factor, zp);
+
+ auto quantparam = std::make_unique<CircleQuantParam>();
+ quantparam->scale = scaling_factor;
+ quantparam->zerop = zp;
+ assert(circle_const->quantparam() == nullptr); // bias should not be quantized before
+ circle_const->quantparam(std::move(quantparam));
+ }
+ else
+ {
+ assert(input->quantparam()->scale.size() == 1); // Only support per-layer quant
+ auto input_scale = input->quantparam()->scale[0];
+
+ assert(weight->quantparam()->scale.size() == 1); // Only support per-layer quant
+ auto weight_scale = weight->quantparam()->scale[0];
+
+ auto circle_const = loco::must_cast<luci::CircleConst *>(node);
+ float scaling_factor{0};
+ int64_t zp{0};
+ asym_quant_bias_per_layer(circle_const, input_scale, weight_scale, &scaling_factor, &zp);
+ auto quantparam = std::make_unique<CircleQuantParam>();
+ quantparam->scale.push_back(scaling_factor);
+ quantparam->zerop.push_back(zp);
+ assert(circle_const->quantparam() == nullptr); // bias should not be quantized before
+ circle_const->quantparam(std::move(quantparam));
+ }
+ return false;
+ }
+};
+
+/**
+ * @brief QuantizeWeights quantizes tensors for weights
+ * @details Find min/max values on the fly and then quantize
+ */
+struct QuantizeWeights final : public luci::CircleNodeMutableVisitor<bool>
+{
+ QuantizeWeights(loco::DataType input, loco::DataType output, QuantizationGranularity gr)
+ : input_type(input), output_type(output), granularity(gr)
+ {
+ }
+
+ loco::DataType input_type;
+ loco::DataType output_type;
+ QuantizationGranularity granularity;
+
+ // Quantize input tensors of each node
+ bool visit(luci::CircleNode *node)
+ {
+ LOGGER(l);
+ INFO(l) << "QuantizeWeights visit node: " << node->name() << std::endl;
+ auto arity = node->arity();
+ for (uint32_t i = 0; i < arity; i++)
+ {
+ auto input_node = node->arg(i);
+ auto circle_node = loco::must_cast<luci::CircleNode *>(input_node);
+
+ // Check if this is already quantized
+ if (is_quantized(circle_node))
+ continue;
+
+ if (is_weights(circle_node))
+ {
+ auto circle_const = loco::must_cast<luci::CircleConst *>(circle_node);
+
+ // Find min/max per channel-wise
+ if (granularity == QuantizationGranularity::ChannelWise)
+ {
+ auto quantparam = circle_node->quantparam();
+ assert(quantparam != nullptr);
+ auto min = quantparam->min;
+ auto scaling_factor = quantparam->scale;
+
+ if (output_type == loco::DataType::U8)
+ {
+ asym_wquant_per_channel(circle_const, min, scaling_factor);
+ }
+ else
+ {
+ sym_wquant_per_channel(circle_const, scaling_factor);
+ }
+ }
+ // Find min/max per layer-wise
+ else
+ {
+ // Quantize using recorded quantparam
+ auto quantparam = circle_node->quantparam();
+ assert(quantparam != nullptr);
+ assert(quantparam->min.size() == 1); // only support layer-wise quant
+ assert(quantparam->scale.size() == 1); // only support layer-wise quant
+ auto min = quantparam->min[0];
+ auto scaling_factor = quantparam->scale[0];
+ asym_wquant_per_layer(circle_const, min, scaling_factor);
+ }
+ }
+ }
+ return false;
+ }
+};
+
+} // namespace
+
+bool QuantizeWithMinMaxPass::run(loco::Graph *g)
+{
+ LOGGER(l);
+ INFO(l) << "QuantizeWithMinMaxPass Start" << std::endl;
+
+ // Quantize activation
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ QuantizeActivation qa(_input_dtype, _output_dtype);
+ auto circle_node = loco::must_cast<luci::CircleNode *>(node);
+ circle_node->accept(&qa);
+ }
+
+ // Quantize weights
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ QuantizeWeights qw(_input_dtype, _output_dtype, _granularity);
+ auto circle_node = loco::must_cast<luci::CircleNode *>(node);
+ circle_node->accept(&qw);
+ }
+
+ // Quantize bias
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ QuantizeBias qb(_input_dtype, _output_dtype, _granularity);
+ auto circle_node = loco::must_cast<luci::CircleNode *>(node);
+ circle_node->accept(&qb);
+ }
+
+ // Update output dtype
+ auto graph_outputs = g->outputs();
+ for (auto node : loco::output_nodes(g))
+ {
+ auto circle_node = loco::must_cast<luci::CircleOutput *>(node);
+ if (static_cast<luci::CircleNode *>(circle_node->from())->dtype() == _output_dtype)
+ {
+ circle_node->dtype(_output_dtype);
+ auto graph_output = graph_outputs->at(circle_node->index());
+ graph_output->dtype(_output_dtype);
+ }
+ }
+
+ INFO(l) << "QuantizeWithMinMaxPass End" << std::endl;
+ return false; // one time run
+}
+
+} // namespace luci
diff --git a/compiler/luci/pass/src/ResolveCustomOpAddPass.cpp b/compiler/luci/pass/src/ResolveCustomOpAddPass.cpp
new file mode 100644
index 000000000..e52d667d7
--- /dev/null
+++ b/compiler/luci/pass/src/ResolveCustomOpAddPass.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Pass/ResolveCustomOpAddPass.h"
+
+#include "flatbuffers/flexbuffers.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/IR/AttrFusedActFunc.h>
+
+namespace
+{
+
+/// @brief Returns the index of BroadcastTo node among cop's inputs.
+// NOTE This function assumes there is only one BroadcastTo node among its inputs.
+int32_t get_broadcastTo_index_among_inputs_of(luci::CircleCustom *cop)
+{
+ for (uint32_t idx = 0; idx < cop->numInputs(); idx++)
+ {
+ auto input = dynamic_cast<const luci::CircleCustomOut *>(cop->inputs(idx));
+ if (input)
+ {
+ auto broadcastTo = loco::must_cast<luci::CircleCustom *>(input->input());
+ if (broadcastTo->custom_code() == "BroadcastTo")
+ return idx;
+ }
+ }
+
+ return -1;
+}
+
+/** BEFORE
+ * [CircleConst]
+ * |
+ * [CircleNode] [BroadcastTo(CircleCustom)]
+ * \ |
+ * \ [CircleCustomOUt]
+ * \ /
+ * [AddV2(CircleCustom)]
+ * AFTER
+ *
+ * [CircleConst] [CircleNode]
+ * \ /
+ * \ /
+ * [CircleAdd]
+ */
+bool resolve_with_BroadcastTo(luci::CircleCustom *addv2)
+{
+ int32_t broadcastTo_idx = get_broadcastTo_index_among_inputs_of(addv2);
+
+ if (broadcastTo_idx == -1)
+ return false;
+
+ auto input = loco::must_cast<const luci::CircleCustomOut *>(addv2->inputs(broadcastTo_idx));
+ auto broadcastTo = loco::must_cast<luci::CircleCustom *>(input->input());
+
+ auto add = addv2->graph()->nodes()->create<luci::CircleAdd>();
+ add->fusedActivationFunction(luci::FusedActFunc::NONE);
+ add->x(addv2->inputs(1 - broadcastTo_idx));
+ add->y(broadcastTo->inputs(0));
+ auto customOut = loco::succs(addv2);
+ assert(customOut.size() == 1);
+ replace(*customOut.begin()).with(add);
+
+ return true;
+}
+
+bool resolve_custom_op(luci::CircleCustom *addv2)
+{
+ const std::string custom_code = addv2->custom_code();
+ const std::vector<uint8_t> custom_options = addv2->custom_options();
+
+ if (custom_code != "AddV2")
+ return false;
+
+ if (resolve_with_BroadcastTo(addv2))
+ return true;
+
+ auto add = addv2->graph()->nodes()->create<luci::CircleAdd>();
+ add->fusedActivationFunction(luci::FusedActFunc::NONE);
+ add->x(addv2->inputs(0));
+ add->y(addv2->inputs(1));
+ auto customOut = loco::succs(addv2);
+ assert(customOut.size() == 1);
+ replace(*customOut.begin()).with(add);
+
+ return true;
+}
+
+} // namespace
+
+namespace luci
+{
+
+bool ResolveCustomOpAddPass::run(loco::Graph *g)
+{
+ bool changed = false;
+
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ auto cop = dynamic_cast<luci::CircleCustom *>(node);
+ if (not cop)
+ continue;
+
+ changed |= resolve_custom_op(cop);
+ }
+
+ return changed;
+}
+
+} // namespace luci
diff --git a/compiler/luci/pass/src/ResolveCustomOpBatchMatMulPass.cpp b/compiler/luci/pass/src/ResolveCustomOpBatchMatMulPass.cpp
new file mode 100644
index 000000000..145e9cb62
--- /dev/null
+++ b/compiler/luci/pass/src/ResolveCustomOpBatchMatMulPass.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Pass/ResolveCustomOpBatchMatMulPass.h"
+
+#include "flatbuffers/flexbuffers.h"
+
+#include <luci/IR/CircleNodes.h>
+
+namespace
+{
+
+bool resolve_custom_op(luci::CircleCustom *cop)
+{
+ const std::string custom_code = cop->custom_code();
+ const std::vector<uint8_t> custom_options = cop->custom_options();
+
+ if (custom_code == "BatchMatMulV2")
+ {
+ auto batch_matmul = cop->graph()->nodes()->create<luci::CircleBatchMatMul>();
+ // input
+ batch_matmul->x(cop->inputs(0));
+ batch_matmul->y(cop->inputs(1));
+ // TODO find much better way of parsing custom_options
+ // adj
+ auto map = flexbuffers::GetRoot(custom_options).AsMap();
+ batch_matmul->adj_x(map["adj_x"].AsBool());
+ batch_matmul->adj_y(map["adj_y"].AsBool());
+
+ replace(cop).with(batch_matmul);
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+namespace luci
+{
+
+bool ResolveCustomOpBatchMatMulPass::run(loco::Graph *g)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ auto cop = dynamic_cast<luci::CircleCustom *>(node);
+ if (not cop)
+ continue;
+
+ changed |= resolve_custom_op(cop);
+ }
+
+ return changed;
+}
+
+} // namespace luci
diff --git a/compiler/luci/pass/src/ResolveCustomOpMatMulPass.cpp b/compiler/luci/pass/src/ResolveCustomOpMatMulPass.cpp
new file mode 100644
index 000000000..547fd22fc
--- /dev/null
+++ b/compiler/luci/pass/src/ResolveCustomOpMatMulPass.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "luci/Pass/ResolveCustomOpMatMulPass.h"
+
+#include "flatbuffers/flexbuffers.h"
+#include <loco/IR/DataTypeTraits.h>
+
+#include <luci/IR/CircleNodes.h>
+
+#include <loco.h>
+#include <oops/InternalExn.h>
+#include <loco/Service/ShapeInference.h>
+#include <loco/Service/TypeInference.h>
+
+namespace
+{
+
+template <typename T>
+luci::CircleConst *create_const_node(loco::Graph *g, const loco::DataType dtype,
+ const std::vector<uint32_t> &shape,
+ const std::vector<T> &values)
+{
+ auto node = g->nodes()->create<luci::CircleConst>();
+ node->dtype(dtype);
+ node->rank(shape.size());
+
+ uint32_t size = 1;
+ for (uint32_t i = 0; i < shape.size(); ++i)
+ {
+ node->dim(i) = shape.at(i);
+ size *= shape.at(i);
+ }
+
+#define INIT_VALUES(DT) \
+ { \
+ node->size<DT>(size); \
+ for (uint32_t i = 0; i < values.size(); ++i) \
+ node->at<DT>(i) = values[i]; \
+ }
+
+ switch (dtype)
+ {
+ case loco::DataType::U8:
+ INIT_VALUES(loco::DataType::U8);
+ break;
+ case loco::DataType::S16:
+ INIT_VALUES(loco::DataType::S16);
+ break;
+ case loco::DataType::S32:
+ INIT_VALUES(loco::DataType::S32);
+ break;
+ case loco::DataType::FLOAT32:
+ INIT_VALUES(loco::DataType::FLOAT32)
+ break;
+ default:
+ INTERNAL_EXN("create_const_node called with unsupported type");
+ break;
+ }
+ return node;
+}
+
+bool resolve_matmul(luci::CircleCustom *cop)
+{
+#define CHECK_OR_FALSE(condition) \
+ if (not(condition)) \
+ return false;
+#define CHECK_OR_THROW(condition, message) \
+ if (not(condition)) \
+ INTERNAL_EXN(message);
+
+ auto graph = cop->graph();
+ const std::vector<uint8_t> custom_options = cop->custom_options();
+ auto map = flexbuffers::GetRoot(custom_options).AsMap();
+ const auto U8 = loco::DataType::U8;
+ const auto S16 = loco::DataType::S16;
+ const auto S32 = loco::DataType::S32;
+ const auto FLOAT32 = loco::DataType::FLOAT32;
+
+ bool transpose_a = map["transpose_a"].AsBool();
+ bool transpose_b = map["transpose_b"].AsBool();
+
+ loco::Node *lhs = cop->inputs(0);
+ loco::Node *rhs = cop->inputs(1);
+
+ // Check that the type of the first input is known
+ CHECK_OR_FALSE(loco::dtype_known(lhs));
+ auto lhs_dtype = loco::dtype_get(cop->inputs(0));
+
+ // If transpose of first input is requested, its shape must be known
+ CHECK_OR_FALSE(!transpose_a || loco::shape_known(lhs));
+ // and its rank should be at least 2
+ CHECK_OR_FALSE(!transpose_a || loco::shape_get(lhs).as<loco::TensorShape>().rank() >= 2);
+ // Check that the shape of the 2nd input is known
+ CHECK_OR_FALSE(loco::shape_known(rhs));
+ // TODO as of 06/23/20 TFLite only supports rank 2 for 2nd input. Fix this once that changes!
+ CHECK_OR_FALSE(loco::shape_get(rhs).as<loco::TensorShape>().rank() == 2);
+ // Check that input data type is supported
+ CHECK_OR_THROW(lhs_dtype == U8 || lhs_dtype == S16 || lhs_dtype == FLOAT32,
+ "Only UInt8, Int16 and Float32 data types are supported by MatMul");
+
+ if (transpose_a)
+ {
+ auto a_shape = loco::shape_get(lhs).as<loco::TensorShape>();
+ // Create a permutation constant node
+ std::vector<uint32_t> perm;
+ for (uint32_t i = 0; i < a_shape.rank(); ++i)
+ perm.push_back(i);
+ std::swap(perm[a_shape.rank() - 1], perm[a_shape.rank() - 2]);
+ auto perm_node = create_const_node(graph, S32, {a_shape.rank()}, perm);
+ // Now make a transpose node
+ auto transpose_node = graph->nodes()->create<luci::CircleTranspose>();
+ transpose_node->a(lhs);
+ transpose_node->perm(perm_node);
+ lhs = transpose_node;
+ }
+
+ // Transpose the second input if needed. TFLite FullyConnected operator
+ // assumes the second input is in column-major order, but the input is
+ // in row-major order, thus we need to convert between them.
+ if (!transpose_b)
+ {
+ const std::vector<uint32_t> perm{1, 0};
+ auto perm_node = create_const_node(graph, S32, {2}, perm);
+ auto transpose_node = graph->nodes()->create<luci::CircleTranspose>();
+ transpose_node->a(rhs);
+ transpose_node->perm(perm_node);
+ rhs = transpose_node;
+ }
+
+ // Make a constant zero-filled bias node
+ auto b_shape = loco::shape_get(cop->inputs(1)).as<loco::TensorShape>();
+ uint32_t bias_size = b_shape.dim(transpose_b ? 1 : 0).value();
+ const std::vector<float> val(bias_size, .0f);
+ auto bias_node = create_const_node(graph, lhs_dtype, {bias_size}, val);
+ auto fc_node = graph->nodes()->create<luci::CircleFullyConnected>();
+ fc_node->input(lhs);
+ fc_node->weights(rhs);
+ fc_node->bias(bias_node);
+ fc_node->fusedActivationFunction(luci::FusedActFunc::NONE);
+
+ replace(cop).with(fc_node);
+ return true;
+}
+
+} // namespace
+
+namespace luci
+{
+
+bool ResolveCustomOpMatMulPass::run(loco::Graph *g)
+{
+ bool changed = false;
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ auto cop = dynamic_cast<luci::CircleCustom *>(node);
+ if (not cop)
+ continue;
+
+ if (cop->custom_code() != "MatMul")
+ continue;
+
+ if (!resolve_matmul(cop))
+ continue;
+
+ changed = true;
+ }
+
+ return changed;
+}
+
+} // namespace luci
diff --git a/compiler/luci/requires.cmake b/compiler/luci/requires.cmake
index e88dabd24..e52523d45 100644
--- a/compiler/luci/requires.cmake
+++ b/compiler/luci/requires.cmake
@@ -1,5 +1,7 @@
+require("foder")
require("loco")
require("locop")
+require("logo")
require("logo-core")
require("mio-circle")
require("oops")
diff --git a/compiler/luci/service/src/CircleShapeInference.cpp b/compiler/luci/service/src/CircleShapeInference.cpp
index fdcfa76bc..0732849db 100644
--- a/compiler/luci/service/src/CircleShapeInference.cpp
+++ b/compiler/luci/service/src/CircleShapeInference.cpp
@@ -27,11 +27,8 @@ namespace luci
ShapeDescription ShapeInference::get(loco::Node *node)
{
- // TODO Adjust indentation level
- {
- assert(loco::shape_known(node));
- return to_shape_description(loco::shape_get(node));
- }
+ assert(loco::shape_known(node));
+ return to_shape_description(loco::shape_get(node));
}
} // namespace luci
diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.cpp
index c8e872b1e..a291cfe70 100644
--- a/compiler/luci/service/src/CircleShapeInferenceRule.cpp
+++ b/compiler/luci/service/src/CircleShapeInferenceRule.cpp
@@ -17,6 +17,8 @@
#include "luci/Service/CircleShapeInferenceRule.h"
#include "Check.h"
+#include "ShapeInfer_StridedSlice.h"
+
#include <luci/IR/CircleNodes.h>
#include <luci/IR/CircleDialect.h>
#include <luci/IR/CircleNodeVisitor.h>
@@ -26,11 +28,25 @@
#include <algorithm>
#include <cassert>
+#include <cmath>
#include <stdexcept>
namespace
{
+std::ostream &operator<<(std::ostream &os, const loco::TensorShape &tensor_shape)
+{
+ os << "[";
+ for (uint32_t r = 0; r < tensor_shape.rank(); ++r)
+ {
+ if (r)
+ os << ",";
+ os << tensor_shape.dim(r).value();
+ }
+ os << "]";
+ return os;
+}
+
// Call this for CircleAvgPool2D and CircleMaxPool2D only
template <class Pool2DType> loco::NodeShape infer_pool_2d_shape(const Pool2DType *node)
{
@@ -176,6 +192,157 @@ loco::TensorShape broadcast_shape(const loco::TensorShape &x, const loco::Tensor
return output_shape;
}
+// BatchMatMulV2 supports broadcasting in the batch dimensions(BatchMatMul doesn't)
+// TODO Distinguish BatchMatMul and BatchMatMulV2
+loco::NodeShape infer_batchmatmul_shape(const loco::TensorShape &x_shape,
+ const loco::TensorShape &y_shape, bool adj_x, bool adj_y)
+{
+ uint32_t x_rank = x_shape.rank();
+ uint32_t y_rank = y_shape.rank();
+ assert(x_rank >= 2 && y_rank >= 2);
+
+ loco::TensorShape output_shape;
+ output_shape.rank(x_shape.rank());
+ // Braodcast in the batch dimension
+ if (x_rank > 2 || y_rank > 2)
+ {
+ loco::TensorShape dummy_x = x_shape;
+ loco::TensorShape dummy_y = y_shape;
+ expand_rank(dummy_x, dummy_y);
+ if (x_rank < y_rank)
+ expand_rank(output_shape, dummy_y);
+
+ for (uint32_t d = 0; d < output_shape.rank() - 2; d++)
+ {
+ uint32_t max_dim = std::max(dummy_x.dim(d).value(), dummy_y.dim(d).value());
+ if (dummy_x.dim(d) == dummy_y.dim(d) ||
+ dummy_x.dim(d).value() * dummy_y.dim(d).value() == max_dim)
+ output_shape.dim(d).set(max_dim);
+ else
+ INTERNAL_EXN("BatchMatMul has wrong shape");
+ }
+ }
+
+ loco::Dimension x_lhs = adj_x ? x_shape.dim(x_rank - 1) : x_shape.dim(x_rank - 2);
+ loco::Dimension x_rhs = adj_x ? x_shape.dim(x_rank - 2) : x_shape.dim(x_rank - 1);
+ loco::Dimension y_lhs = adj_y ? y_shape.dim(y_rank - 1) : y_shape.dim(y_rank - 2);
+ loco::Dimension y_rhs = adj_y ? y_shape.dim(y_rank - 2) : y_shape.dim(y_rank - 1);
+
+ if (not(x_rhs == y_lhs))
+ INTERNAL_EXN("x_rhs and y_lhs should be same");
+
+ uint32_t out_rank = output_shape.rank();
+ output_shape.dim(out_rank - 2) = x_lhs;
+ output_shape.dim(out_rank - 1) = y_rhs;
+
+ return loco::NodeShape{output_shape};
+}
+
+loco::TensorShape own_shape(const luci::CircleNode *node)
+{
+ loco::TensorShape shape;
+ shape.rank(node->rank());
+ for (uint32_t r = 0; r < node->rank(); ++r)
+ shape.dim(r) = loco::Dimension(node->dim(r).value());
+ return shape;
+}
+
+loco::TensorShape infer_reducer(const loco::Node *input, const loco::Node *indices, bool keep_dims)
+{
+ const loco::DataType S32 = loco::DataType::S32;
+
+ auto input_shape = loco::shape_get(input).as<loco::TensorShape>();
+ auto reduction_indices = loco::must_cast<const luci::CircleConst *>(indices);
+
+ { // Exceptions
+ // TODO support non-const case
+ // TODO support other data type
+ LUCI_ASSERT(reduction_indices->dtype() == S32, "Only support int 32");
+ }
+
+ std::vector<int32_t> reduction_values;
+
+ for (uint32_t i = 0; i < reduction_indices->size<S32>(); ++i)
+ {
+ int32_t axis = reduction_indices->at<S32>(i);
+ if (axis < 0)
+ axis += input_shape.rank();
+ if (not(0 <= axis and axis < static_cast<int32_t>(input_shape.rank())))
+ INTERNAL_EXN_V("Invalid reduction axis for REDUCER", oops::to_uint32(axis));
+ reduction_values.push_back(axis);
+ }
+
+ loco::TensorShape output_shape;
+
+ if (keep_dims)
+ {
+ output_shape.rank(input_shape.rank());
+ for (uint32_t i = 0; i < input_shape.rank(); ++i)
+ output_shape.dim(i) = input_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_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_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++) = input_shape.dim(i);
+ }
+
+ return output_shape;
+}
+
+/**
+ * @brief vector_from_constant will return int64_t vector from CircleConst node
+ */
+template <loco::DataType T> std::vector<int64_t> vector_from_constant(luci::CircleConst *const_node)
+{
+ std::vector<int64_t> result;
+
+ for (uint32_t idx = 0; idx < const_node->size<T>(); ++idx)
+ result.push_back(const_node->at<T>(idx));
+
+ return result;
+}
+
+template <class CIRCLENODE> loco::NodeShape broadcast_xy(const CIRCLENODE *node)
+{
+ auto x_shape = loco::shape_get(node->x()).template as<loco::TensorShape>();
+ auto y_shape = loco::shape_get(node->y()).template as<loco::TensorShape>();
+
+ auto output_shape = broadcast_shape(x_shape, y_shape);
+
+ return loco::NodeShape{output_shape};
+}
+
+template <class CIRCLENODE> loco::NodeShape use_x(const CIRCLENODE *node)
+{
+ auto x_shape = loco::shape_get(node->x()).template as<loco::TensorShape>();
+ return loco::NodeShape{x_shape};
+}
+
+template <class CIRCLENODE> loco::NodeShape use_logits(const CIRCLENODE *node)
+{
+ auto shape = loco::shape_get(node->logits()).template as<loco::TensorShape>();
+ return loco::NodeShape{shape};
+}
+
+loco::NodeShape use_own(const luci::CircleNode *node)
+{
+ loco::TensorShape shape = own_shape(node);
+ return loco::NodeShape{shape};
+}
+
/**
* @brief Class to infer the shape of CircleNode
*
@@ -184,20 +351,24 @@ loco::TensorShape broadcast_shape(const loco::TensorShape &x, const loco::Tensor
class ShapeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::NodeShape>
{
public:
- loco::NodeShape visit(const luci::CircleAbs *node) final
- {
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- return loco::NodeShape{x_shape};
- }
+ loco::NodeShape visit(const luci::CircleAbs *node) final { return use_x(node); }
- loco::NodeShape visit(const luci::CircleAdd *node) final
+ loco::NodeShape visit(const luci::CircleAdd *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleAddN *node) final
{
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>();
+ auto shape = loco::shape_get(node->inputs(0)).as<loco::TensorShape>();
- auto output_shape = broadcast_shape(x_shape, y_shape);
+ for (uint32_t idx = 1; idx < node->arity(); ++idx)
+ {
+ auto shape_idx = loco::shape_get(node->inputs(idx)).as<loco::TensorShape>();
+ if (!(shape == shape_idx))
+ {
+ INTERNAL_EXN_V("ADD_N shape not same as the first input: ", idx);
+ }
+ }
- return loco::NodeShape{output_shape};
+ return loco::NodeShape{shape};
}
loco::NodeShape visit(const luci::CircleArgMax *node) final
@@ -211,8 +382,7 @@ public:
// Only support node's shape() is CircleConst with S32/S64
// Support S32 for now.
- auto const_shape_node = dynamic_cast<luci::CircleConst *>(node->dimension());
- LUCI_ASSERT(const_shape_node, "Only support CircleConst for shape of CircleArgMax");
+ auto const_shape_node = loco::must_cast<luci::CircleConst *>(node->dimension());
LUCI_ASSERT(const_shape_node->dtype() == loco::DataType::S32,
"Only support int32 CircleConst for CircleArgMax");
@@ -240,11 +410,58 @@ public:
return loco::NodeShape{shape_output};
}
+ loco::NodeShape visit(const luci::CircleArgMin *node) final
+ {
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ auto dimension_shape = loco::shape_get(node->dimension()).as<loco::TensorShape>();
+
+ int64_t select_axis = 0;
+ {
+ LUCI_ASSERT(node->dimension(), "2nd input dimension() should not be nullptr");
+
+ // Only support node's shape() is CircleConst with S32/S64
+ // Support S32 for now.
+ auto const_shape_node = loco::must_cast<luci::CircleConst *>(node->dimension());
+ LUCI_ASSERT(const_shape_node->dtype() == loco::DataType::S32,
+ "Only support int32 CircleConst for CircleArgMin");
+
+ if (const_shape_node->rank() > 1)
+ INTERNAL_EXN_V("Only support rank 0/1 CircleConst",
+ oops::to_uint32(const_shape_node->rank()));
+
+ select_axis = const_shape_node->scalar<loco::DataType::S32>();
+ }
+ assert(select_axis < input_shape.rank());
+ assert(select_axis >= 0); // TODO support minus of this breaks
+
+ // NOTE select_axis is removed
+ loco::TensorShape shape_output;
+ uint32_t rank = input_shape.rank();
+ uint32_t shrink = static_cast<uint32_t>(select_axis);
+ assert(rank > 0);
+ shape_output.rank(rank - 1);
+ for (uint32_t r = 0, d = 0; r < rank; ++r)
+ {
+ if (r == shrink)
+ continue;
+ shape_output.dim(d++) = input_shape.dim(r);
+ }
+ return loco::NodeShape{shape_output};
+ }
+
loco::NodeShape visit(const luci::CircleAveragePool2D *node) final
{
return infer_pool_2d_shape(node);
}
+ loco::NodeShape visit(const luci::CircleBatchMatMul *node) final
+ {
+ auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
+ auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>();
+
+ return infer_batchmatmul_shape(x_shape, y_shape, node->adj_x(), node->adj_y());
+ }
+
loco::NodeShape visit(const luci::CircleBatchToSpaceND *node) final
{
const loco::DataType S32 = loco::DataType::S32;
@@ -254,14 +471,12 @@ public:
assert(input_shape.rank() == 3 || input_shape.rank() == 4);
// Only support block_shape() with S32 type CircleConst for now
- auto const_block_shape = dynamic_cast<luci::CircleConst *>(node->block_shape());
- LUCI_ASSERT(const_block_shape, "Only support CircleConst for block_shape");
+ auto const_block_shape = loco::must_cast<luci::CircleConst *>(node->block_shape());
LUCI_ASSERT(const_block_shape->dtype() == loco::DataType::S32,
"Only support int32 block_shape");
// Only support crops() with S32 type CircleConst for now
- auto const_crops = dynamic_cast<luci::CircleConst *>(node->crops());
- LUCI_ASSERT(const_crops, "Only support CircleConst for crops");
+ auto const_crops = loco::must_cast<luci::CircleConst *>(node->crops());
LUCI_ASSERT(const_crops->dtype() == loco::DataType::S32, "Only support int32 crops");
auto const_block_shape_shape = loco::shape_get(const_block_shape).as<loco::TensorShape>();
@@ -295,6 +510,10 @@ public:
return loco::NodeShape{shape_output};
}
+ loco::NodeShape visit(const luci::CircleCast *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleCeil *node) final { return use_x(node); }
+
loco::NodeShape visit(const luci::CircleConcatenation *node) final
{
// TODO Support when CircleConcatenation has 0 input
@@ -330,16 +549,7 @@ public:
return loco::NodeShape{output_shape};
}
- loco::NodeShape visit(const luci::CircleConst *node) final
- {
- loco::TensorShape shape;
-
- shape.rank(node->rank());
- for (uint32_t axis = 0; axis < node->rank(); axis++)
- shape.dim(axis) = node->dim(axis);
-
- return loco::NodeShape{shape};
- }
+ loco::NodeShape visit(const luci::CircleConst *node) final { return use_own(node); }
loco::NodeShape visit(const luci::CircleConv2D *node) final
{
@@ -361,8 +571,8 @@ public:
uint32_t stride_width = node->stride()->w();
uint32_t ker_height = ker_shape.dim(1).value();
uint32_t ker_width = ker_shape.dim(2).value();
- uint32_t dilation_height = 1;
- uint32_t dilation_width = 1;
+ uint32_t dilation_height = node->dilation()->h();
+ uint32_t dilation_width = node->dilation()->w();
uint32_t effective_ker_height = dilation_height * (ker_height - 1) + 1;
uint32_t effective_ker_width = dilation_width * (ker_width - 1) + 1;
@@ -392,11 +602,40 @@ public:
return loco::NodeShape{ofm_shape};
}
- loco::NodeShape visit(const luci::CircleCos *node) final
+ loco::NodeShape visit(const luci::CircleCos *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleCustom *node) final { return use_own(node); }
+
+ loco::NodeShape visit(const luci::CircleDepthToSpace *node) final
{
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ LUCI_ASSERT(input_shape.rank() == 4, "Only input rank 4 is supported");
+
+ // Only data format NHWC is supported
+ // TODO need to clarify what to do with layout in this operator
+ int32_t height = input_shape.dim(1).value();
+ int32_t width = input_shape.dim(2).value();
+ int32_t depth = input_shape.dim(3).value();
+
+ int block_size = node->block_size();
+
+ if (block_size < 2)
+ INTERNAL_EXN("Block size must be >= 2");
+
+ if (depth % (block_size * block_size))
+ {
+ INTERNAL_EXN("The input tensor's depth must be divisible by block_size^2");
+ }
- return loco::NodeShape{x_shape};
+ loco::TensorShape output_shape;
+ output_shape.rank(4);
+
+ output_shape.dim(0) = input_shape.dim(0).value();
+ output_shape.dim(1) = height * block_size;
+ output_shape.dim(2) = width * block_size;
+ output_shape.dim(3) = depth / (block_size * block_size);
+
+ return loco::NodeShape{output_shape};
}
loco::NodeShape visit(const luci::CircleDepthwiseConv2D *node) final
@@ -414,8 +653,8 @@ public:
uint32_t stride_width = node->stride()->w();
uint32_t ker_height = ker_shape.dim(1).value();
uint32_t ker_width = ker_shape.dim(2).value();
- uint32_t dilation_height = 1;
- uint32_t dilation_width = 1;
+ uint32_t dilation_height = node->dilation()->h();
+ uint32_t dilation_width = node->dilation()->w();
uint32_t effective_ker_height = dilation_height * (ker_height - 1) + 1;
uint32_t effective_ker_width = dilation_width * (ker_width - 1) + 1;
@@ -445,30 +684,87 @@ public:
return loco::NodeShape{ofm_shape};
}
- loco::NodeShape visit(const luci::CircleDiv *node) final
- {
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>();
+ loco::NodeShape visit(const luci::CircleDiv *node) final { return broadcast_xy(node); }
- auto output_shape = broadcast_shape(x_shape, y_shape);
+ loco::NodeShape visit(const luci::CircleElu *node) final
+ {
+ auto input_shape = loco::shape_get(node->features()).as<loco::TensorShape>();
- return loco::NodeShape{output_shape};
+ return loco::NodeShape{input_shape};
}
- loco::NodeShape visit(const luci::CircleEqual *node) final
+ loco::NodeShape visit(const luci::CircleEqual *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleExp *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleExpandDims *node) final
{
- const auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- const auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>();
- loco::TensorShape output_shape = broadcast_shape(x_shape, y_shape);
+ const loco::DataType S32 = loco::DataType::S32;
+ auto x_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ if (x_shape.rank() == 0)
+ {
+ // This maybe for unknown shape. We use shape from the node itself.
+ return use_own(node);
+ }
+ auto const_axis = loco::must_cast<luci::CircleConst *>(node->axis());
+ LUCI_ASSERT(const_axis->dtype() == S32, "Only support int32 CircleConst for axis");
+ if (const_axis->rank() != 0 && const_axis->rank() != 1)
+ {
+ INTERNAL_EXN_V("Non-scalar axis in OP", node->opnum());
+ }
+ int32_t axis = const_axis->at<S32>(0);
+ LUCI_ASSERT((axis <= static_cast<int32_t>(x_shape.rank())) &&
+ (axis >= -1 - static_cast<int32_t>(x_shape.rank())),
+ "Axis has to be between [-(D+1), D], where D is rank of input.");
+ size_t positive_axis = axis < 0 ? x_shape.rank() + axis + 1 : axis;
+ loco::TensorShape output_shape;
+ output_shape.rank(x_shape.rank() + 1);
+ size_t i = 0;
+ for (; i < positive_axis; i++)
+ output_shape.dim(i) = x_shape.dim(i);
+ output_shape.dim(i) = loco::Dimension(1);
+ for (; i < x_shape.rank(); i++)
+ output_shape.dim(i + 1) = x_shape.dim(i);
return loco::NodeShape{output_shape};
}
- loco::NodeShape visit(const luci::CircleExp *node) final
+ loco::NodeShape visit(const luci::CircleFill *node) final
{
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- return loco::NodeShape{x_shape};
+ loco::TensorShape shape;
+ {
+ LUCI_ASSERT(node->dims(), "dims input should not be nullptr");
+
+ auto dims_node = dynamic_cast<luci::CircleConst *>(node->dims());
+ if (dims_node != nullptr)
+ {
+ // Only support node with S32
+ LUCI_ASSERT(dims_node->dtype() == loco::DataType::S32, "Only support int32 CircleConst");
+
+ if (dims_node->rank() != 1)
+ INTERNAL_EXN_V("Only support rank 1 CircleConst", oops::to_uint32(dims_node->rank()));
+
+ shape.rank(dims_node->dim(0).value());
+
+ for (uint32_t axis = 0; axis < shape.rank(); ++axis)
+ {
+ shape.dim(axis) = dims_node->at<loco::DataType::S32>(axis);
+ }
+ }
+ else
+ {
+ shape = own_shape(node);
+ }
+ }
+
+ return loco::NodeShape{shape};
}
+ loco::NodeShape visit(const luci::CircleFloor *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleFloorDiv *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleFloorMod *node) final { return broadcast_xy(node); }
+
loco::NodeShape visit(const luci::CircleFullyConnected *node) final
{
auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
@@ -478,8 +774,11 @@ public:
// Input: a tensor of at least rank 2 [D1, D2, ... Dn]
// Weight: [# of units, K]
// Output: [D1 * D2 * ... * Dn / K, # of units]
- LUCI_ASSERT(input_shape.rank() >= 2, "Input rank should be at least 2");
- LUCI_ASSERT(weights_shape.rank() == 2, "Incompatible weights rank for fully connected");
+ if (input_shape.rank() < 2 || weights_shape.rank() != 2)
+ {
+ // Return node own shape if shape inference is not possible
+ return use_own(node);
+ }
uint32_t input_size = 1;
for (uint32_t i = 0; i < input_shape.rank(); i++)
@@ -495,28 +794,171 @@ public:
return loco::NodeShape{out_shape};
}
- loco::NodeShape visit(const luci::CircleLogicalNot *node) final
+ loco::NodeShape visit(const luci::CircleGather *node) final
+ {
+ loco::TensorShape output_shape;
+
+ const auto input_shape = loco::shape_get(node->params()).as<loco::TensorShape>();
+ const auto positions_shape = loco::shape_get(node->indices()).as<loco::TensorShape>();
+ int32_t axis = node->axis();
+
+ // If CircleGather input has a dynamic shape, it can't inference this shape. So, it returns the
+ // shape that node already has.
+ if (input_shape.rank() == 0 || positions_shape.rank() == 0)
+ return use_own(node);
+
+ if (axis < 0)
+ axis += input_shape.rank();
+
+ output_shape.rank(input_shape.rank() - 1 + positions_shape.rank());
+ int32_t outdim_index = 0;
+ for (int32_t i = 0; i < axis; ++i)
+ output_shape.dim(outdim_index++) = input_shape.dim(i);
+ for (uint32_t i = 0; i < positions_shape.rank(); ++i)
+ output_shape.dim(outdim_index++) = positions_shape.dim(i);
+ for (uint32_t i = axis + 1; i < input_shape.rank(); ++i)
+ output_shape.dim(outdim_index++) = input_shape.dim(i);
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleGatherNd *node) final
+ {
+ loco::TensorShape output_shape;
+
+ const auto params_shape = loco::shape_get(node->params()).as<loco::TensorShape>();
+ const auto indices_shape = loco::shape_get(node->indices()).as<loco::TensorShape>();
+
+ const auto params_rank = params_shape.rank();
+ const auto indices_rank = indices_shape.rank();
+
+ // see https://www.tensorflow.org/api_docs/python/tf/gather_nd
+ // output.shape = indices.shape[:-1] + params.shape[indices.shape[-1]:]
+ // batch_dims isn't supported in tflite
+
+ // TODO: replace exceptions with setting shape to unknown?
+
+ if (!indices_shape.dim(indices_rank - 1).known())
+ INTERNAL_EXN("Last indices dimension is unknown");
+
+ auto indices_last_dim = indices_shape.dim(indices_rank - 1).value();
+
+ if (indices_last_dim > params_rank)
+ INTERNAL_EXN("Last indices dimension should be <= params rank");
+
+ const uint32_t output_rank = indices_rank + params_rank - indices_last_dim - 1;
+
+ output_shape.rank(output_rank);
+
+ uint32_t output_index = 0;
+ for (uint32_t i = 0; i < indices_rank - 1; ++i)
+ {
+ auto &dim = indices_shape.dim(i);
+ if (!dim.known())
+ INTERNAL_EXN("Unknown indices dimension is unsupported");
+ output_shape.dim(output_index++).set(dim.value());
+ }
+
+ for (uint32_t i = indices_last_dim; i < params_rank; ++i)
+ {
+ auto &dim = params_shape.dim(i);
+ if (!dim.known())
+ INTERNAL_EXN("Unknown params dimension is unsupported");
+ output_shape.dim(output_index++).set(dim.value());
+ }
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleGreater *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleGreaterEqual *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleIf *node) final
{
- const auto input_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
+ // Shape of CircleIf is not used. Just use input 0
+ assert(node->input_count() > 0);
+ const auto input_shape = loco::shape_get(node->input(0)).as<loco::TensorShape>();
return loco::NodeShape{input_shape};
}
- loco::NodeShape visit(const luci::CircleLogicalOr *node) final
+ loco::NodeShape visit(const luci::CircleL2Normalize *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleL2Pool2D *node) final
+ {
+ return infer_pool_2d_shape(node);
+ }
+
+ loco::NodeShape visit(const luci::CircleLeakyRelu *node) final
{
- const auto input_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
+ const auto input_shape = loco::shape_get(node->features()).as<loco::TensorShape>();
return loco::NodeShape{input_shape};
}
- loco::NodeShape visit(const luci::CircleMaximum *node) final
+ loco::NodeShape visit(const luci::CircleLess *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleLessEqual *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleLocalResponseNormalization *node) final
{
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>();
+ const auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ return loco::NodeShape{input_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleLog *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleLogicalAnd *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleLogicalNot *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleLogicalOr *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleLogistic *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleMatrixSetDiag *node) final
+ {
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ auto diagonal_shape = loco::shape_get(node->diagonal()).as<loco::TensorShape>();
+
+ auto rank = diagonal_shape.rank();
+
+ LUCI_ASSERT(rank == input_shape.rank() - 1, "diagonal rank = input rank - 1");
+
+ for (uint32_t i = 0; i < rank - 1; i++)
+ {
+ LUCI_ASSERT(diagonal_shape.dim(i) == input_shape.dim(i), "diagonal dims = input dims");
+ }
+
+ auto dim = std::min(input_shape.dim(rank - 1).value(), input_shape.dim(rank).value());
+
+ LUCI_ASSERT(dim == diagonal_shape.dim(rank - 1), "Max diag len error");
+
+ return loco::NodeShape{input_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleLogSoftmax *node) final { return use_logits(node); }
+
+ loco::NodeShape visit(const luci::CircleMatrixDiag *node) final
+ {
+ loco::TensorShape output_shape;
+
+ auto diagonal_shape = loco::shape_get(node->diagonal()).as<loco::TensorShape>();
+ auto rank = diagonal_shape.rank();
- auto output_shape = broadcast_shape(x_shape, y_shape);
+ output_shape.rank(rank + 1);
+
+ for (uint32_t i = 0; i < rank; i++)
+ {
+ output_shape.dim(i) = diagonal_shape.dim(i);
+ }
+
+ output_shape.dim(rank) = diagonal_shape.dim(rank - 1);
return loco::NodeShape{output_shape};
}
+ loco::NodeShape visit(const luci::CircleMaximum *node) final { return broadcast_xy(node); }
+
loco::NodeShape visit(const luci::CircleMaxPool2D *node) final
{
return infer_pool_2d_shape(node);
@@ -524,67 +966,81 @@ public:
loco::NodeShape visit(const luci::CircleMean *node) final
{
+ auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims());
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleMinimum *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleMirrorPad *node) final
+ {
const loco::DataType S32 = loco::DataType::S32;
auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
- auto reduction_indices = dynamic_cast<luci::CircleConst *>(node->reduction_indices());
+ auto paddings = loco::must_cast<luci::CircleConst *>(node->paddings());
- { // Exceptions
- // TODO support non-const case
- LUCI_ASSERT(reduction_indices, "Only support constant reduction_indices");
- // TODO support other data type
- LUCI_ASSERT(reduction_indices->dtype() == S32, "Only support int 32");
- }
+ // TODO support non-const case
+ // TODO support other data type
+ LUCI_ASSERT(paddings->dtype() == S32, "Only support int 32 for now");
+ LUCI_ASSERT(paddings->rank() == 2, "paddings should be rank 2")
- std::vector<int32_t> reduction_values;
+ int32_t n = paddings->dim(0).value();
+ int32_t v = paddings->dim(1).value();
- for (uint32_t i = 0; i < reduction_indices->size<S32>(); ++i)
- {
- int32_t axis = reduction_indices->at<S32>(i);
- if (axis < 0)
- axis += input_shape.rank();
- if (not(0 <= axis and axis < static_cast<int32_t>(input_shape.rank())))
- INTERNAL_EXN_V("Invalid reduction axis for MEAN", oops::to_uint32(axis));
- reduction_values.push_back(axis);
- }
+ LUCI_ASSERT(v == 2, "paddings should be [n, 2]");
+ LUCI_ASSERT(n == int32_t(input_shape.rank()),
+ "paddings [n, 2] should have same value of input rank");
loco::TensorShape output_shape;
- if (node->keep_dims())
- {
- output_shape.rank(input_shape.rank());
- for (uint32_t i = 0; i < input_shape.rank(); ++i)
- output_shape.dim(i) = input_shape.dim(i);
- for (uint32_t i = 0; i < reduction_values.size(); ++i)
- output_shape.dim(reduction_values.at(i)) = 1;
- }
- else
+ output_shape.rank(input_shape.rank());
+ for (int32_t ni = 0; ni < n; ++ni)
{
- std::vector<bool> check_reduce(input_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_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;
+ int32_t idx = ni * 2;
+ int value = input_shape.dim(ni).value();
+ value += paddings->at<S32>(idx + 0); // left
+ value += paddings->at<S32>(idx + 1); // right
+ output_shape.dim(ni) = value;
}
return loco::NodeShape{output_shape};
}
- loco::NodeShape visit(const luci::CircleMul *node) final
- {
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>();
+ loco::NodeShape visit(const luci::CircleMul *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleNeg *node) final { return use_x(node); }
- auto output_shape = broadcast_shape(x_shape, y_shape);
+ loco::NodeShape visit(const luci::CircleNotEqual *node) final { return broadcast_xy(node); }
+ loco::NodeShape visit(const luci::CircleOneHot *node) final
+ {
+ const loco::DataType S32 = loco::DataType::S32;
+ auto indices_shape = loco::shape_get(node->indices()).as<loco::TensorShape>();
+ // Only support OneHot node's depth() is CircleConst with type S32
+ // TODO support depth with other types
+ auto depth = loco::must_cast<luci::CircleConst *>(node->depth());
+ LUCI_ASSERT(depth->dtype() == S32, "Only support int32 CircleConst");
+ if (depth->rank() != 0)
+ INTERNAL_EXN_V("Only support rank 0 CircleOneHot in Depth", oops::to_uint32(depth->rank()));
+ loco::TensorShape output_shape;
+ output_shape.rank(indices_shape.rank() + 1);
+ auto axis = node->axis();
+ if (axis < 0)
+ axis += indices_shape.rank() + 1;
+ LUCI_ASSERT(0 <= axis, "Axis is out of range");
+ LUCI_ASSERT(static_cast<uint32_t>(axis) <= indices_shape.rank(), "Axis is out of range");
+ uint32_t j = 0;
+ for (uint32_t i = 0; i < output_shape.rank(); i++)
+ {
+ if (i == static_cast<uint32_t>(axis))
+ {
+ output_shape.dim(i) = depth->at<S32>(0);
+ }
+ else
+ {
+ output_shape.dim(i) = indices_shape.dim(j++);
+ }
+ }
return loco::NodeShape{output_shape};
}
@@ -636,10 +1092,9 @@ public:
const loco::DataType S32 = loco::DataType::S32;
auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
- auto paddings = dynamic_cast<luci::CircleConst *>(node->paddings());
+ auto paddings = loco::must_cast<luci::CircleConst *>(node->paddings());
// TODO support non-const case
- LUCI_ASSERT(paddings, "Only support constant reduction_indices");
// TODO support other data type
LUCI_ASSERT(paddings->dtype() == S32, "Only support int 32 for now");
LUCI_ASSERT(paddings->rank() == 2, "paddings should be rank 2")
@@ -666,6 +1121,93 @@ public:
return loco::NodeShape{output_shape};
}
+ loco::NodeShape visit(const luci::CirclePow *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CirclePRelu *node) final
+ {
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ auto alpha_shape = loco::shape_get(node->alpha()).as<loco::TensorShape>();
+
+ auto output_shape = broadcast_shape(input_shape, alpha_shape);
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleRange *node) final
+ {
+ loco::TensorShape output_shape;
+ output_shape.rank(1);
+
+ auto start_node = dynamic_cast<luci::CircleConst *>(node->start());
+ auto limit_node = dynamic_cast<luci::CircleConst *>(node->limit());
+ auto delta_node = dynamic_cast<luci::CircleConst *>(node->delta());
+
+ if (start_node == nullptr || limit_node == nullptr || delta_node == nullptr)
+ {
+ return use_own(node);
+ }
+
+ double start = 0, limit = 0, delta = 0;
+
+#define GET_RANGE_PARAM(DT) \
+ start = start_node->scalar<DT>(); \
+ limit = limit_node->scalar<DT>(); \
+ delta = delta_node->scalar<DT>();
+
+ switch (start_node->dtype())
+ {
+ case loco::DataType::FLOAT32:
+ GET_RANGE_PARAM(loco::DataType::FLOAT32)
+ break;
+ case loco::DataType::S32:
+ GET_RANGE_PARAM(loco::DataType::S32)
+ break;
+ default:
+ INTERNAL_EXN("Range data type not supported");
+ }
+
+#undef GET_RANGE_PARAM
+
+ if (delta == 0)
+ INTERNAL_EXN("Delta can not be zero");
+
+ output_shape.dim(0) = ceil((limit - start) / delta);
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleRank *) final
+ {
+ loco::TensorShape shape_output;
+ shape_output.rank(0);
+
+ return loco::NodeShape{shape_output};
+ }
+
+ loco::NodeShape visit(const luci::CircleReduceAny *node) final
+ {
+ auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims());
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleReduceMax *node) final
+ {
+ auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims());
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleReduceMin *node) final
+ {
+ auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims());
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleReduceProd *node) final
+ {
+ auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims());
+ return loco::NodeShape{output_shape};
+ }
+
loco::NodeShape visit(const luci::CircleRelu *node) final
{
auto input_shape = loco::shape_get(node->features()).as<loco::TensorShape>();
@@ -680,15 +1222,24 @@ public:
return loco::NodeShape{input_shape};
}
+ loco::NodeShape visit(const luci::CircleReluN1To1 *node) final
+ {
+ auto input_shape = loco::shape_get(node->features()).as<loco::TensorShape>();
+
+ return loco::NodeShape{input_shape};
+ }
+
/**
* @note CircleReshape has new shape info in two places: 2nd input and attribute.
- * This shape inference forces both to exist, and match each other.
- * When this condition satisfied, it return the inferred shape
+ * This shape inference uses shape from input 'shape' node when it's constant.
+ * If not, shape will be from node itself. shape from attribute is not used.
*
* TODO Change this policy when not appropriate
*/
loco::NodeShape visit(const luci::CircleReshape *node) final
{
+ LOGGER(l);
+
const loco::DataType S32 = loco::DataType::S32;
loco::TensorShape shape_by_input;
@@ -698,18 +1249,21 @@ public:
// Only support node's shape() is CircleConst with S32
// TODO support other node with other types
auto const_shape_node = dynamic_cast<luci::CircleConst *>(node->shape());
- LUCI_ASSERT(const_shape_node, "Only support CircleConst for shape of CircleReshape");
- LUCI_ASSERT(const_shape_node->dtype() == S32, "Only support int32 CircleConst");
-
- if (const_shape_node->rank() != 1)
- INTERNAL_EXN_V("Only support rank 1 CircleConst",
- oops::to_uint32(const_shape_node->rank()));
+ if (const_shape_node != nullptr)
+ {
+ LUCI_ASSERT(const_shape_node->dtype() == S32, "Only support int32 CircleConst");
- shape_by_input.rank(const_shape_node->dim(0).value());
+ shape_by_input.rank(const_shape_node->size<S32>());
- for (uint32_t axis = 0; axis < shape_by_input.rank(); ++axis)
+ for (uint32_t axis = 0; axis < shape_by_input.rank(); ++axis)
+ {
+ shape_by_input.dim(axis) = const_shape_node->at<S32>(axis);
+ }
+ }
+ else
{
- shape_by_input.dim(axis) = const_shape_node->at<S32>(axis);
+ // We use shape from the node itself
+ shape_by_input = own_shape(node);
}
}
@@ -723,8 +1277,12 @@ public:
}
}
- LUCI_ASSERT(shape_by_input == shape_by_attr,
- "Warning: Two new shape information mismatched for CircleReshape");
+ if (!(shape_by_input == shape_by_attr))
+ {
+ INFO(l) << "CircleReshape: Two new shape information mismatched : " << std::endl;
+ INFO(l) << " shape_by_input : " << shape_by_input << std::endl;
+ INFO(l) << " shape_by_attr : " << shape_by_attr << std::endl;
+ }
loco::TensorShape output_shape = shape_by_input;
@@ -754,94 +1312,517 @@ public:
return loco::NodeShape{output_shape};
}
- loco::NodeShape visit(const luci::CircleRsqrt *node) final
+ loco::NodeShape visit(const luci::CircleResizeBilinear *node) final
{
- auto input_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
- return loco::NodeShape{input_shape};
+ if (input_shape.rank() != 4)
+ INTERNAL_EXN("Expected ResizeBilinear input to have rank 4");
+
+ auto *const_node = loco::must_cast<luci::CircleConst *>(node->size());
+
+ if (const_node->dtype() != loco::DataType::S32)
+ INTERNAL_EXN("Only S32 datatype is supported for ResizeBilinear size");
+
+ if (const_node->rank() != 1)
+ INTERNAL_EXN("Expected size tensor of rank 1");
+
+ if (const_node->dim(0).value() != 2)
+ INTERNAL_EXN("Expected size tensor with shape [2]");
+
+ loco::TensorShape output_shape;
+ output_shape.rank(4);
+ output_shape.dim(0) = input_shape.dim(0);
+ output_shape.dim(1) = const_node->at<loco::DataType::S32>(0);
+ output_shape.dim(2) = const_node->at<loco::DataType::S32>(1);
+ output_shape.dim(3) = input_shape.dim(3);
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleResizeNearestNeighbor *node) final
+ {
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+
+ if (input_shape.rank() != 4)
+ INTERNAL_EXN("Expected ResizeNearesNeighbor input to have rank 4");
+
+ auto *const_node = loco::must_cast<luci::CircleConst *>(node->size());
+
+ if (const_node->dtype() != loco::DataType::S32)
+ INTERNAL_EXN("Only S32 datatype is supported for ResizeNearesNeighbor size");
+
+ if (const_node->rank() != 1)
+ INTERNAL_EXN("Expected size tensor of rank 1");
+
+ if (const_node->dim(0).value() != 2)
+ INTERNAL_EXN("Expected size tensor with shape [2]");
+
+ loco::TensorShape output_shape;
+ output_shape.rank(4);
+ output_shape.dim(0) = input_shape.dim(0);
+ output_shape.dim(1) = const_node->at<loco::DataType::S32>(0);
+ output_shape.dim(2) = const_node->at<loco::DataType::S32>(1);
+ output_shape.dim(3) = input_shape.dim(3);
+
+ return loco::NodeShape{output_shape};
}
- loco::NodeShape visit(const luci::CircleSoftmax *node) final
+ loco::NodeShape visit(const luci::CircleReverseSequence *node) final
{
- auto input_shape = loco::shape_get(node->logits()).as<loco::TensorShape>();
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
return loco::NodeShape{input_shape};
}
- loco::NodeShape visit(const luci::CircleSqrt *node) final
+ loco::NodeShape visit(const luci::CircleRound *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleReverseV2 *node) final
{
- auto input_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
+ auto input_shape = loco::shape_get(node->tensor()).as<loco::TensorShape>();
+
+ LUCI_ASSERT(loco::shape_get(node->axis()).as<loco::TensorShape>().rank() == 1,
+ "Tensor must be 1-D");
return loco::NodeShape{input_shape};
}
- loco::NodeShape visit(const luci::CircleSquaredDifference *node) final
+ loco::NodeShape visit(const luci::CircleRsqrt *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleScatterNd *node) final
{
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>();
+ loco::TensorShape output_shape;
+
+ auto shape_node = loco::must_cast<luci::CircleConst *>(node->shape());
+
+ const loco::DataType S32 = loco::DataType::S32;
+ const loco::DataType S64 = loco::DataType::S64;
- auto output_shape = broadcast_shape(x_shape, y_shape);
+ std::vector<int64_t> vect_shape;
+
+ if (shape_node->dtype() == S32)
+ vect_shape = vector_from_constant<S32>(shape_node);
+ else if (shape_node->dtype() == S64)
+ vect_shape = vector_from_constant<S64>(shape_node);
+ else
+ LUCI_ASSERT(false, "Only support int32/int64 for shape()");
+
+ output_shape.rank(vect_shape.size());
+ for (uint32_t i = 0; i < vect_shape.size(); ++i)
+ output_shape.dim(i) = vect_shape[i];
return loco::NodeShape{output_shape};
}
- loco::NodeShape visit(const luci::CircleSub *node) final
+ loco::NodeShape visit(const luci::CircleSegmentSum *node) final
{
- auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>();
- auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>();
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ auto segment_shape = loco::shape_get(node->segment_ids()).as<loco::TensorShape>();
+
+ LUCI_ASSERT(segment_shape.rank() == 1, "segment_ids must be 1-D tensor");
+ LUCI_ASSERT(segment_shape.dim(0).value() == input_shape.dim(0).value(),
+ "segment_ids size must be equal to the size of data's first dimension");
+
+ auto ids_shape_value = loco::must_cast<luci::CircleConst *>(node->segment_ids());
+
+ std::vector<int64_t> vect_ids;
+
+ if (ids_shape_value->dtype() == loco::DataType::S32)
+ vect_ids = vector_from_constant<loco::DataType::S32>(ids_shape_value);
+
+ LUCI_ASSERT(std::is_sorted(vect_ids.begin(), vect_ids.end()),
+ "segment_ids values should be sorted")
+
+ loco::TensorShape output_shape;
+
+ output_shape.rank(input_shape.rank());
+
+ for (uint32_t i = 1; i < input_shape.rank(); ++i)
+ output_shape.dim(i) = input_shape.dim(i);
+
+ output_shape.dim(0) = vect_ids.back() + 1;
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleSelect *node) final
+ {
+ auto t_shape = loco::shape_get(node->t()).as<loco::TensorShape>();
+ assert(t_shape == loco::shape_get(node->e()).as<loco::TensorShape>());
+
+ // condition shape validation
+ auto c_shape = loco::shape_get(node->condition()).as<loco::TensorShape>();
+ if (c_shape.rank() != t_shape.rank())
+ {
+ if (c_shape.rank() != 0 && c_shape.rank() != 1)
+ INTERNAL_EXN_V("CircleSelect condition rank is not 0 nor 1: ", c_shape.rank());
+
+ if (c_shape.rank() == 1)
+ {
+ if (c_shape.dim(0).value() != t_shape.dim(0).value())
+ INTERNAL_EXN("CircleSelect condition dim(0) should match with t.dim(0)");
+ }
+ }
+
+ return loco::NodeShape{t_shape};
+ }
- auto output_shape = broadcast_shape(x_shape, y_shape);
+ loco::NodeShape visit(const luci::CircleSelectV2 *node) final
+ {
+ auto c_shape = loco::shape_get(node->condition()).as<loco::TensorShape>();
+ auto t_shape = loco::shape_get(node->t()).as<loco::TensorShape>();
+ auto e_shape = loco::shape_get(node->e()).as<loco::TensorShape>();
+
+ // validate ability to broadcast shapes to each other
+ auto b_shape = broadcast_shape(broadcast_shape(c_shape, t_shape), e_shape);
+ return loco::NodeShape{b_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleShape *node) final
+ {
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+
+ loco::TensorShape output_shape;
+
+ output_shape.rank(1);
+ output_shape.dim(0) = input_shape.rank();
return loco::NodeShape{output_shape};
}
- // TODO CircleTanh
+ loco::NodeShape visit(const luci::CircleSin *node) final { return use_x(node); }
- /// @brief Returns output shape of transpose. Use loco::ConstGen and luci::CircleConst for ConstT.
- template <class ConstT>
- loco::TensorShape output_shape_of_transpose(loco::TensorShape input_shape,
- const ConstT *perm_node)
+ loco::NodeShape visit(const luci::CircleSlice *node) final
{
+ const loco::DataType S32 = loco::DataType::S32;
+ const loco::DataType S64 = loco::DataType::S64;
+
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+
+ auto const_begin = loco::must_cast<luci::CircleConst *>(node->begin());
+ auto const_size = loco::must_cast<luci::CircleConst *>(node->size());
+
loco::TensorShape output_shape;
- output_shape.rank(input_shape.rank());
+ std::vector<int64_t> vect_begin; // to hold both S32/S64, we use int64_t
+ std::vector<int64_t> vect_size;
- assert(perm_node->dtype() == loco::DataType::S32);
- assert(input_shape.rank() == perm_node->template size<loco::DataType::S32>());
+ if (const_begin->dtype() == S32)
+ vect_begin = vector_from_constant<S32>(const_begin);
+ else if (const_begin->dtype() == S64)
+ vect_begin = vector_from_constant<S64>(const_begin);
+ else
+ LUCI_ASSERT(false, "Only support int32/int64 for begin()");
- for (uint32_t out_axis = 0; out_axis < output_shape.rank(); out_axis++)
+ if (const_size->dtype() == S32)
+ vect_size = vector_from_constant<S32>(const_size);
+ else if (const_size->dtype() == S64)
+ vect_size = vector_from_constant<S64>(const_size);
+ else
+ LUCI_ASSERT(false, "Only support int32/int64 for size()");
+
+ assert(input_shape.rank() == vect_begin.size());
+ assert(input_shape.rank() == vect_size.size());
+
+ output_shape.rank(vect_begin.size());
+ for (uint32_t idx = 0; idx < vect_begin.size(); ++idx)
{
- auto in_axis = perm_node->template at<loco::DataType::S32>(out_axis);
- output_shape.dim(out_axis) = input_shape.dim(in_axis);
+ auto size = vect_size.at(idx);
+ if (size == -1)
+ {
+ size = input_shape.dim(idx).value() - vect_begin.at(idx);
+ }
+ output_shape.dim(idx) = size;
}
- return output_shape;
+ return loco::NodeShape{output_shape};
}
- loco::NodeShape visit(const luci::CircleTranspose *node) final
+ loco::NodeShape visit(const luci::CircleSoftmax *node) final { return use_logits(node); }
+
+ loco::NodeShape visit(const luci::CircleSpaceToBatchND *node) final
{
- auto input_shape = loco::shape_get(node->a()).as<loco::TensorShape>();
+ const loco::DataType S32 = loco::DataType::S32;
+
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ // Support only input rank is 3 and 4
+ assert(input_shape.rank() == 3 || input_shape.rank() == 4);
+
+ // Only support block_shape() with S32 type CircleConst for now
+ auto const_block_shape = loco::must_cast<luci::CircleConst *>(node->block_shape());
+ LUCI_ASSERT(const_block_shape->dtype() == S32, "Only support int32 block_shape");
+
+ // Only support paddings() with S32 type CircleConst for now
+ auto const_paddings = loco::must_cast<luci::CircleConst *>(node->paddings());
+ LUCI_ASSERT(const_paddings->dtype() == S32, "Only support int32 paddings");
+
+ auto const_block_shape_shape = loco::shape_get(const_block_shape).as<loco::TensorShape>();
+ auto const_paddings_shape = loco::shape_get(const_paddings).as<loco::TensorShape>();
+ assert(const_block_shape_shape.rank() == 1);
+ assert(const_paddings_shape.rank() == 2);
+
+ int32_t input_spatial_dim = input_shape.rank() - 2;
+ assert(const_block_shape_shape.dim(0) == input_spatial_dim);
+ assert(const_paddings_shape.dim(0) == input_spatial_dim);
+ assert(const_paddings_shape.dim(1) == 2);
+
+ // Check all values of block_shape >= 1
+ uint32_t ele_count = const_block_shape->size<S32>();
+ for (uint32_t e = 0; e < ele_count; ++e)
+ {
+ auto val = const_block_shape->at<S32>(e);
+ if (val < 1)
+ {
+ INTERNAL_EXN_V("All values of block_shape >= 1: ", e);
+ }
+ }
+
+ loco::TensorShape shape_output;
+
+ shape_output.rank(input_shape.rank());
+
+ int32_t output_batch_size = input_shape.dim(0).value();
+ for (int32_t dim = 0; dim < input_spatial_dim; ++dim)
+ {
+ int dim_size = input_shape.dim(dim + 1).value();
+ dim_size += const_paddings->at<S32>(dim * 2);
+ dim_size += const_paddings->at<S32>(dim * 2 + 1);
+ shape_output.dim(dim + 1) = dim_size / const_block_shape->at<S32>(dim);
+
+ assert(dim_size % const_block_shape->at<S32>(dim) == 0);
+ output_batch_size = output_batch_size * const_block_shape->at<S32>(dim);
+ }
+ shape_output.dim(0) = output_batch_size;
+ shape_output.dim(input_shape.rank() - 1) = input_shape.dim(input_shape.rank() - 1);
+
+ return loco::NodeShape{shape_output};
+ }
+
+ loco::NodeShape visit(const luci::CircleSpaceToDepth *node) final
+ {
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ LUCI_ASSERT(input_shape.rank() == 4, "Only input rank 4 is supported");
+
+ // Only data format NHWC is supported
+ int32_t height = input_shape.dim(1).value();
+ int32_t width = input_shape.dim(2).value();
+ int32_t depth = input_shape.dim(3).value();
+
+ int block_size = node->block_size();
+
+ if (block_size < 2)
+ INTERNAL_EXN("Block size must be >= 2");
+
+ if ((height % block_size) || (width % block_size))
+ {
+ INTERNAL_EXN("The input tensor's height and width must be divisible by block_size");
+ }
+
+ loco::TensorShape output_shape;
+ output_shape.rank(4);
+
+ output_shape.dim(0) = input_shape.dim(0).value();
+ output_shape.dim(1) = height / block_size;
+ output_shape.dim(2) = width / block_size;
+ output_shape.dim(3) = block_size * block_size * depth;
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleSparseToDense *node) final
+ {
+ loco::TensorShape shape;
+ {
+ LUCI_ASSERT(node->output_shape(), "dims input should not be nullptr");
+
+ auto output_shape_node = dynamic_cast<luci::CircleConst *>(node->output_shape());
+ if (output_shape_node != nullptr)
+ {
+ // Only support node with S32
+ LUCI_ASSERT(output_shape_node->dtype() == loco::DataType::S32,
+ "Only support int32 CircleConst");
+
+ if (output_shape_node->rank() != 1)
+ INTERNAL_EXN_V("Only support rank 1 CircleConst",
+ oops::to_uint32(output_shape_node->rank()));
+
+ shape.rank(output_shape_node->dim(0).value());
+
+ for (uint32_t axis = 0; axis < shape.rank(); ++axis)
+ {
+ shape.dim(axis) = output_shape_node->at<loco::DataType::S32>(axis);
+ }
+ }
+ else
+ {
+ shape = own_shape(node);
+ }
+ }
+
+ return loco::NodeShape{shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleSplit *node) final
+ {
+ // We'll set Split output as same as input so that SplitOut can handle it's own shape
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ return loco::NodeShape{input_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleSplitV *node) final
+ {
+ // We'll set SplitV output as same as input so that SplitOut can handle it's own shape
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ return loco::NodeShape{input_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleSqrt *node) final { return use_x(node); }
- auto canon_perm = dynamic_cast<loco::ConstGen *>(node->perm());
- auto circle_perm = dynamic_cast<luci::CircleConst *>(node->perm());
+ loco::NodeShape visit(const luci::CircleSquare *node) final { return use_x(node); }
- if (canon_perm)
+ loco::NodeShape visit(const luci::CircleSquaredDifference *node) final
+ {
+ return broadcast_xy(node);
+ }
+
+ loco::NodeShape visit(const luci::CircleStridedSlice *node) final
+ {
+ auto begin_node = dynamic_cast<luci::CircleConst *>(node->begin());
+ auto end_node = dynamic_cast<luci::CircleConst *>(node->end());
+ auto strides_node = dynamic_cast<luci::CircleConst *>(node->strides());
+
+ if (begin_node == nullptr || end_node == nullptr || strides_node == nullptr)
{
- return loco::NodeShape{output_shape_of_transpose(input_shape, canon_perm)};
+ return use_own(node);
}
- else if (circle_perm)
+
+ loco::TensorShape shape = infer_output_shape(node);
+ return loco::NodeShape{shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleSqueeze *node) final
+ {
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+
+ // TODO input shape may be unknown before runtime
+ std::vector<bool> do_squeeze(input_shape.rank(), false);
+ uint32_t num_squeezed = 0;
+
+ if (!node->squeeze_dims().empty())
{
- return loco::NodeShape{output_shape_of_transpose(input_shape, circle_perm)};
+ // SqueezeDims not empty, squeeze only dims specified
+ for (int32_t raw_dim : node->squeeze_dims())
+ {
+ int32_t dim = raw_dim < 0 ? raw_dim + input_shape.rank() : raw_dim;
+
+ if (dim < 0 || static_cast<uint32_t>(dim) >= input_shape.rank() ||
+ input_shape.dim(dim).value() != 1)
+ {
+ INTERNAL_EXN("invalid dimention specified to Squeeze");
+ }
+
+ if (!do_squeeze[dim])
+ ++num_squeezed;
+ do_squeeze[dim] = true;
+ }
}
else
- INTERNAL_EXN("perm of CircleTranspose should be either ConstGen or CircleConst");
+ {
+ // SqueezeDims empty, squeeze any dims with size == 1
+ for (uint32_t dim = 0; dim < input_shape.rank(); ++dim)
+ {
+ if (input_shape.dim(dim) == 1)
+ {
+ do_squeeze[dim] = true;
+ ++num_squeezed;
+ }
+ }
+ }
+
+ loco::TensorShape output_shape;
+ output_shape.rank(input_shape.rank() - num_squeezed);
+
+ for (uint32_t in_dim = 0, out_dim = 0; in_dim < input_shape.rank(); ++in_dim)
+ {
+ if (!do_squeeze[in_dim])
+ {
+ output_shape.dim(out_dim++) = input_shape.dim(in_dim);
+ }
+ }
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleSub *node) final { return broadcast_xy(node); }
+
+ loco::NodeShape visit(const luci::CircleSum *node) final
+ {
+ auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims());
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleTanh *node) final { return use_x(node); }
+
+ loco::NodeShape visit(const luci::CircleTile *node) final
+ {
+ const loco::DataType S32 = loco::DataType::S32;
+
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ auto multiples = loco::must_cast<luci::CircleConst *>(node->multiples());
+
+ // TODO support non-const case
+ // TODO support S64 type
+ LUCI_ASSERT(multiples->dtype() == S32, "Only support int32 multiples");
+ LUCI_ASSERT(multiples->rank() == 1, "multiples should be rank 1")
+
+ uint32_t n = multiples->dim(0).value();
+
+ LUCI_ASSERT(n == input_shape.rank(), "length of multiples should be the same with input rank");
+
+ loco::TensorShape output_shape;
+
+ output_shape.rank(input_shape.rank());
+ for (uint32_t ni = 0; ni < n; ++ni)
+ {
+ int32_t multiple = multiples->at<S32>(ni);
+ output_shape.dim(ni) = input_shape.dim(ni).value() * static_cast<uint32_t>(multiple);
+ }
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleTopKV2 *node) final
+ {
+ // set shape of this node as same as input
+ const auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ return loco::NodeShape{input_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleTranspose *node) final
+ {
+ auto input_shape = loco::shape_get(node->a()).as<loco::TensorShape>();
+
+ auto perm_node = loco::must_cast<luci::CircleConst *>(node->perm());
+
+ loco::TensorShape output_shape;
+ output_shape.rank(input_shape.rank());
+
+ assert(perm_node->dtype() == loco::DataType::S32);
+ assert(input_shape.rank() == perm_node->template size<loco::DataType::S32>());
+
+ for (uint32_t out_axis = 0; out_axis < output_shape.rank(); out_axis++)
+ {
+ auto in_axis = perm_node->template at<loco::DataType::S32>(out_axis);
+ output_shape.dim(out_axis) = input_shape.dim(in_axis);
+ }
+
+ return output_shape;
}
loco::NodeShape visit(const luci::CircleTransposeConv *node) final
{
// TransposeConv's output shape is written in its 'inputSizes' argument
- auto input_sizes_const = dynamic_cast<luci::CircleConst *>(node->inputSizes());
- LUCI_ASSERT(input_sizes_const,
- "Only support when CircleTransposeConv's inputSizes is CircleConst")
+ auto input_sizes_const = loco::must_cast<luci::CircleConst *>(node->inputSizes());
+ // TODO support non-const type
LUCI_ASSERT(input_sizes_const->dtype() == loco::DataType::S32, "Only support S32 dtype")
LUCI_ASSERT(input_sizes_const->rank() == 1 && input_sizes_const->dim(0).value() == 4,
"Only support rank 1 with 4 entries")
@@ -855,7 +1836,115 @@ public:
return loco::NodeShape{shape};
}
+ loco::NodeShape visit(const luci::CircleUnpack *node) final
+ {
+ // CircleUnpack provides list(array) of Tensors which has one less dimension of the input
+ // We'll set shape of CircleUnpack to shape of actual outputs
+ // TODO fix this if any problem rises
+ auto value_shape = loco::shape_get(node->value()).as<loco::TensorShape>();
+
+ auto axis = node->axis();
+ auto num = node->num();
+ auto rank = static_cast<int32_t>(value_shape.rank());
+
+ if (rank == 0)
+ {
+ // Unknown shape
+ return use_own(node);
+ }
+
+ LUCI_ASSERT(-rank <= axis && axis < rank, "Axis is out of range");
+
+ if (axis < 0)
+ axis += rank;
+
+ LUCI_ASSERT(num == static_cast<int32_t>(value_shape.dim(axis).value()),
+ "num, axis maybe incorrect");
+
+ loco::TensorShape output_shape;
+ output_shape.rank(rank - 1);
+
+ for (int32_t i = 0, o = 0; i < rank; ++i)
+ {
+ if (i != axis)
+ output_shape.dim(o++) = value_shape.dim(i);
+ }
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleWhere *node) final { return use_own(node); }
+
+ loco::NodeShape visit(const luci::CircleWhile *node) final
+ {
+ // Shape of CircleWhile is not used. Just use input 0
+ assert(node->arity() > 0);
+ const auto input_shape = loco::shape_get(node->input(0)).as<loco::TensorShape>();
+ return loco::NodeShape{input_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleZerosLike *node) final
+ {
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+
+ return loco::NodeShape{input_shape};
+ }
+
// Circle Only
+ loco::NodeShape visit(const luci::CircleBCQFullyConnected *node) final
+ {
+ loco::TensorShape out_shape;
+
+ auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
+ auto weights_clusters = loco::must_cast<luci::CircleConst *>(node->weights_clusters());
+
+ LUCI_ASSERT(input_shape.rank() == 2, "Input rank of BCQFullyConnected should be 2");
+
+ int32_t qbits_sum = 0;
+ for (uint32_t i = 0; i < weights_clusters->dim(0).value(); ++i)
+ {
+ qbits_sum += weights_clusters->at<loco::DataType::S32>(i * 2 + 1);
+ }
+
+ out_shape.rank(2);
+ out_shape.dim(0) = qbits_sum;
+ out_shape.dim(1) = input_shape.dim(1);
+
+ return loco::NodeShape{out_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleBCQGather *node) final
+ {
+ loco::TensorShape input_shape;
+ loco::TensorShape output_shape;
+
+ const auto input_binary_shape = loco::shape_get(node->input_binary()).as<loco::TensorShape>();
+ const auto indices_shape = loco::shape_get(node->indices()).as<loco::TensorShape>();
+ auto axis = node->axis();
+
+ auto input_clusters = loco::must_cast<luci::CircleConst *>(node->input_clusters());
+ auto qbits_sum = 0;
+ for (uint32_t i = 0; i < input_clusters->dim(0).value(); ++i)
+ {
+ qbits_sum += input_clusters->at<loco::DataType::S32>(i * 2 + 1);
+ }
+
+ input_shape.rank(2);
+ input_shape.dim(0) = qbits_sum;
+ input_shape.dim(1) = input_binary_shape.dim(1).value() * 32;
+
+ output_shape.rank(input_shape.rank() - 1 + indices_shape.rank());
+ int32_t outdim_index = 0;
+ for (int32_t i = 0; i < axis; ++i)
+ output_shape.dim(outdim_index++) = input_shape.dim(i);
+ for (uint32_t i = 0; i < indices_shape.rank(); ++i)
+ output_shape.dim(outdim_index++) = indices_shape.dim(i);
+ for (uint32_t i = axis + 1; i < input_shape.rank(); ++i)
+ output_shape.dim(outdim_index++) = input_shape.dim(i);
+
+ return loco::NodeShape{output_shape};
+ }
+
loco::NodeShape visit(const luci::CircleInstanceNorm *node) final
{
auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>();
@@ -877,9 +1966,230 @@ public:
loco::NodeShape visit(const luci::CircleOutput *node) final
{
- auto from_shape = loco::shape_get(node->from()).as<loco::TensorShape>();
+ auto graph_outputs = node->graph()->outputs();
+ auto graph_output = graph_outputs->at(node->index());
+ auto output_shape = graph_output->shape();
+
+ return loco::NodeShape{*output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleOutputDummy *node) final { return use_own(node); }
+
+ loco::NodeShape visit(const luci::CircleOutputExclude *node) final { return use_own(node); }
+
+ loco::NodeShape visit(const luci::CircleCustomOut *node) final { return use_own(node); }
+
+ loco::NodeShape visit(const luci::CircleIfOut *node) final
+ {
+ /**
+ * @note IF operator type and shape are that of the "then" and "else"
+ * Graph Outputs.
+ */
+ auto circle_if = dynamic_cast<const luci::CircleIf *>(node->input());
+ if (circle_if == nullptr)
+ {
+ INTERNAL_EXN("CircleIf IR is not configured correctly");
+ }
+
+ auto index = node->index();
+ auto then_graph = circle_if->then_graph();
+ auto else_graph = circle_if->else_graph();
+ assert(then_graph != nullptr);
+ assert(else_graph != nullptr);
+
+ // shape and type are assumed to be same
+ // these are checked at post_import_graph() in Import
+ auto then_outputs = loco::output_nodes(then_graph);
+ auto else_outputs = loco::output_nodes(else_graph);
+ assert(then_outputs.size() == else_outputs.size());
+ assert(index < static_cast<int32_t>(then_outputs.size()));
+
+ auto then_out = loco::must_cast<luci::CircleOutput *>(then_outputs.at(index));
+ auto else_out = loco::must_cast<luci::CircleOutput *>(else_outputs.at(index));
+
+ auto then_graph_outputs = then_graph->outputs(); // loco::GraphOutput items
+ auto else_graph_outputs = else_graph->outputs();
+ assert(then_graph_outputs->size() == else_graph_outputs->size());
+
+ auto then_graph_output = then_graph_outputs->at(then_out->index());
+ auto else_graph_output = else_graph_outputs->at(else_out->index());
+ (void)else_graph_output; // make compiler happy for unused variable warnings
+ assert(*then_graph_output->shape() == *else_graph_output->shape());
+
+ return loco::NodeShape{*then_graph_output->shape()};
+ }
+
+ loco::NodeShape visit(const luci::CircleSplitOut *node) final
+ {
+ const loco::DataType S32 = loco::DataType::S32;
+
+ auto split = dynamic_cast<const luci::CircleSplit *>(node->input());
+ if (split == nullptr)
+ INTERNAL_EXN("CircleSplit IR is not configured correctly");
+
+ loco::NodeShape unknown;
+
+ auto split_shape = loco::shape_get(split).as<loco::TensorShape>();
+
+ auto split_dim = dynamic_cast<const luci::CircleConst *>(split->split_dim());
+ if (split_dim == nullptr)
+ return unknown; // we need CircleConst for split_dim
+ LUCI_ASSERT(split_dim->dtype() == S32, "Only support int32 for split_dim");
+
+ assert(split_dim->size<S32>() == 1);
+ auto split_dim_axis = split_dim->at<S32>(0);
+ if (split_dim_axis < 0)
+ split_dim_axis += split_shape.rank();
+
+ auto split_dim_value = split_shape.dim(split_dim_axis).value();
+ assert(split_dim_value % split->num_split() == 0);
+ const int split_depth = split_dim_value / split->num_split();
+
+ loco::TensorShape output_shape = split_shape;
+
+ // All shapes are equally same
+ output_shape.dim(split_dim_axis) = loco::Dimension(split_depth);
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleSplitVOut *node) final
+ {
+ const loco::DataType S32 = loco::DataType::S32;
+
+ auto split = dynamic_cast<const luci::CircleSplitV *>(node->input());
+ if (split == nullptr)
+ INTERNAL_EXN("CircleSplit IR is not configured correctly");
+
+ loco::NodeShape unknown;
+
+ auto split_shape = loco::shape_get(split).as<loco::TensorShape>();
+
+ auto size_splits = dynamic_cast<const luci::CircleConst *>(split->size_splits());
+ if (size_splits == nullptr)
+ return unknown; // we need CircleConst for size_splits
+ LUCI_ASSERT(size_splits->dtype() == S32, "Only support int32 for size_splits");
+
+ auto split_dim = dynamic_cast<const luci::CircleConst *>(split->split_dim());
+ if (split_dim == nullptr)
+ return unknown; // we need CircleConst for split_dim
+ LUCI_ASSERT(split_dim->dtype() == S32, "Only support int32 for split_dim");
+
+ // fetch axis
+ assert(split_dim->size<S32>() == 1);
+ auto split_dim_axis = split_dim->at<S32>(0);
+ if (split_dim_axis < 0)
+ split_dim_axis += split_shape.rank();
+
+ // interpret size_splits values
+ int32_t size_splits_count = static_cast<int32_t>(size_splits->size<S32>());
+ assert(size_splits_count == split->num_split());
+
+ int64_t minus_one_count = 0, size_splits_sum = 0;
+ for (int32_t idx = 0; idx < size_splits_count; ++idx)
+ {
+ auto size = size_splits->at<S32>(idx);
+ assert(size >= -1);
+ if (size == -1)
+ ++minus_one_count;
+ else
+ size_splits_sum += size;
+ }
+ if (minus_one_count > 1)
+ INTERNAL_EXN("CircleSplitV size_splits has more than two -1 values");
+
+ // calcuate this SplitVOut shape
+ auto input_size = split_shape.dim(split_dim_axis).value();
+ assert(size_splits_sum <= input_size);
+
+ auto index_this = node->index();
+ assert(0 <= index_this && index_this < split->num_split());
+ auto split_depth = size_splits->at<S32>(index_this);
+ if (split_depth == -1)
+ split_depth = input_size - size_splits_sum;
+
+ loco::TensorShape output_shape = split_shape;
+
+ output_shape.dim(split_dim_axis) = loco::Dimension(split_depth);
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleTopKV2Out *node) final
+ {
+ const loco::DataType S32 = loco::DataType::S32;
+
+ auto topkv2 = dynamic_cast<const luci::CircleTopKV2 *>(node->input());
+ if (topkv2 == nullptr)
+ INTERNAL_EXN("CircleSplit IR is not configured correctly");
+
+ // shape of topkv2 is same as topkv2->input()
+ auto input_shape = loco::shape_get(topkv2).as<loco::TensorShape>();
+
+ auto node_k = loco::must_cast<const luci::CircleConst *>(topkv2->k());
+ LUCI_ASSERT(node_k->dtype() == S32, "Only support Int32");
+ assert(node_k->size<S32>() == 1);
+
+ loco::TensorShape output_shape;
+
+ output_shape.rank(input_shape.rank());
+ for (uint32_t idx = 0; idx < input_shape.rank() - 1; ++idx)
+ {
+ output_shape.dim(idx) = input_shape.dim(idx);
+ }
+ output_shape.dim(input_shape.rank() - 1) = node_k->at<S32>(0);
+
+ return loco::NodeShape{output_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleUnpackOut *node) final
+ {
+ auto unpack = dynamic_cast<const luci::CircleUnpack *>(node->input());
+ if (unpack == nullptr)
+ {
+ INTERNAL_EXN("CircleUnpack IR is not configured correctly");
+ }
+
+ auto unpack_shape = loco::shape_get(unpack).as<loco::TensorShape>();
+
+ return loco::NodeShape{unpack_shape};
+ }
+
+ loco::NodeShape visit(const luci::CircleWhileOut *node) final
+ {
+ /**
+ * @note WHILE operator's shape is the same with the "cond"
+ * Graph input.
+ */
+ auto circle_while = dynamic_cast<const luci::CircleWhile *>(node->input());
+ if (circle_while == nullptr)
+ {
+ INTERNAL_EXN("CircleWhile IR is not configured correctly");
+ }
+
+ auto index = node->index();
+ auto cond_graph = circle_while->cond_graph();
+ assert(cond_graph != nullptr);
+
+ // Assumption: the index of CircleWhileOut matches with the index of input nodes returned by
+ // loco::input_nodes
+ auto cond_inputs = loco::input_nodes(cond_graph);
+ auto cond_in = loco::must_cast<luci::CircleInput *>(cond_inputs.at(index));
+
+ auto cond_graph_inputs = cond_graph->inputs();
+ auto cond_graph_input = cond_graph_inputs->at(cond_in->index());
- return loco::NodeShape{from_shape};
+ auto cond_graph_input_shape = *cond_graph_input->shape();
+ auto this_shape = own_shape(node);
+
+ if (!(this_shape == cond_graph_input_shape))
+ {
+ LOGGER(l);
+ WARN(l) << "Warning: CircleWhileOut '" << node->name() << "' shape mispatch " << this_shape
+ << " vs " << cond_graph_input_shape;
+ }
+
+ return loco::NodeShape{this_shape};
}
};
@@ -895,11 +2205,30 @@ bool CircleShapeInferenceRule::recognize(const loco::Dialect *d) const
bool CircleShapeInferenceRule::infer(const loco::Node *node, loco::NodeShape &shape) const
{
+ LOGGER(l);
+
assert(node->dialect() == CircleDialect::get());
- assert(dynamic_cast<const CircleNode *>(node) != nullptr);
ShapeInferenceAlgorithm alg;
- shape = dynamic_cast<const CircleNode *>(node)->accept(&alg);
+ auto circle_node = loco::must_cast<const CircleNode *>(node);
+
+ bool is_shape_undefined = (circle_node->shape_status() == ShapeStatus::UNDEFINED);
+ bool is_shape_none = (circle_node->shape_status() == ShapeStatus::NOSHAPE);
+ bool is_scalar = (circle_node->rank() == 0);
+
+ if (is_shape_undefined)
+ shape = circle_node->accept(&alg);
+ else
+ {
+ if (is_shape_none || is_scalar)
+ shape = own_shape(circle_node);
+ else
+ shape = circle_node->accept(&alg);
+ }
+
+ VERBOSE(l, 1) << "[luci] shape: " << circle_node->name();
+ VERBOSE(l, 1) << " own_shape: " << own_shape(circle_node)
+ << " -> infer: " << shape.as<loco::TensorShape>();
return true;
}
diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp
index 0374251a0..ac27db3bd 100644
--- a/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp
+++ b/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp
@@ -26,6 +26,8 @@
#include <loco/Service/CanonicalShapeInferenceRule.h>
#include <loco/Service/MultiDialectShapeInferenceRule.h>
+#include <oops/InternalExn.h>
+
#include <gtest/gtest.h>
#include <memory>
@@ -51,38 +53,39 @@ TEST(CircleShapeInferenceRuleTest, minimal_with_CircleRelu)
{
// Create a simple network
luci::test::TestGraph graph;
- auto tfl_node = graph.append<luci::CircleRelu>(graph.pull);
- graph.complete(tfl_node);
+ auto relu_node = graph.append<luci::CircleRelu>(graph.input_node);
+ graph.complete(relu_node);
// set shape
{
- graph.pull->rank(2);
- graph.pull->dim(0) = 3;
- graph.pull->dim(1) = 4;
+ graph.input_node->rank(2);
+ graph.input_node->dim(0) = 3;
+ graph.input_node->dim(1) = 4;
+
+ graph.output_node->rank(2);
+ graph.output_node->dim(0) = 3;
+ graph.output_node->dim(1) = 4;
+
+ luci::test::graph_input_shape(graph.input_node);
+ luci::test::graph_output_shape(graph.output_node);
}
// pre-check
- ASSERT_FALSE(loco::shape_known(tfl_node));
+ ASSERT_FALSE(loco::shape_known(relu_node));
// shape inference
- luci::CircleShapeInferenceRule tfl_rule;
- loco::CanonicalShapeInferenceRule canonical_rule;
- loco::MultiDialectShapeInferenceRule rules;
-
- rules.bind(loco::CanonicalDialect::get(), &canonical_rule)
- .bind(luci::CircleDialect::get(), &tfl_rule);
-
- loco::apply(&rules).to(graph.g.get());
+ while (shape_pass(graph.graph()) == true)
+ ;
// Verify
{
- ASSERT_TRUE(loco::shape_known(tfl_node));
- ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor);
+ ASSERT_TRUE(loco::shape_known(relu_node));
+ ASSERT_EQ(loco::Domain::Tensor, loco::shape_get(relu_node).domain());
- auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>();
- ASSERT_EQ(shape.rank(), 2);
- ASSERT_EQ(shape.dim(0), 3);
- ASSERT_EQ(shape.dim(1), 4);
+ auto shape = loco::shape_get(relu_node).as<loco::TensorShape>();
+ ASSERT_EQ(2, shape.rank());
+ ASSERT_EQ(3, shape.dim(0));
+ ASSERT_EQ(4, shape.dim(1));
}
}
@@ -91,85 +94,92 @@ TEST(CircleShapeInferenceRuleTest, minimal_with_CircleRelu)
TEST(CircleShapeInferenceRuleTest, avgpool2d_valid)
{
luci::test::TestGraph graph;
- auto tfl_node = graph.append<luci::CircleAveragePool2D>(graph.pull);
+ auto avg_node = graph.append<luci::CircleAveragePool2D>(graph.input_node);
graph.complete();
- auto pull = graph.pull;
+ auto input_node = graph.input_node;
{
- pull->shape({1, 4, 3, 1});
+ input_node->shape({1, 4, 3, 1});
+ luci::test::graph_input_shape(input_node);
+ }
+ auto output_node = graph.output_node;
+ {
+ output_node->shape({1, 2, 1, 1});
+ luci::test::graph_output_shape(output_node);
}
// setting CircleAveragePool2D
{
- tfl_node->filter()->h(2);
- tfl_node->filter()->w(2);
- tfl_node->stride()->h(2);
- tfl_node->stride()->w(2);
- tfl_node->fusedActivationFunction(luci::FusedActFunc::NONE);
- tfl_node->padding(luci::Padding::VALID);
+ avg_node->filter()->h(2);
+ avg_node->filter()->w(2);
+ avg_node->stride()->h(2);
+ avg_node->stride()->w(2);
+ avg_node->fusedActivationFunction(luci::FusedActFunc::NONE);
+ avg_node->padding(luci::Padding::VALID);
}
- ASSERT_FALSE(loco::shape_known(tfl_node));
+ ASSERT_FALSE(loco::shape_known(avg_node));
// shape inference
- luci::CircleShapeInferenceRule tfl_rule;
- loco::CanonicalShapeInferenceRule canonical_rule;
- loco::MultiDialectShapeInferenceRule rules;
-
- rules.bind(loco::CanonicalDialect::get(), &canonical_rule)
- .bind(luci::CircleDialect::get(), &tfl_rule);
-
- loco::apply(&rules).to(graph.g.get());
+ while (shape_pass(graph.graph()) == true)
+ ;
// Verify
{
- ASSERT_TRUE(loco::shape_known(tfl_node));
- ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor);
-
- auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>();
- ASSERT_EQ(shape.rank(), 4);
- ASSERT_EQ(shape.dim(0).value(), 1);
- ASSERT_EQ(shape.dim(1).value(), 2);
- ASSERT_EQ(shape.dim(2).value(), 1);
- ASSERT_EQ(shape.dim(3).value(), 1);
+ ASSERT_TRUE(loco::shape_known(avg_node));
+ ASSERT_EQ(loco::Domain::Tensor, loco::shape_get(avg_node).domain());
+
+ auto shape = loco::shape_get(avg_node).as<loco::TensorShape>();
+ ASSERT_EQ(4, shape.rank());
+ ASSERT_EQ(1, shape.dim(0).value());
+ ASSERT_EQ(2, shape.dim(1).value());
+ ASSERT_EQ(1, shape.dim(2).value());
+ ASSERT_EQ(1, shape.dim(3).value());
}
}
TEST(CircleShapeInferenceRuleTest, avgpool2d_same)
{
luci::test::TestGraph graph;
- auto tfl_node = graph.append<luci::CircleAveragePool2D>(graph.pull);
+ auto avg_node = graph.append<luci::CircleAveragePool2D>(graph.input_node);
graph.complete();
- auto pull = graph.pull;
+ auto input_node = graph.input_node;
{
- pull->shape({1, 4, 3, 1});
+ input_node->shape({1, 4, 3, 1});
+ luci::test::graph_input_shape(input_node);
+ }
+ auto output_node = graph.output_node;
+ {
+ output_node->shape({1, 2, 2, 1});
+ luci::test::graph_output_shape(output_node);
}
// setting CircleAveragePool2D
{
- tfl_node->filter()->h(2);
- tfl_node->filter()->w(2);
- tfl_node->stride()->h(2);
- tfl_node->stride()->w(2);
- tfl_node->fusedActivationFunction(luci::FusedActFunc::NONE);
- tfl_node->padding(luci::Padding::SAME);
+ avg_node->filter()->h(2);
+ avg_node->filter()->w(2);
+ avg_node->stride()->h(2);
+ avg_node->stride()->w(2);
+ avg_node->fusedActivationFunction(luci::FusedActFunc::NONE);
+ avg_node->padding(luci::Padding::SAME);
}
- ASSERT_FALSE(loco::shape_known(tfl_node));
+ ASSERT_FALSE(loco::shape_known(avg_node));
// shape inference
- shape_pass(graph.g.get());
+ while (shape_pass(graph.graph()) == true)
+ ;
// Verify
{
- ASSERT_TRUE(loco::shape_known(tfl_node));
- ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor);
-
- auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>();
- ASSERT_EQ(shape.rank(), 4);
- ASSERT_EQ(shape.dim(0).value(), 1);
- ASSERT_EQ(shape.dim(1).value(), 2);
- ASSERT_EQ(shape.dim(2).value(), 2);
- ASSERT_EQ(shape.dim(3).value(), 1);
+ ASSERT_TRUE(loco::shape_known(avg_node));
+ ASSERT_EQ(loco::Domain::Tensor, loco::shape_get(avg_node).domain());
+
+ auto shape = loco::shape_get(avg_node).as<loco::TensorShape>();
+ ASSERT_EQ(4, shape.rank());
+ ASSERT_EQ(1, shape.dim(0).value());
+ ASSERT_EQ(2, shape.dim(1).value());
+ ASSERT_EQ(2, shape.dim(2).value());
+ ASSERT_EQ(1, shape.dim(3).value());
}
}
@@ -186,47 +196,51 @@ TEST(CircleShapeInferenceRuleTest, TFAdd_shapeinf_different)
{
auto g = loco::make_graph();
- auto x_node = g->nodes()->create<loco::Pull>();
+ auto x_node = g->nodes()->create<luci::CircleInput>();
{
x_node->rank(3);
x_node->dim(0) = 2;
x_node->dim(1) = 1;
x_node->dim(2) = 5;
}
- auto y_node = g->nodes()->create<loco::Pull>();
+ auto y_node = g->nodes()->create<luci::CircleInput>();
{
y_node->rank(2);
y_node->dim(0) = 3;
y_node->dim(1) = 5;
}
- auto tfl_node = g->nodes()->create<luci::CircleAdd>();
+ auto add_node = g->nodes()->create<luci::CircleAdd>();
{
- tfl_node->x(x_node);
- tfl_node->y(y_node);
+ add_node->x(x_node);
+ add_node->y(y_node);
}
- auto push_node = g->nodes()->create<loco::Push>();
+ auto output_node = g->nodes()->create<luci::CircleOutput>();
{
- push_node->from(tfl_node);
+ output_node->from(add_node);
}
auto x_input = g->inputs()->create();
{
x_input->name("x");
- loco::link(x_input, x_node);
+ luci::link(x_input, x_node);
}
auto y_input = g->inputs()->create();
{
y_input->name("y");
- loco::link(y_input, y_node);
+ luci::link(y_input, y_node);
}
auto output = g->outputs()->create();
{
output->name("output");
- loco::link(output, push_node);
+ luci::link(output, output_node);
}
+ luci::test::graph_input_shape(x_node);
+ luci::test::graph_input_shape(y_node);
+ luci::test::graph_output_shape(output_node);
+
// pre-check
- ASSERT_FALSE(loco::shape_known(tfl_node));
+ ASSERT_FALSE(loco::shape_known(add_node));
// shape inference
while (shape_pass(g.get()) == true)
@@ -234,14 +248,14 @@ TEST(CircleShapeInferenceRuleTest, TFAdd_shapeinf_different)
// Verify
{
- ASSERT_TRUE(loco::shape_known(tfl_node));
- ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor);
-
- auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>();
- ASSERT_EQ(shape.rank(), 3);
- ASSERT_EQ(shape.dim(0), 2);
- ASSERT_EQ(shape.dim(1), 3);
- ASSERT_EQ(shape.dim(2), 5);
+ ASSERT_TRUE(loco::shape_known(add_node));
+ ASSERT_EQ(loco::Domain::Tensor, loco::shape_get(add_node).domain());
+
+ auto shape = loco::shape_get(add_node).as<loco::TensorShape>();
+ ASSERT_EQ(3, shape.rank());
+ ASSERT_EQ(2, shape.dim(0));
+ ASSERT_EQ(3, shape.dim(1));
+ ASSERT_EQ(5, shape.dim(2));
}
}
@@ -249,10 +263,10 @@ TEST(CircleShapeInferenceRuleTest, CircleTranspose_simple)
{
luci::test::ExampleGraph<luci::test::ExampleGraphType::CircleTranspose> g;
- g.pull->rank(3);
- g.pull->dim(0) = 3;
- g.pull->dim(1) = 8;
- g.pull->dim(2) = 1;
+ g.input_node->rank(3);
+ g.input_node->dim(0) = 3;
+ g.input_node->dim(1) = 8;
+ g.input_node->dim(2) = 1;
g.const_perm->dtype(loco::DataType::S32);
g.const_perm->rank(1);
@@ -262,6 +276,9 @@ TEST(CircleShapeInferenceRuleTest, CircleTranspose_simple)
g.const_perm->at<loco::DataType::S32>(1) = 2;
g.const_perm->at<loco::DataType::S32>(2) = 0;
+ luci::test::graph_input_shape(g.input_node);
+ luci::test::graph_output_shape(g.output_node);
+
// pre-check
ASSERT_FALSE(loco::shape_known(g.transpose_node));
@@ -274,9 +291,336 @@ TEST(CircleShapeInferenceRuleTest, CircleTranspose_simple)
ASSERT_TRUE(loco::shape_known(g.transpose_node));
auto shape = loco::shape_get(g.transpose_node).as<loco::TensorShape>();
- ASSERT_EQ(shape.rank(), 3);
- ASSERT_EQ(shape.dim(0), 8);
- ASSERT_EQ(shape.dim(1), 1);
- ASSERT_EQ(shape.dim(2), 3);
+ ASSERT_EQ(3, shape.rank());
+ ASSERT_EQ(8, shape.dim(0));
+ ASSERT_EQ(1, shape.dim(1));
+ ASSERT_EQ(3, shape.dim(2));
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleSqueeze)
+{
+ luci::test::TestGraph graph;
+ auto squeeze_node = graph.append<luci::CircleSqueeze>(graph.input_node);
+ graph.complete();
+
+ auto input_node = graph.input_node;
+ {
+ input_node->shape({1, 4, 3, 1});
+ }
+ auto output_node = graph.output_node;
+ {
+ output_node->shape({4, 3, 1});
+ }
+
+ luci::test::graph_input_shape(input_node);
+ luci::test::graph_output_shape(output_node);
+
+ squeeze_node->squeeze_dims({0});
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(squeeze_node));
+
+ // shape inference
+ while (shape_pass(graph.graph()) == true)
+ ;
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(squeeze_node));
+
+ auto shape = loco::shape_get(squeeze_node).as<loco::TensorShape>();
+ ASSERT_EQ(3, shape.rank());
+ ASSERT_EQ(4, shape.dim(0));
+ ASSERT_EQ(3, shape.dim(1));
+ ASSERT_EQ(1, shape.dim(2));
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleExpandDims)
+{
+ luci::test::TestGraph graph;
+ auto axis = graph.append<luci::CircleConst>();
+ axis->dtype(loco::DataType::S32);
+ axis->rank(0);
+ axis->size<loco::DataType::S32>(1);
+ axis->at<loco::DataType::S32>(0) = 1;
+
+ auto expand_dims = graph.append<luci::CircleExpandDims>(graph.input_node, axis);
+ graph.complete();
+
+ auto input_node = graph.input_node;
+ {
+ input_node->shape({4, 3});
+ }
+
+ auto output_node = graph.output_node;
+ {
+ output_node->from(expand_dims);
+ }
+
+ luci::test::graph_input_shape(input_node);
+ luci::test::graph_output_shape(output_node);
+
+ // shape inference
+ while (shape_pass(graph.graph()))
+ ;
+
+ // validation
+ {
+ ASSERT_TRUE(loco::shape_known(expand_dims));
+
+ auto shape = loco::shape_get(expand_dims).as<loco::TensorShape>();
+
+ ASSERT_EQ(3, shape.rank());
+ ASSERT_EQ(4, shape.dim(0));
+ ASSERT_EQ(1, shape.dim(1));
+ ASSERT_EQ(3, shape.dim(2));
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleSqueezeAll)
+{
+ luci::test::TestGraph graph;
+ auto squeeze_node = graph.append<luci::CircleSqueeze>(graph.input_node);
+ graph.complete();
+
+ auto input_node = graph.input_node;
+ {
+ input_node->shape({1, 4, 3, 1});
+ }
+ auto output_node = graph.output_node;
+ {
+ input_node->shape({4, 3});
+ }
+
+ luci::test::graph_input_shape(input_node);
+ luci::test::graph_output_shape(output_node);
+
+ squeeze_node->squeeze_dims({});
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(squeeze_node));
+
+ // shape inference
+ while (shape_pass(graph.graph()) == true)
+ ;
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(squeeze_node));
+
+ auto shape = loco::shape_get(squeeze_node).as<loco::TensorShape>();
+ ASSERT_EQ(2, shape.rank());
+ ASSERT_EQ(4, shape.dim(0));
+ ASSERT_EQ(3, shape.dim(1));
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleGatherNd_simple)
+{
+ luci::test::TestGraph graph;
+ auto indices_const = graph.append<luci::CircleConst>();
+ auto gather_nd_node = graph.append<luci::CircleGatherNd>(graph.input_node, indices_const);
+ graph.complete();
+
+ {
+ auto input_node = graph.input_node;
+ input_node->shape({1, 4, 4, 3});
+ luci::test::graph_input_shape(input_node);
+ }
+ {
+ auto output_node = graph.output_node;
+ output_node->shape({1, 2, 2, 3});
+ luci::test::graph_output_shape(output_node);
+ }
+
+ {
+ indices_const->shape({1, 2, 3});
+ }
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(gather_nd_node));
+
+ // shape inference
+ while (shape_pass(graph.graph()) == true)
+ ;
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(gather_nd_node));
+
+ auto shape = loco::shape_get(gather_nd_node).as<loco::TensorShape>();
+ ASSERT_EQ(3, shape.rank());
+ ASSERT_EQ(1, shape.dim(0));
+ ASSERT_EQ(2, shape.dim(1));
+ ASSERT_EQ(3, shape.dim(2));
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleGatherNd_slices)
+{
+ luci::test::TestGraph graph;
+ auto indices_const = graph.append<luci::CircleConst>();
+ auto gather_nd_node = graph.append<luci::CircleGatherNd>(graph.input_node, indices_const);
+ graph.complete();
+
+ {
+ auto input_node = graph.input_node;
+ input_node->shape({1, 4, 4, 3});
+ luci::test::graph_input_shape(input_node);
+ }
+ {
+ auto output_node = graph.output_node;
+ output_node->shape({1, 2, 4, 4, 3});
+ luci::test::graph_output_shape(output_node);
+ }
+
+ {
+ indices_const->shape({1, 2, 1});
+ }
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(gather_nd_node));
+
+ // shape inference
+ while (shape_pass(graph.graph()) == true)
+ ;
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(gather_nd_node));
+
+ auto shape = loco::shape_get(gather_nd_node).as<loco::TensorShape>();
+ ASSERT_EQ(5, shape.rank());
+ ASSERT_EQ(1, shape.dim(0));
+ ASSERT_EQ(2, shape.dim(1));
+ ASSERT_EQ(4, shape.dim(2));
+ ASSERT_EQ(4, shape.dim(3));
+ ASSERT_EQ(3, shape.dim(4));
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleGatherNd_NEG)
+{
+ luci::test::TestGraph graph;
+ auto indices_const = graph.append<luci::CircleConst>();
+ auto gather_nd_node = graph.append<luci::CircleGatherNd>(graph.input_node, indices_const);
+ graph.complete();
+
+ {
+ auto input_node = graph.input_node;
+ input_node->shape({1, 4, 4, 3});
+ luci::test::graph_input_shape(input_node);
+ }
+ {
+ // Does not matter, because test should fail anyway
+ auto output_node = graph.output_node;
+ output_node->shape({0, 0, 0});
+ luci::test::graph_output_shape(output_node);
+ }
+
+ {
+ indices_const->shape({1, 2, 5});
+ }
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(gather_nd_node));
+
+ // had to pack into lambda to check throw
+ auto lambda = [&]() {
+ // shape inference
+ while (shape_pass(graph.graph()) == true)
+ ;
+ };
+
+ ASSERT_THROW(lambda(), oops::InternalExn);
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleResizeNearestNeighbor)
+{
+ luci::test::TestGraph graph;
+ auto size_const = graph.append<luci::CircleConst>();
+ size_const->dtype(loco::DataType::S32);
+ size_const->rank(1);
+ size_const->dim(0) = 2;
+ size_const->size<loco::DataType::S32>(2);
+ size_const->at<loco::DataType::S32>(0) = 16;
+ size_const->at<loco::DataType::S32>(1) = 16;
+ auto resize_node = graph.append<luci::CircleResizeNearestNeighbor>(graph.input_node, size_const);
+ graph.complete();
+
+ {
+ auto input_node = graph.input_node;
+ input_node->shape({1, 4, 4, 3});
+ luci::test::graph_input_shape(input_node);
+ }
+ {
+ auto output_node = graph.output_node;
+ output_node->from(resize_node);
+ luci::test::graph_output_shape(output_node);
+ }
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(resize_node));
+
+ // shape inference
+ while (shape_pass(graph.graph()) == true)
+ ;
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(resize_node));
+
+ auto shape = loco::shape_get(resize_node).as<loco::TensorShape>();
+ ASSERT_EQ(4, shape.rank());
+ ASSERT_EQ(1, shape.dim(0));
+ ASSERT_EQ(16, shape.dim(1));
+ ASSERT_EQ(16, shape.dim(2));
+ ASSERT_EQ(3, shape.dim(3));
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleResizeBilinear)
+{
+ luci::test::TestGraph graph;
+ auto size_const = graph.append<luci::CircleConst>();
+ size_const->dtype(loco::DataType::S32);
+ size_const->rank(1);
+ size_const->dim(0) = 2;
+ size_const->size<loco::DataType::S32>(2);
+ size_const->at<loco::DataType::S32>(0) = 16;
+ size_const->at<loco::DataType::S32>(1) = 16;
+ auto resize_node = graph.append<luci::CircleResizeBilinear>(graph.input_node, size_const);
+ graph.complete();
+
+ {
+ auto input_node = graph.input_node;
+ input_node->shape({1, 4, 4, 3});
+ luci::test::graph_input_shape(input_node);
+ }
+ {
+ auto output_node = graph.output_node;
+ output_node->from(resize_node);
+ luci::test::graph_output_shape(output_node);
+ }
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(resize_node));
+
+ // shape inference
+ while (shape_pass(graph.graph()) == true)
+ ;
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(resize_node));
+
+ auto shape = loco::shape_get(resize_node).as<loco::TensorShape>();
+ ASSERT_EQ(4, shape.rank());
+ ASSERT_EQ(1, shape.dim(0));
+ ASSERT_EQ(16, shape.dim(1));
+ ASSERT_EQ(16, shape.dim(2));
+ ASSERT_EQ(3, shape.dim(3));
}
}
diff --git a/compiler/luci/service/src/CircleTypeInference.cpp b/compiler/luci/service/src/CircleTypeInference.cpp
index 669906159..aa8524a55 100644
--- a/compiler/luci/service/src/CircleTypeInference.cpp
+++ b/compiler/luci/service/src/CircleTypeInference.cpp
@@ -15,19 +15,13 @@
*/
#include "luci/Service/CircleTypeInference.h"
-#include "luci/Service/CircleTypeInferenceRule.h"
-#include <luci/IR/CircleDialect.h>
-
-#include <loco/IR/CanonicalNode.h>
-#include <loco/IR/CanonicalNodeVisitor.h>
-#include <loco/IR/CanonicalDialect.h>
+#include <loco.h>
#include <loco/Service/TypeInference.h>
+
#include <mio/circle/schema_generated.h>
#include <oops/InternalExn.h>
-#include <memory>
-#include <stdexcept>
#include <type_traits>
namespace
diff --git a/compiler/luci/service/src/CircleTypeInferenceRule.cpp b/compiler/luci/service/src/CircleTypeInferenceRule.cpp
index 21a28c1b6..de2ba3ea4 100644
--- a/compiler/luci/service/src/CircleTypeInferenceRule.cpp
+++ b/compiler/luci/service/src/CircleTypeInferenceRule.cpp
@@ -33,18 +33,45 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
loco::DataType visit(const luci::CircleAdd *node) final { return loco::dtype_get(node->x()); }
+ loco::DataType visit(const luci::CircleAddN *node) final
+ {
+ auto dtype = loco::dtype_get(node->inputs(0));
+
+ for (uint32_t idx = 1; idx < node->arity(); ++idx)
+ {
+ auto dtype_idx = loco::dtype_get(node->inputs(idx));
+ if (dtype != dtype_idx)
+ {
+ INTERNAL_EXN_V("ADD_N dtype not same as the first input: ", idx);
+ }
+ }
+
+ return loco::dtype_get(node->inputs(0));
+ }
+
loco::DataType visit(const luci::CircleArgMax *node) final { return node->output_type(); }
+ loco::DataType visit(const luci::CircleArgMin *node) final { return node->output_type(); }
+
loco::DataType visit(const luci::CircleAveragePool2D *node) final
{
return loco::dtype_get(node->value());
}
+ loco::DataType visit(const luci::CircleBatchMatMul *node) final
+ {
+ return loco::dtype_get(node->x());
+ }
+
loco::DataType visit(const luci::CircleBatchToSpaceND *node) final
{
return loco::dtype_get(node->input());
}
+ loco::DataType visit(const luci::CircleCast *node) final { return node->dtype(); }
+
+ loco::DataType visit(const luci::CircleCeil *node) final { return loco::dtype_get(node->x()); }
+
loco::DataType visit(const luci::CircleConcatenation *node) final
{
// TODO Support when CircleConcatenation has 0 input
@@ -65,6 +92,20 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
loco::DataType visit(const luci::CircleCos *node) final { return loco::dtype_get(node->x()); }
+ loco::DataType visit(const luci::CircleCustom *node) final
+ {
+ if (node->custom_code() == "BatchMatMulV2")
+ {
+ return loco::dtype_get(node->inputs(0));
+ }
+ return node->dtype();
+ }
+
+ loco::DataType visit(const luci::CircleDepthToSpace *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
loco::DataType visit(const luci::CircleDepthwiseConv2D *node) final
{
return loco::dtype_get(node->input());
@@ -72,15 +113,94 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
loco::DataType visit(const luci::CircleDiv *node) final { return loco::dtype_get(node->x()); }
+ loco::DataType visit(const luci::CircleElu *node) final
+ {
+ return loco::dtype_get(node->features());
+ }
+
loco::DataType visit(const luci::CircleEqual *) final { return loco::DataType::BOOL; }
loco::DataType visit(const luci::CircleExp *node) final { return loco::dtype_get(node->x()); }
+ loco::DataType visit(const luci::CircleExpandDims *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleFill *node) final
+ {
+ return loco::dtype_get(node->value());
+ }
+
+ loco::DataType visit(const luci::CircleFloor *node) final { return loco::dtype_get(node->x()); }
+
+ loco::DataType visit(const luci::CircleFloorDiv *node) final
+ {
+ return loco::dtype_get(node->x());
+ }
+
+ loco::DataType visit(const luci::CircleFloorMod *node) final
+ {
+ return loco::dtype_get(node->x());
+ }
+
loco::DataType visit(const luci::CircleFullyConnected *node) final
{
return loco::dtype_get(node->input());
}
+ loco::DataType visit(const luci::CircleGather *node) final
+ {
+ return loco::dtype_get(node->params());
+ }
+
+ loco::DataType visit(const luci::CircleGatherNd *node) final
+ {
+ return loco::dtype_get(node->params());
+ }
+
+ loco::DataType visit(const luci::CircleGreater *) final { return loco::DataType::BOOL; }
+
+ loco::DataType visit(const luci::CircleGreaterEqual *) final { return loco::DataType::BOOL; }
+
+ loco::DataType visit(const luci::CircleIf *node) final
+ {
+ // Type of If is not used. Just use input 0
+ assert(node->input_count() > 0);
+ return loco::dtype_get(node->input(0));
+ }
+
+ loco::DataType visit(const luci::CircleL2Normalize *node) final
+ {
+ return loco::dtype_get(node->x());
+ }
+
+ loco::DataType visit(const luci::CircleL2Pool2D *node) final
+ {
+ return loco::dtype_get(node->value());
+ }
+
+ loco::DataType visit(const luci::CircleLeakyRelu *node) final
+ {
+ return loco::dtype_get(node->features());
+ }
+
+ loco::DataType visit(const luci::CircleLess *) final { return loco::DataType::BOOL; }
+
+ loco::DataType visit(const luci::CircleLessEqual *) final { return loco::DataType::BOOL; }
+
+ loco::DataType visit(const luci::CircleLocalResponseNormalization *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleLog *node) final { return loco::dtype_get(node->x()); }
+
+ loco::DataType visit(const luci::CircleLogicalAnd *node) final
+ {
+ return loco::dtype_get(node->x());
+ }
+
loco::DataType visit(const luci::CircleLogicalNot *node) final
{
return loco::dtype_get(node->x());
@@ -91,6 +211,26 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
return loco::dtype_get(node->x());
}
+ loco::DataType visit(const luci::CircleLogistic *node) final
+ {
+ return loco::dtype_get(node->x());
+ }
+
+ loco::DataType visit(const luci::CircleLogSoftmax *node) final
+ {
+ return loco::dtype_get(node->logits());
+ }
+
+ loco::DataType visit(const luci::CircleMatrixDiag *node) final
+ {
+ return loco::dtype_get(node->diagonal());
+ }
+
+ loco::DataType visit(const luci::CircleMatrixSetDiag *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
loco::DataType visit(const luci::CircleMaximum *node) final { return loco::dtype_get(node->x()); }
loco::DataType visit(const luci::CircleMaxPool2D *node) final
@@ -103,6 +243,17 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
return loco::dtype_get(node->input());
}
+ loco::DataType visit(const luci::CircleMinimum *node) final { return loco::dtype_get(node->x()); }
+
+ loco::DataType visit(const luci::CircleMirrorPad *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleNeg *node) final { return loco::dtype_get(node->x()); }
+
+ loco::DataType visit(const luci::CircleNotEqual *) final { return loco::DataType::BOOL; }
+
loco::DataType visit(const luci::CirclePack *node) final
{
// Only support CirclePack with one or more inputs
@@ -117,8 +268,63 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
loco::DataType visit(const luci::CirclePad *node) final { return loco::dtype_get(node->input()); }
+ loco::DataType visit(const luci::CirclePow *node) final
+ {
+ // TODO make sure types cannot differ
+ auto x_type = loco::dtype_get(node->x());
+ auto y_type = loco::dtype_get(node->y());
+
+ if (x_type != y_type)
+ INTERNAL_EXN("Different datatype for x and y are not supported");
+
+ return x_type;
+ }
+
+ loco::DataType visit(const luci::CirclePRelu *node) final
+ {
+ auto input_type = loco::dtype_get(node->input());
+ auto alpha_type = loco::dtype_get(node->alpha());
+
+ if (input_type != alpha_type)
+ INTERNAL_EXN("Different datatype for input and alpha are not supported");
+
+ return input_type;
+ }
+
+ loco::DataType visit(const luci::CircleRange *node) final
+ {
+ return loco::dtype_get(node->start());
+ }
+
+ loco::DataType visit(const luci::CircleRank *) final { return loco::DataType::S32; }
+
loco::DataType visit(const luci::CircleMul *node) final { return loco::dtype_get(node->x()); }
+ loco::DataType visit(const luci::CircleOneHot *node) final
+ {
+ return loco::dtype_get(node->on_value());
+ }
+
+ loco::DataType visit(const luci::CircleReduceAny *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleReduceMax *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleReduceMin *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleReduceProd *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
loco::DataType visit(const luci::CircleRelu *node) final
{
return loco::dtype_get(node->features());
@@ -129,28 +335,132 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
return loco::dtype_get(node->features());
}
+ loco::DataType visit(const luci::CircleReluN1To1 *node) final
+ {
+ return loco::dtype_get(node->features());
+ }
+
loco::DataType visit(const luci::CircleReshape *node) final
{
return loco::dtype_get(node->tensor());
}
+ loco::DataType visit(const luci::CircleResizeBilinear *) final { return loco::DataType::FLOAT32; }
+
+ loco::DataType visit(const luci::CircleResizeNearestNeighbor *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleReverseSequence *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleReverseV2 *node) final
+ {
+ return loco::dtype_get(node->tensor());
+ }
+
+ loco::DataType visit(const luci::CircleRound *node) final { return loco::dtype_get(node->x()); }
+
loco::DataType visit(const luci::CircleRsqrt *node) final { return loco::dtype_get(node->x()); }
+ loco::DataType visit(const luci::CircleScatterNd *node) final
+ {
+ return loco::dtype_get(node->updates());
+ }
+
+ loco::DataType visit(const luci::CircleSegmentSum *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleSelect *node) final
+ {
+ assert(loco::dtype_get(node->t()) == loco::dtype_get(node->e()));
+ return loco::dtype_get(node->t());
+ }
+
+ loco::DataType visit(const luci::CircleSelectV2 *node) final
+ {
+ assert(loco::dtype_get(node->t()) == loco::dtype_get(node->e()));
+ return loco::dtype_get(node->t());
+ }
+
+ loco::DataType visit(const luci::CircleShape *node) final { return node->out_type(); }
+
+ loco::DataType visit(const luci::CircleSin *node) final { return loco::dtype_get(node->x()); }
+
+ loco::DataType visit(const luci::CircleSlice *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
loco::DataType visit(const luci::CircleSoftmax *node) final
{
return loco::dtype_get(node->logits());
}
+ loco::DataType visit(const luci::CircleSpaceToBatchND *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleSpaceToDepth *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleSparseToDense *node) final
+ {
+ return loco::dtype_get(node->values());
+ }
+
+ loco::DataType visit(const luci::CircleSplit *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleSplitV *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
loco::DataType visit(const luci::CircleSqrt *node) final { return loco::dtype_get(node->x()); }
+ loco::DataType visit(const luci::CircleSquare *node) final { return loco::dtype_get(node->x()); }
+
loco::DataType visit(const luci::CircleSquaredDifference *node) final
{
return loco::dtype_get(node->x());
}
+ loco::DataType visit(const luci::CircleSqueeze *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleStridedSlice *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
loco::DataType visit(const luci::CircleSub *node) final { return loco::dtype_get(node->x()); }
- // TODO CircleTanh
+ loco::DataType visit(const luci::CircleSum *node) final { return loco::dtype_get(node->input()); }
+
+ loco::DataType visit(const luci::CircleTanh *node) final { return loco::dtype_get(node->x()); }
+
+ loco::DataType visit(const luci::CircleTile *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleTopKV2 *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
loco::DataType visit(const luci::CircleTranspose *node) final
{
@@ -162,7 +472,33 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
return loco::dtype_get(node->outBackprop());
}
+ loco::DataType visit(const luci::CircleUnpack *node) final
+ {
+ return loco::dtype_get(node->value());
+ }
+
+ loco::DataType visit(const luci::CircleWhere *) final { return loco::DataType::S64; }
+
+ loco::DataType visit(const luci::CircleWhile *node) final
+ {
+ // Type of While is not used. Just use input 0
+ assert(node->input_count() > 0);
+ return loco::dtype_get(node->input(0));
+ }
+
+ loco::DataType visit(const luci::CircleZerosLike *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
// Circle Only
+ loco::DataType visit(const luci::CircleBCQFullyConnected *) final
+ {
+ return loco::DataType::FLOAT32;
+ }
+
+ loco::DataType visit(const luci::CircleBCQGather *) final { return loco::DataType::FLOAT32; }
+
loco::DataType visit(const luci::CircleInstanceNorm *node) final
{
return loco::dtype_get(node->input());
@@ -173,7 +509,116 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT
loco::DataType visit(const luci::CircleOutput *node) final
{
- return loco::dtype_get(node->from());
+ auto graph_outputs = node->graph()->outputs();
+ auto graph_output = graph_outputs->at(node->index());
+ auto output_dtype = graph_output->dtype();
+
+ if (dynamic_cast<luci::CircleOutputDummy *>(node->from()) == nullptr &&
+ dynamic_cast<luci::CircleOutputExclude *>(node->from()) == nullptr)
+ {
+ // We don't care for the type if from() is CircleOutputDummy or CircleOutputExclude
+ // from() type should match that of CircleOutput
+ assert(output_dtype == loco::dtype_get(node->from()));
+ }
+ return output_dtype;
+ }
+
+ loco::DataType visit(const luci::CircleOutputDummy *node) final { return node->dtype(); }
+
+ loco::DataType visit(const luci::CircleOutputExclude *node) final { return node->dtype(); }
+
+ loco::DataType visit(const luci::CircleCustomOut *node) final { return node->dtype(); }
+
+ loco::DataType visit(const luci::CircleIfOut *node) final
+ {
+ /**
+ * @note IF operator type and shape are that of the "then" and "else"
+ * Graph Outputs.
+ */
+ auto circle_if = dynamic_cast<const luci::CircleIf *>(node->input());
+ if (circle_if == nullptr)
+ {
+ INTERNAL_EXN("CircleIf IR is not configured correctly");
+ }
+
+ auto index = node->index();
+ auto then_graph = circle_if->then_graph();
+ auto else_graph = circle_if->else_graph();
+ assert(then_graph != nullptr);
+ assert(else_graph != nullptr);
+
+ // shape and type are assumed to be same
+ // these are checked at post_import_graph() in Import
+ auto then_outputs = loco::output_nodes(then_graph);
+ auto else_outputs = loco::output_nodes(else_graph);
+ assert(then_outputs.size() == else_outputs.size());
+ assert(index < static_cast<int32_t>(then_outputs.size()));
+
+ auto then_out = loco::must_cast<luci::CircleOutput *>(then_outputs.at(index));
+ auto else_out = loco::must_cast<luci::CircleOutput *>(else_outputs.at(index));
+
+ auto then_graph_outputs = then_graph->outputs(); // loco::GraphOutput items
+ auto else_graph_outputs = else_graph->outputs();
+ assert(then_graph_outputs->size() == else_graph_outputs->size());
+
+ auto then_graph_output = then_graph_outputs->at(then_out->index());
+ auto else_graph_output = else_graph_outputs->at(else_out->index());
+ (void)else_graph_output; // make compiler happy for unused variable warnings
+ assert(then_graph_output->dtype() == else_graph_output->dtype());
+
+ return then_graph_output->dtype();
+ }
+
+ loco::DataType visit(const luci::CircleSplitOut *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleSplitVOut *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleTopKV2Out *node) final
+ {
+ // First output is same as input
+ if (node->index() == 0)
+ return loco::dtype_get(node->input());
+ // Second outout is always S32
+ assert(node->index() == 1);
+ return loco::DataType::S32;
+ }
+
+ loco::DataType visit(const luci::CircleUnpackOut *node) final
+ {
+ return loco::dtype_get(node->input());
+ }
+
+ loco::DataType visit(const luci::CircleWhileOut *node) final
+ {
+ /**
+ * @note WHILE operator's type is the same with the "cond"
+ * Graph Input.
+ */
+ auto circle_while = dynamic_cast<const luci::CircleWhile *>(node->input());
+ if (circle_while == nullptr)
+ {
+ INTERNAL_EXN("CircleWhile IR is not configured correctly");
+ }
+
+ auto index = node->index();
+ auto cond_graph = circle_while->cond_graph();
+ assert(cond_graph != nullptr);
+
+ // Assumption: the index of CircleWhileOut matches with the index of input nodes returned by
+ // loco::input_nodes
+ auto cond_inputs = loco::input_nodes(cond_graph);
+ auto cond_in = loco::must_cast<luci::CircleInput *>(cond_inputs.at(index));
+
+ auto cond_graph_inputs = cond_graph->inputs();
+ auto cond_graph_input = cond_graph_inputs->at(cond_in->index());
+
+ return cond_graph_input->dtype();
}
};
@@ -193,7 +638,8 @@ bool CircleTypeInferenceRule::infer(const loco::Node *node, loco::DataType &dtyp
TypeInferenceAlgorithm alg;
- dtype = dynamic_cast<const CircleNode *>(node)->accept(&alg);
+ auto circle_node = loco::must_cast<const CircleNode *>(node);
+ dtype = circle_node->accept(&alg);
assert(dtype != loco::DataType::Unknown);
return true;
diff --git a/compiler/luci/service/src/CircleTypeInferenceRule.test.cpp b/compiler/luci/service/src/CircleTypeInferenceRule.test.cpp
index 29f45173e..711a489af 100644
--- a/compiler/luci/service/src/CircleTypeInferenceRule.test.cpp
+++ b/compiler/luci/service/src/CircleTypeInferenceRule.test.cpp
@@ -32,26 +32,32 @@ TEST(CircleTypeInferenceRuleTest, minimal_with_CircleRelu)
{
// Create a simple network
luci::test::TestGraph graph;
- auto tfl_node = graph.append<luci::CircleRelu>(graph.pull);
- graph.complete(tfl_node);
+ auto relu_node = graph.append<luci::CircleRelu>(graph.input_node);
+ graph.complete(relu_node);
- graph.pull->dtype(loco::DataType::S32);
+ // set dtype for nodes; like setting them in import
+ graph.input_node->dtype(loco::DataType::S32);
+ relu_node->dtype(loco::DataType::S32);
+ graph.output_node->dtype(loco::DataType::S32);
+
+ luci::test::graph_input_dtype(graph.input_node);
+ luci::test::graph_output_dtype(graph.output_node);
// pre-check
- ASSERT_FALSE(loco::dtype_known(tfl_node));
+ ASSERT_FALSE(loco::dtype_known(relu_node));
// type inference
- luci::CircleTypeInferenceRule tfl_rule;
+ luci::CircleTypeInferenceRule circle_rule;
loco::CanonicalTypeInferenceRule canon_rule;
loco::MultiDialectTypeInferenceRule rules;
rules.bind(loco::CanonicalDialect::get(), &canon_rule);
- rules.bind(luci::CircleDialect::get(), &tfl_rule);
+ rules.bind(luci::CircleDialect::get(), &circle_rule);
loco::apply(&rules).to(graph.g.get());
// Verify
- ASSERT_TRUE(loco::dtype_known(tfl_node));
- auto type = loco::dtype_get(tfl_node);
- ASSERT_EQ(type, loco::DataType::S32);
+ ASSERT_TRUE(loco::dtype_known(relu_node));
+ auto type = loco::dtype_get(relu_node);
+ ASSERT_EQ(loco::DataType::S32, type);
}
diff --git a/compiler/luci/service/src/GraphBlock.h b/compiler/luci/service/src/GraphBlock.h
deleted file mode 100644
index 2a455888a..000000000
--- a/compiler/luci/service/src/GraphBlock.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __GRAPH_BLOCK_H__
-#define __GRAPH_BLOCK_H__
-
-#include <loco.h>
-#include <loco/Service/ShapeInference.h>
-
-#include <oops/InternalExn.h>
-
-#include <functional>
-
-// TODO Change all Canonical nodes to Circle nodes
-
-namespace luci
-{
-
-/// @brief feature layout of TFlite/Circle file
-enum class FeatureLayout
-{
- NHWC,
-};
-
-/// @brief Creates a loco::FeatureEncode with T layout (NHWC for tflite) and add it to graph.
-template <FeatureLayout T> loco::FeatureEncode *make_feature_encode(loco::Node *input_for_encode);
-
-/// @brief Creates a loco::FeatureDecode with T layout (NHWC for tflite) and add it to graph.
-template <FeatureLayout T> loco::FeatureDecode *make_feature_decode(loco::Node *input_for_decode);
-
-enum class FilterLayout
-{
- OHWI, // a.k.a., NHWC, Tensorflow Lite uses this layout for filter
- HWIO, // a.k.a., HWCN, Tensorflow uses this layout for filter
-};
-
-/// @brief Create a loco::FilterEncode of given layout
-template <FilterLayout T> loco::FilterEncode *make_filter_encode(loco::Node *input_for_encode);
-
-/// @brief Create a loco::FilterDecode of given layout
-template <FilterLayout T> loco::FilterDecode *make_filter_decode(loco::Node *input_for_decode);
-
-enum class DepthwiseFilterLayout
-{
- HWCM,
-};
-
-/// @brief Create a loco::DepthwiseFilterDecode of given layout
-template <DepthwiseFilterLayout T>
-loco::DepthwiseFilterDecode *make_dw_filter_decode(loco::Node *input_for_decode);
-
-enum class MatrixLayout
-{
- HW,
- WH
-};
-
-/// @brief Create a loco::MatrixEncode of given layout
-template <MatrixLayout T> loco::MatrixEncode *make_matrix_encode(loco::Node *input_for_encode);
-
-/// @brief Create a loco::MatrixDecode of given layout
-template <MatrixLayout T> loco::MatrixDecode *make_matrix_decode(loco::Node *input_for_decode);
-
-} // luci
-
-//
-// DomainConverter
-//
-
-/**
- * Some canonical nodes can have input of various loco::Domain, e.g., loco::Domain::Tensor,
- * loco::Domain::Feature, etc. However, TFL node accepts only loco::Domain::Tensor.
- * So, When converting such canonical node to TFL node and input(s) of a canonical node are not
- * loco::Domain::Tensor, additional nodes need to be inserted.
- *
- * The following two classes helps this insertion.
- *
- * For example, in case of loco::Relu conversion,
- *
- * Before:
- *
- * A (output: feature) -- loco::ReLU --- B (input:feature)
- *
- * After:
- *
- * A -- loco::FeatureDecode -- locoex::TFLRelu -- loco::FeatureEncode --- B
- *
- * loco::ReLU (dead node)
- */
-
-namespace luci
-{
-
-/**
- * @brief Handles input(s) while converting a canonical node to TFL node(s).
- * This class informs DomainConverter how to handle inputs of a specific canonical node.
- */
-template <class CanonicalT, class TFLT> class InputHandler
-{
-public:
- /**
- * @brief Assign origin's inputs to replacer's inputs.
- * (This is called when origin belongs in Tensor domain.)
- */
- virtual void handover(CanonicalT *origin, TFLT *replacer) = 0;
-
- /**
- * @brief Returns the list of inputs that needs to have FeatureDecode as its input.
- * (This is called when origin belongs in Feature domain.)
- */
- virtual std::vector<loco::Node *> getInputsToConvert(CanonicalT *origin) = 0;
-
- /// @brief Set the inputs of replacer to new_inputs
- virtual void set(TFLT *replacer, std::vector<loco::Node *> &new_inputs) = 0;
-
- /// @brief Set the inputs to nullptr
- virtual void nullify(CanonicalT *origin) = 0;
-};
-
-/**
- * @brief Class to handle domain conversion while converting a canonical node to TFL node(s)
- */
-template <class CanonicalT, class TFLT> class DomainConverter
-{
-public:
- template <FeatureLayout FeatureLayoutT>
- TFLT *convert(CanonicalT *origin, InputHandler<CanonicalT, TFLT> &input_handler);
-};
-
-/**
- * @brief Performs domain conversion
- *
- * 1. if origin belong to loco::Domain::Tensor, and replace origin to a TFL node.
- * 2. if origin belong to loco::Domain::Feature, insert loco::FeatureDecode for input(s) and
- * insert loco::FeatureEncode for output. Then replace origin to a TFL node.
- *
- * @return new TFL node; nullptr if shape of origin cannot be known
- */
-template <class CanonicalT, class TFLT>
-template <FeatureLayout FeatureLayoutT>
-TFLT *DomainConverter<CanonicalT, TFLT>::convert(CanonicalT *origin,
- InputHandler<CanonicalT, TFLT> &input_handler)
-{
- static_assert(FeatureLayoutT == FeatureLayout::NHWC, "Feature layout should be NHWC");
-
- if (!loco::shape_known(origin))
- {
- return nullptr;
- }
-
- auto tfl_node = origin->graph()->nodes()->template create<TFLT>();
-
- // when the input is Tensor, just replace canonical node to TFL node.
- if (loco::shape_get(origin).domain() == loco::Domain::Tensor)
- {
- input_handler.handover(origin, tfl_node);
-
- loco::replace(origin).with(tfl_node);
- input_handler.nullify(origin);
-
- return tfl_node;
- }
- else if (loco::shape_get(origin).domain() == loco::Domain::Feature)
- {
- std::vector<loco::Node *> feature_decodes;
-
- for (auto input : input_handler.getInputsToConvert(origin))
- {
- auto dec = make_feature_decode<FeatureLayoutT>(input);
- feature_decodes.emplace_back(dec);
- }
-
- input_handler.set(tfl_node, feature_decodes);
-
- auto enc = make_feature_encode<FeatureLayoutT>(tfl_node);
-
- loco::replace(origin).with(enc);
- input_handler.nullify(origin);
-
- return tfl_node;
- }
- else
- INTERNAL_EXN_V("Unsupported loco::Domain", oops::to_uint32(loco::shape_get(origin).domain()));
-}
-
-} // namespace luci
-
-#endif //__GRAPH_BLOCK_H__
diff --git a/compiler/luci/service/src/GraphBlock.test.cpp b/compiler/luci/service/src/GraphBlock.test.cpp
deleted file mode 100644
index 1da8c18fa..000000000
--- a/compiler/luci/service/src/GraphBlock.test.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "GraphBlock.h"
-
-#include "Check.h"
-
-#include <loco.h>
-
-#include <memory>
-
-// TODO Change all Canonical nodes to Circle nodes
-
-namespace
-{
-
-template <luci::FeatureLayout T> loco::Permutation<loco::Domain::Feature> perm();
-
-template <> loco::Permutation<loco::Domain::Feature> perm<luci::FeatureLayout::NHWC>()
-{
- // Make NHWC permutation for encoder and decoder
- loco::Permutation<loco::Domain::Feature> NHWC;
-
- NHWC.axis(loco::FeatureAxis::Count) = 0;
- NHWC.axis(loco::FeatureAxis::Height) = 1;
- NHWC.axis(loco::FeatureAxis::Width) = 2;
- NHWC.axis(loco::FeatureAxis::Depth) = 3;
-
- return NHWC;
-}
-
-template <luci::FilterLayout T> loco::Permutation<loco::Domain::Filter> perm();
-
-template <> loco::Permutation<loco::Domain::Filter> perm<luci::FilterLayout::HWIO>()
-{
- loco::Permutation<loco::Domain::Filter> HWIO; // a.k.a., HWCN
-
- HWIO.axis(loco::FilterAxis::Height) = 0;
- HWIO.axis(loco::FilterAxis::Width) = 1;
- HWIO.axis(loco::FilterAxis::Depth) = 2;
- HWIO.axis(loco::FilterAxis::Count) = 3;
-
- return HWIO;
-}
-
-template <> loco::Permutation<loco::Domain::Filter> perm<luci::FilterLayout::OHWI>()
-{
-
- // Make NHWC permutation for encoder and decoder
- loco::Permutation<loco::Domain::Filter> OHWI; // a.k.a., NHWC
-
- OHWI.axis(loco::FilterAxis::Count) = 0;
- OHWI.axis(loco::FilterAxis::Height) = 1;
- OHWI.axis(loco::FilterAxis::Width) = 2;
- OHWI.axis(loco::FilterAxis::Depth) = 3;
-
- return OHWI;
-}
-
-template <luci::DepthwiseFilterLayout T> loco::Permutation<loco::Domain::DepthwiseFilter> perm();
-
-template <>
-loco::Permutation<loco::Domain::DepthwiseFilter> perm<luci::DepthwiseFilterLayout::HWCM>()
-{
- loco::Permutation<loco::Domain::DepthwiseFilter> HWCM;
-
- HWCM.axis(loco::DepthwiseFilterAxis::Height) = 0;
- HWCM.axis(loco::DepthwiseFilterAxis::Width) = 1;
- HWCM.axis(loco::DepthwiseFilterAxis::Depth) = 2;
- HWCM.axis(loco::DepthwiseFilterAxis::Multiplier) = 3;
-
- return HWCM;
-}
-
-template <luci::MatrixLayout T> loco::Permutation<loco::Domain::Matrix> perm();
-
-template <> loco::Permutation<loco::Domain::Matrix> perm<luci::MatrixLayout::HW>()
-{
- loco::Permutation<loco::Domain::Matrix> HW;
-
- HW.axis(loco::MatrixAxis::Height) = 0;
- HW.axis(loco::MatrixAxis::Width) = 1;
-
- return HW;
-}
-
-template <> loco::Permutation<loco::Domain::Matrix> perm<luci::MatrixLayout::WH>()
-{
- loco::Permutation<loco::Domain::Matrix> WH;
-
- WH.axis(loco::MatrixAxis::Height) = 1;
- WH.axis(loco::MatrixAxis::Width) = 0;
-
- return WH;
-}
-
-} // namespace
-
-namespace luci
-{
-
-template <FeatureLayout T> loco::FeatureEncode *make_feature_encode(loco::Node *input_for_encode)
-{
- LUCI_ASSERT(input_for_encode != nullptr, "input should not be nullptr");
- loco::Graph *g = input_for_encode->graph();
-
- auto encoder = std::make_unique<loco::PermutingEncoder<loco::Domain::Feature>>();
-
- encoder->perm(perm<T>());
-
- auto enc = g->nodes()->create<loco::FeatureEncode>();
- enc->input(input_for_encode);
- enc->encoder(std::move(encoder));
-
- return enc;
-}
-
-template <FeatureLayout T> loco::FeatureDecode *make_feature_decode(loco::Node *input_for_decode)
-{
- LUCI_ASSERT(input_for_decode != nullptr, "input should not be nullptr");
- loco::Graph *g = input_for_decode->graph();
-
- auto decoder = std::make_unique<loco::PermutingDecoder<loco::Domain::Feature>>();
-
- decoder->perm(perm<T>());
-
- auto dec = g->nodes()->create<loco::FeatureDecode>();
- dec->input(input_for_decode);
- dec->decoder(std::move(decoder));
-
- return dec;
-}
-
-template <FilterLayout T> loco::FilterEncode *make_filter_encode(loco::Node *input_for_encode)
-{
- LUCI_ASSERT(input_for_encode != nullptr, "filter should not be nullptr");
- loco::Graph *g = input_for_encode->graph();
-
- auto encoder = std::make_unique<loco::PermutingEncoder<loco::Domain::Filter>>();
-
- encoder->perm(perm<T>());
-
- auto enc = g->nodes()->create<loco::FilterEncode>();
- enc->input(input_for_encode);
- enc->encoder(std::move(encoder));
-
- return enc;
-}
-
-template <FilterLayout T> loco::FilterDecode *make_filter_decode(loco::Node *input_for_decode)
-{
- LUCI_ASSERT(input_for_decode != nullptr, "filter should not be nullptr");
- loco::Graph *g = input_for_decode->graph();
-
- auto decoder = std::make_unique<loco::PermutingDecoder<loco::Domain::Filter>>();
-
- decoder->perm(perm<T>());
-
- auto dec = g->nodes()->create<loco::FilterDecode>();
- dec->input(input_for_decode);
- dec->decoder(std::move(decoder));
-
- return dec;
-}
-
-template <DepthwiseFilterLayout T>
-loco::DepthwiseFilterDecode *make_dw_filter_decode(loco::Node *input_for_decode)
-{
- LUCI_ASSERT(input_for_decode != nullptr, "filter should not be nullptr");
- loco::Graph *g = input_for_decode->graph();
-
- auto decoder = std::make_unique<loco::PermutingDecoder<loco::Domain::DepthwiseFilter>>();
-
- decoder->perm(perm<T>());
-
- auto dec = g->nodes()->create<loco::DepthwiseFilterDecode>();
- dec->input(input_for_decode);
- dec->decoder(std::move(decoder));
-
- return dec;
-}
-
-template <MatrixLayout T> loco::MatrixEncode *make_matrix_encode(loco::Node *input_for_encode)
-{
- LUCI_ASSERT(input_for_encode != nullptr, "input should not be nullptr");
- loco::Graph *g = input_for_encode->graph();
-
- auto encoder = std::make_unique<loco::PermutingEncoder<loco::Domain::Matrix>>();
-
- encoder->perm(perm<T>());
-
- auto enc = g->nodes()->create<loco::MatrixEncode>();
- enc->input(input_for_encode);
- enc->encoder(std::move(encoder));
-
- return enc;
-}
-
-template <MatrixLayout T> loco::MatrixDecode *make_matrix_decode(loco::Node *input_for_decode)
-{
- LUCI_ASSERT(input_for_decode != nullptr, "input should not be nullptr");
- loco::Graph *g = input_for_decode->graph();
-
- auto decoder = std::make_unique<loco::PermutingDecoder<loco::Domain::Matrix>>();
-
- decoder->perm(perm<T>());
-
- auto dec = g->nodes()->create<loco::MatrixDecode>();
- dec->input(input_for_decode);
- dec->decoder(std::move(decoder));
-
- return dec;
-}
-
-// template instantiation
-template loco::FeatureEncode *
-make_feature_encode<FeatureLayout::NHWC>(loco::Node *input_for_encode);
-
-template loco::FeatureDecode *
-make_feature_decode<FeatureLayout::NHWC>(loco::Node *input_for_encode);
-
-template loco::FilterEncode *make_filter_encode<FilterLayout::HWIO>(loco::Node *input_for_encode);
-template loco::FilterDecode *make_filter_decode<FilterLayout::OHWI>(loco::Node *input_for_decode);
-
-template loco::DepthwiseFilterDecode *
-make_dw_filter_decode<DepthwiseFilterLayout::HWCM>(loco::Node *input_for_decode);
-
-template loco::MatrixEncode *make_matrix_encode<MatrixLayout::HW>(loco::Node *input_for_encode);
-template loco::MatrixEncode *make_matrix_encode<MatrixLayout::WH>(loco::Node *input_for_encode);
-template loco::MatrixDecode *make_matrix_decode<MatrixLayout::HW>(loco::Node *input_for_decode);
-template loco::MatrixDecode *make_matrix_decode<MatrixLayout::WH>(loco::Node *input_for_decode);
-
-} // namespace luci
diff --git a/compiler/luci/service/src/ShapeInfer_StridedSlice.cpp b/compiler/luci/service/src/ShapeInfer_StridedSlice.cpp
new file mode 100644
index 000000000..341201148
--- /dev/null
+++ b/compiler/luci/service/src/ShapeInfer_StridedSlice.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ShapeInfer_StridedSlice.h"
+#include "Check.h"
+
+#include <luci/IR/CircleNode.h>
+#include <loco/IR/DataType.h>
+#include <loco/IR/NodeShape.h>
+#include <oops/InternalExn.h>
+#include <loco/Service/ShapeInference.h>
+
+#include <cmath>
+#include <cstdint>
+#include <limits>
+
+namespace
+{
+
+// This Op only supports 1-4D cases and since we use the reference 4D
+// implementation, the 1-3D tensors are mapped to 4D.
+const int kMaxDim = 4;
+
+const loco::DataType S32 = loco::DataType::S32;
+
+using int8 = int8_t;
+using int16 = int16_t;
+
+struct StridedSliceParams
+{
+ int8 start_indices_count;
+ int16 start_indices[kMaxDim];
+ int8 stop_indices_count;
+ int16 stop_indices[kMaxDim];
+ int8 strides_count;
+ int16 strides[kMaxDim];
+
+ int16 begin_mask;
+ int16 ellipsis_mask;
+ int16 end_mask;
+ int16 new_axis_mask;
+ int16 shrink_axis_mask;
+};
+
+// Use until std::clamp() is available from C++17.
+inline int Clamp(const int32_t v, const int32_t lo, const int32_t hi)
+{
+ LUCI_ASSERT(!(hi < lo), "Clamp hi < lo");
+ if (hi < v)
+ return hi;
+ if (v < lo)
+ return lo;
+ return v;
+}
+
+// Return the index for the first element along that axis. This index will be a
+// positive integer between [0, axis_size - 1] that can be used to index
+// directly into the data.
+inline int StartForAxis(const StridedSliceParams &params, const loco::TensorShape &input_shape,
+ uint32_t axis)
+{
+ const auto begin_mask = params.begin_mask;
+ const auto *start_indices = params.start_indices;
+ const auto *strides = params.strides;
+ const int32_t axis_size = static_cast<int>(input_shape.dim(axis).value());
+ if (axis_size == 0)
+ {
+ return 0;
+ }
+ // Begin with the specified index.
+ int32_t start = start_indices[axis];
+
+ // begin_mask override
+ if (begin_mask & (1 << axis))
+ {
+ if (strides[axis] > 0)
+ {
+ // Forward iteration - use the first element. These values will get
+ // clamped below (Note: We could have set them to 0 and axis_size-1, but
+ // use lowest() and max() to maintain symmetry with StopForAxis())
+ start = std::numeric_limits<int32_t>::lowest();
+ }
+ else
+ {
+ // Backward iteration - use the last element.
+ start = std::numeric_limits<int32_t>::max();
+ }
+ }
+
+ // Handle negative indices
+ if (start < 0)
+ {
+ start += axis_size;
+ }
+
+ // Clamping
+ start = Clamp(start, 0, axis_size - 1);
+
+ return start;
+}
+
+// Return the "real" index for the end of iteration along that axis. This is an
+// "end" in the traditional C sense, in that it points to one past the last
+// element. ie. So if you were iterating through all elements of a 1D array of
+// size 4, this function would return 4 as the stop, because it is one past the
+// "real" indices of 0, 1, 2 & 3.
+inline int StopForAxis(const StridedSliceParams &params, const loco::TensorShape &input_shape,
+ int axis, int start_for_axis)
+{
+ const auto end_mask = params.end_mask;
+ const auto shrink_axis_mask = params.shrink_axis_mask;
+ const auto *stop_indices = params.stop_indices;
+ const auto *strides = params.strides;
+ const int axis_size = static_cast<int32_t>(input_shape.dim(axis).value());
+ if (axis_size == 0)
+ {
+ return 0;
+ }
+
+ // Begin with the specified index
+ const bool shrink_axis = shrink_axis_mask & (1 << axis);
+ int32_t stop = stop_indices[axis];
+
+ // When shrinking an axis, the end position does not matter (and can be
+ // incorrect when negative indexing is used, see Issue #19260). Always use
+ // start_for_axis + 1 to generate a length 1 slice, since start_for_axis has
+ // already been adjusted for negative indices.
+ if (shrink_axis)
+ {
+ stop = start_for_axis + 1;
+ }
+
+ // end_mask override
+ if (end_mask & (1 << axis))
+ {
+ if (strides[axis] > 0)
+ {
+ // Forward iteration - use the last element. These values will get
+ // clamped below
+ stop = std::numeric_limits<int32_t>::max();
+ }
+ else
+ {
+ // Backward iteration - use the first element.
+ stop = std::numeric_limits<int32_t>::lowest();
+ }
+ }
+
+ // Handle negative indices
+ if (stop < 0)
+ {
+ stop += axis_size;
+ }
+
+ // Clamping
+ // Because the end index points one past the last element, we need slightly
+ // different clamping ranges depending on the direction.
+ if (strides[axis] > 0)
+ {
+ // Forward iteration
+ stop = Clamp(stop, 0, axis_size);
+ }
+ else
+ {
+ // Backward iteration
+ stop = Clamp(stop, -1, axis_size - 1);
+ }
+
+ return stop;
+}
+
+StridedSliceParams BuildStridedSliceParams(const luci::CircleStridedSlice *node)
+{
+ StridedSliceParams op_params;
+
+ if (kMaxDim < node->rank())
+ {
+ INTERNAL_EXN_V("Cannot support StridedSlice rank > ", kMaxDim);
+ }
+
+ auto begin_node = loco::must_cast<luci::CircleConst *>(node->begin());
+ auto end_node = loco::must_cast<luci::CircleConst *>(node->end());
+ auto strides_node = loco::must_cast<luci::CircleConst *>(node->strides());
+
+ uint32_t dims_count = begin_node->size<S32>();
+
+ op_params.start_indices_count = dims_count;
+ op_params.stop_indices_count = dims_count;
+ op_params.strides_count = dims_count;
+
+ for (uint32_t i = 0; i < dims_count; ++i)
+ {
+ op_params.start_indices[i] = begin_node->at<S32>(i);
+ op_params.stop_indices[i] = end_node->at<S32>(i);
+ op_params.strides[i] = strides_node->at<S32>(i);
+ }
+
+ op_params.begin_mask = node->begin_mask();
+ op_params.ellipsis_mask = 0;
+ op_params.end_mask = node->end_mask();
+ op_params.new_axis_mask = 0;
+ op_params.shrink_axis_mask = node->shrink_axis_mask();
+
+ return op_params;
+}
+
+} // namespace
+
+namespace luci
+{
+
+loco::TensorShape infer_output_shape(const CircleStridedSlice *node)
+{
+ loco::TensorShape output_shape;
+
+ auto input_node = loco::must_cast<luci::CircleNode *>(node->input());
+
+ auto begin_node = dynamic_cast<luci::CircleConst *>(node->begin());
+ auto end_node = dynamic_cast<luci::CircleConst *>(node->end());
+ auto strides_node = dynamic_cast<luci::CircleConst *>(node->strides());
+ if (begin_node == nullptr || end_node == nullptr || strides_node == nullptr)
+ {
+ INTERNAL_EXN("StridedSlice begin/end/strides nodes are not Constant");
+ }
+
+ LUCI_ASSERT(begin_node->dtype() == S32, "Only support S32 for begin_node");
+ LUCI_ASSERT(end_node->dtype() == S32, "Only support S32 for end_node");
+ LUCI_ASSERT(strides_node->dtype() == S32, "Only support S32 for strides_node");
+
+ assert(node->ellipsis_mask() == 0);
+ assert(node->new_axis_mask() == 0);
+
+ auto op_params = BuildStridedSliceParams(node);
+ loco::TensorShape input_shape = loco::shape_get(input_node).as<loco::TensorShape>();
+
+ uint32_t num_input_axes = input_shape.rank();
+ assert(begin_node->size<S32>() <= num_input_axes);
+ assert(end_node->size<S32>() <= num_input_axes);
+ assert(strides_node->size<S32>() <= num_input_axes);
+ for (uint32_t i = 0; i < strides_node->size<S32>(); i++)
+ {
+ LUCI_ASSERT(strides_node->at<S32>(i) != 0, "Stride value has to be non-zero");
+ }
+
+ uint32_t shape_size = 0;
+ std::array<int32_t, 16> output_shape_data;
+
+ for (uint32_t idx = 0; idx < num_input_axes; ++idx)
+ {
+ int32_t begin = StartForAxis(op_params, input_shape, idx);
+ int32_t end = StopForAxis(op_params, input_shape, idx, begin);
+ if (end < 0)
+ end = input_shape.dim(idx).value() + end + 1;
+
+ // This is valid for both positive and negative strides
+ int32_t stride = strides_node->at<S32>(idx);
+ int32_t dim_shape = std::ceil(static_cast<float>(end - begin) / stride);
+ assert(dim_shape > 0);
+
+ // When shrinking an axis, the end position does not matter (and can be
+ // incorrect when negative indexing is used, see Issue #19260). Always use
+ // begin + 1 to generate a length 1 slice, since begin has
+ // already been adjusted for negative indices by StartForAxis.
+ const bool shrink_axis = node->shrink_axis_mask() & (1 << idx);
+ if (shrink_axis)
+ {
+ assert(dim_shape == 1);
+ }
+ else
+ {
+ output_shape_data[shape_size++] = dim_shape;
+ }
+ }
+
+ output_shape.rank(shape_size);
+ for (uint32_t idx = 0; idx < shape_size; ++idx)
+ {
+ output_shape.dim(idx) = output_shape_data[idx];
+ }
+
+ return output_shape;
+}
+
+} // namespace luci
diff --git a/compiler/luci/service/src/ShapeInfer_StridedSlice.h b/compiler/luci/service/src/ShapeInfer_StridedSlice.h
new file mode 100644
index 000000000..fa800b720
--- /dev/null
+++ b/compiler/luci/service/src/ShapeInfer_StridedSlice.h
@@ -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.
+ */
+
+#ifndef __SHAPE_INFER_STRIDED_SLICE_H__
+#define __SHAPE_INFER_STRIDED_SLICE_H__
+
+#include <luci/IR/CircleNodes.h>
+
+#include <loco/IR/NodeShape.h>
+
+namespace luci
+{
+
+loco::TensorShape infer_output_shape(const CircleStridedSlice *node);
+
+} // namespace luci
+
+#endif // __SHAPE_INFER_STRIDED_SLICE_H__
diff --git a/compiler/luci/service/src/TestGraph.h b/compiler/luci/service/src/TestGraph.h
index 73562040f..2865b0f44 100644
--- a/compiler/luci/service/src/TestGraph.h
+++ b/compiler/luci/service/src/TestGraph.h
@@ -18,7 +18,6 @@
#define __TEST_GRAPH_H__
#include <luci/IR/CircleNodes.h>
-#include "GraphBlock.h"
#include <loco.h>
@@ -36,29 +35,29 @@ class TestGraph
{
public:
std::unique_ptr<loco::Graph> g;
- loco::Pull *pull;
- loco::Push *push;
+ luci::CircleInput *input_node = nullptr;
+ luci::CircleOutput *output_node = nullptr;
TestGraph() // creates Pull and Push
{
g = loco::make_graph();
- pull = g->nodes()->create<loco::Pull>();
+ input_node = g->nodes()->create<luci::CircleInput>();
- push = g->nodes()->create<loco::Push>();
+ output_node = g->nodes()->create<luci::CircleOutput>();
auto input = g->inputs()->create();
{
input->name("input");
- loco::link(input, pull);
+ luci::link(input, input_node);
}
auto output = g->outputs()->create();
{
output->name("output");
- loco::link(output, push);
+ luci::link(output, output_node);
}
- _next_input = pull;
+ _next_input = input_node;
}
loco::Graph *graph() { return g.get(); }
@@ -73,7 +72,7 @@ public:
}
/// @brief Creates op T (arity=1) with arg1 as an input and appends it to graph
- template <class T> T *append(loco::Node *arg1)
+ template <class T> T *append(luci::CircleNode *arg1)
{
auto node = g->nodes()->create<T>();
setInput(node, arg1);
@@ -83,7 +82,7 @@ public:
}
/// @brief Creates op T (arity=2) with arg1, arg2 as inputs and appends it to graph
- template <class T> T *append(loco::Node *arg1, loco::Node *arg2)
+ template <class T> T *append(luci::CircleNode *arg1, luci::CircleNode *arg2)
{
auto node = g->nodes()->create<T>();
setInput(node, arg1, arg2);
@@ -93,7 +92,8 @@ public:
}
/// @brief Creates op T (arity=3) with arg1, arg2, arg3 as inputs and appends it to graph
- template <class T> T *append(loco::Node *arg1, loco::Node *arg2, loco::Node *arg3)
+ template <class T>
+ T *append(luci::CircleNode *arg1, luci::CircleNode *arg2, luci::CircleNode *arg3)
{
auto node = g->nodes()->create<T>();
setInput(node, arg1, arg2, arg3);
@@ -102,101 +102,68 @@ public:
return node;
}
- // push will get the last appended node
- void complete() { push->from(_next_input); }
+ // output will get the last appended node
+ void complete() { output_node->from(_next_input); }
- void complete(loco::Node *last_node) { push->from(last_node); }
+ void complete(luci::CircleNode *last_node) { output_node->from(last_node); }
private:
// arity 1
- void setInput(loco::Node *node, loco::Node *) { assert(false && "NYI"); };
-
- void setInput(loco::AvgPool2D *node, loco::Node *input) { node->ifm(input); }
- void setInput(loco::BiasDecode *node, loco::Node *input) { node->input(input); };
- void setInput(loco::BiasEncode *node, loco::Node *input) { node->input(input); };
- void setInput(loco::FeatureDecode *node, loco::Node *input) { node->input(input); };
- void setInput(loco::FeatureEncode *node, loco::Node *input) { node->input(input); };
- void setInput(loco::MaxPool2D *node, loco::Node *input) { node->ifm(input); }
- void setInput(loco::Push *node, loco::Node *input) { node->from(input); };
- void setInput(loco::ReLU *node, loco::Node *input) { node->input(input); };
- void setInput(loco::ReLU6 *node, loco::Node *input) { node->input(input); };
- void setInput(loco::Tanh *node, loco::Node *input) { node->input(input); };
- void setInput(loco::TensorTranspose *node, loco::Node *input) { node->input(input); };
-
- void setInput(luci::CircleAveragePool2D *node, loco::Node *input) { node->value(input); };
- void setInput(luci::CircleMaxPool2D *node, loco::Node *input) { node->value(input); };
- void setInput(luci::CircleRelu *node, loco::Node *input) { node->features(input); };
- void setInput(luci::CircleRelu6 *node, loco::Node *input) { node->features(input); };
+ void setInput(luci::CircleNode *, luci::CircleNode *) { assert(false && "NYI"); };
- // arity 2
- void setInput(loco::Node *node, loco::Node *, loco::Node *) { assert(false && "NYI"); };
+ void setInput(luci::CircleAveragePool2D *node, luci::CircleNode *input) { node->value(input); };
+ void setInput(luci::CircleRelu *node, luci::CircleNode *input) { node->features(input); };
+ void setInput(luci::CircleSqueeze *node, luci::CircleNode *input) { node->input(input); };
- void setInput(loco::Conv2D *node, loco::Node *input, loco::Node *filter)
+ void setInput(luci::CircleGatherNd *node, luci::CircleNode *params, luci::CircleNode *indices)
{
- node->ifm(input);
- node->ker(filter);
- }
-
- void setInput(loco::EltwiseAdd *node, loco::Node *arg1, loco::Node *arg2)
- {
- node->lhs(arg1);
- node->rhs(arg2);
+ node->params(params);
+ node->indices(indices);
};
- void setInput(loco::FeatureBiasAdd *node, loco::Node *arg1, loco::Node *arg2)
+ // arity 2
+ void setInput(luci::CircleNode *, luci::CircleNode *, luci::CircleNode *)
{
- node->value(arg1);
- node->bias(arg2);
+ assert(false && "NYI");
};
- void setInput(luci::CircleAdd *node, loco::Node *arg1, loco::Node *arg2)
+ void setInput(luci::CircleExpandDims *node, luci::CircleNode *arg1, luci::CircleNode *arg2)
{
- node->x(arg1);
- node->y(arg2);
+ node->input(arg1);
+ node->axis(arg2);
};
- void setInput(luci::CircleMul *node, loco::Node *arg1, loco::Node *arg2)
+ void setInput(luci::CircleTranspose *node, luci::CircleNode *arg1, luci::CircleNode *arg2)
{
- node->x(arg1);
- node->y(arg2);
+ node->a(arg1);
+ node->perm(arg2);
};
- void setInput(luci::CircleSub *node, loco::Node *arg1, loco::Node *arg2)
+ void setInput(luci::CircleResizeBilinear *node, luci::CircleNode *input, luci::CircleNode *size)
{
- node->x(arg1);
- node->y(arg2);
+ node->input(input);
+ node->size(size);
};
- void setInput(luci::CircleTranspose *node, loco::Node *arg1, loco::Node *arg2)
+ void setInput(luci::CircleResizeNearestNeighbor *node, luci::CircleNode *input,
+ luci::CircleNode *size)
{
- node->a(arg1);
- node->perm(arg2);
+ node->input(input);
+ node->size(size);
};
// arity 3
- void setInput(loco::Node *node, loco::Node *, loco::Node *, loco::Node *)
+ void setInput(luci::CircleNode *, luci::CircleNode *, luci::CircleNode *, luci::CircleNode *)
{
assert(false && "NYI");
};
- void setInput(luci::CircleConv2D *node, loco::Node *input, loco::Node *filter, loco::Node *bias)
- {
- node->input(input);
- node->filter(filter);
- node->bias(bias);
- }
-
private:
loco::Node *_next_input;
};
enum class ExampleGraphType
{
- FeatureBiasAdd,
- ConstGen_ReLU,
- FilterEncode_FilterDecode,
- Transpose,
-
CircleTranspose,
};
@@ -205,109 +172,42 @@ template <ExampleGraphType T> class ExampleGraph;
/**
* @brief Class to create the following:
*
- * Pull - FeatureEncoder - FeatureBiasAdd - FeatureDecode - Push
- * |
- * ConstGen - BiasEncode --+
+ * CircleInput -- CircleTranspose -- CircleOutput
*/
-template <> class ExampleGraph<ExampleGraphType::FeatureBiasAdd> : public TestGraph
+template <> class ExampleGraph<ExampleGraphType::CircleTranspose> : public TestGraph
{
public:
- loco::FeatureEncode *fea_enc = nullptr;
- loco::ConstGen *constgen = nullptr;
- loco::BiasEncode *bias_enc = nullptr;
- loco::FeatureBiasAdd *fea_bias_add = nullptr;
- loco::FeatureDecode *fea_dec = nullptr;
+ luci::CircleConst *const_perm = nullptr;
+ luci::CircleTranspose *transpose_node = nullptr;
public:
ExampleGraph()
{
- fea_enc = luci::make_feature_encode<luci::FeatureLayout::NHWC>(pull);
- constgen = append<loco::ConstGen>();
- bias_enc = append<loco::BiasEncode>(constgen);
- fea_bias_add = append<loco::FeatureBiasAdd>(fea_enc, bias_enc);
- fea_dec = luci::make_feature_decode<luci::FeatureLayout::NHWC>(fea_bias_add);
- complete(fea_dec);
+ const_perm = append<luci::CircleConst>();
+ transpose_node = append<luci::CircleTranspose>(input_node, const_perm);
+ complete(transpose_node);
}
};
-/**
- * @brief Class to creates the following:
- *
- * ConstGen -- ReLU -- Push
- */
-template <> class ExampleGraph<ExampleGraphType::ConstGen_ReLU> : public TestGraph
-{
-public:
- loco::ConstGen *constgen = nullptr;
- loco::ReLU *relu = nullptr;
-
-public:
- ExampleGraph()
- {
- constgen = append<loco::ConstGen>();
- relu = append<loco::ReLU>(constgen);
- complete(relu);
- }
-};
+} // namespace test
+} // namespace luci
-/**
- * @brief Class to creates the following:
- *
- * Pull -- Transpose -- Push
- */
-template <> class ExampleGraph<ExampleGraphType::Transpose> : public TestGraph
+namespace luci
{
-public:
- loco::TensorTranspose *transpose = nullptr;
-
-public:
- ExampleGraph()
- {
- transpose = append<loco::TensorTranspose>(pull);
- complete(transpose);
- }
-};
-
-/**
- * @brief Class to creates the following:
- *
- * Pull -- FilterEncode -- FilterDecode -- Push
- */
-template <> class ExampleGraph<ExampleGraphType::FilterEncode_FilterDecode> : public TestGraph
+namespace test
{
-public:
- loco::FilterEncode *filterEncode = nullptr;
- loco::FilterDecode *filterDecode = nullptr;
-public:
- ExampleGraph()
- {
- filterEncode = luci::make_filter_encode<luci::FilterLayout::HWIO>(pull); // from Tensorflow
- filterDecode =
- luci::make_filter_decode<luci::FilterLayout::OHWI>(filterEncode); // to Tensorflow Lite
- complete(filterDecode);
- }
-};
+/// @brief This will set GraphInput shape from CircleInput shape
+void graph_input_shape(luci::CircleInput *input);
-/**
- * @brief Class to create the following:
- *
- * Pull -- CircleTranspose -- Push
- */
-template <> class ExampleGraph<ExampleGraphType::CircleTranspose> : public TestGraph
-{
-public:
- loco::ConstGen *const_perm = nullptr;
- luci::CircleTranspose *transpose_node = nullptr;
+/// @brief This will set GraphOutput shape from CircleOutput shape
+void graph_output_shape(luci::CircleOutput *output);
-public:
- ExampleGraph()
- {
- const_perm = append<loco::ConstGen>();
- transpose_node = append<luci::CircleTranspose>(pull, const_perm);
- complete(transpose_node);
- }
-};
+/// @brief This will set GraphInput dtype from CircleInput dtype
+void graph_input_dtype(luci::CircleInput *input);
+
+/// @brief This will set GraphOutput dtype from CircleOutput dtype
+void graph_output_dtype(luci::CircleOutput *output);
} // namespace test
} // namespace luci
diff --git a/compiler/luci/service/src/TestGraph.test.cpp b/compiler/luci/service/src/TestGraph.test.cpp
new file mode 100644
index 000000000..9ede70370
--- /dev/null
+++ b/compiler/luci/service/src/TestGraph.test.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestGraph.h"
+
+namespace luci
+{
+namespace test
+{
+
+void graph_input_shape(luci::CircleInput *input)
+{
+ auto index = input->index();
+ auto inputs = input->graph()->inputs();
+
+ for (uint32_t idx = 0; idx < inputs->size(); ++idx)
+ {
+ auto gi = inputs->at(idx);
+ if (gi->index() == index)
+ {
+ auto input_shape = std::make_unique<loco::TensorShape>();
+
+ input_shape->rank(input->rank());
+ for (uint32_t r = 0; r < input->rank(); ++r)
+ input_shape->dim(r) = loco::Dimension(input->dim(r));
+
+ gi->shape(std::move(input_shape));
+ break;
+ }
+ }
+}
+
+void graph_output_shape(luci::CircleOutput *output)
+{
+ auto index = output->index();
+ auto outputs = output->graph()->outputs();
+
+ for (uint32_t idx = 0; idx < outputs->size(); ++idx)
+ {
+ auto go = outputs->at(idx);
+ if (go->index() == index)
+ {
+ auto output_shape = std::make_unique<loco::TensorShape>();
+
+ output_shape->rank(output->rank());
+ for (uint32_t r = 0; r < output->rank(); ++r)
+ output_shape->dim(r) = loco::Dimension(output->dim(r));
+
+ go->shape(std::move(output_shape));
+ break;
+ }
+ }
+}
+
+void graph_input_dtype(luci::CircleInput *input)
+{
+ auto index = input->index();
+ auto inputs = input->graph()->inputs();
+
+ for (uint32_t idx = 0; idx < inputs->size(); ++idx)
+ {
+ auto gi = inputs->at(idx);
+ if (gi->index() == index)
+ {
+ gi->dtype(input->dtype());
+ break;
+ }
+ }
+}
+
+void graph_output_dtype(luci::CircleOutput *output)
+{
+ auto index = output->index();
+ auto outputs = output->graph()->outputs();
+
+ for (uint32_t idx = 0; idx < outputs->size(); ++idx)
+ {
+ auto go = outputs->at(idx);
+ if (go->index() == index)
+ {
+ go->dtype(output->dtype());
+ break;
+ }
+ }
+}
+
+} // namespace test
+} // namespace luci
diff --git a/compiler/luci/service/src/Validate.cpp b/compiler/luci/service/src/Validate.cpp
index 65b82c2b4..282a068e0 100644
--- a/compiler/luci/service/src/Validate.cpp
+++ b/compiler/luci/service/src/Validate.cpp
@@ -29,6 +29,19 @@
namespace
{
+std::ostream &operator<<(std::ostream &os, const loco::TensorShape &tensor_shape)
+{
+ os << "[";
+ for (uint32_t r = 0; r < tensor_shape.rank(); ++r)
+ {
+ if (r)
+ os << ",";
+ os << tensor_shape.dim(r).value();
+ }
+ os << "]";
+ return os;
+}
+
/**
* @brief returns a node that is CircleOutput with index is out_index in nodes
*/
@@ -46,7 +59,7 @@ luci::CircleOutput *find_node(std::vector<loco::Node *> nodes, loco::GraphOutput
return nullptr;
}
-bool validate_shape_type(loco::Graph *g)
+bool validate_shape_dtype(loco::Graph *g)
{
LOGGER(l);
@@ -61,18 +74,18 @@ bool validate_shape_type(loco::Graph *g)
auto circle_output = find_node(output_nodes, out_index);
assert(circle_output != nullptr);
assert(circle_output->from() != nullptr);
- auto circle_node = dynamic_cast<luci::CircleNode *>(circle_output->from());
- assert(circle_node != nullptr);
+ auto circle_node = loco::must_cast<luci::CircleNode *>(circle_output->from());
assert(loco::shape_known(circle_node));
// check if output node shape is same as graph output shape
- auto co_shape = loco::shape_get(circle_node);
+ auto co_tensor_shape = loco::shape_get(circle_node).as<loco::TensorShape>();
auto go_tensor_shape = graph_out->shape();
assert(go_tensor_shape);
- auto go_shape = loco::NodeShape(*go_tensor_shape);
- if (!(co_shape == go_shape))
+ if (!(co_tensor_shape == *go_tensor_shape))
{
- INFO(l) << "Shape for #" << out_index << " not same " << std::endl;
+ INFO(l) << "[luci] Shape for output #" << out_index << " not same " << std::endl;
+ INFO(l) << "[luci] " << circle_node->name() << " " << co_tensor_shape << " vs "
+ << *go_tensor_shape << std::endl;
return false;
}
@@ -80,7 +93,7 @@ bool validate_shape_type(loco::Graph *g)
assert(loco::dtype_known(circle_node));
if (graph_out->dtype() != loco::dtype_get(circle_node))
{
- INFO(l) << "Type for #" << out_index << " not same " << std::endl;
+ INFO(l) << "[luci] Type for output #" << out_index << " not same " << std::endl;
return false;
}
}
@@ -98,7 +111,7 @@ bool validate(loco::Graph *g)
if (!loco::valid(g))
return false;
- if (!validate_shape_type(g))
+ if (!validate_shape_dtype(g))
return false;
// TODO add more validation
diff --git a/compiler/luci/tester/CMakeLists.txt b/compiler/luci/tester/CMakeLists.txt
index bcb47183e..3ac06ef3a 100644
--- a/compiler/luci/tester/CMakeLists.txt
+++ b/compiler/luci/tester/CMakeLists.txt
@@ -1,17 +1,23 @@
+nnas_include(TargetRequire)
+
+unset(REQUIRED_TARGETS)
+list(APPEND REQUIRED_TARGETS safemain)
+TargetRequire_Return(${REQUIRED_TARGETS})
+
set(SRCS_READ_TESTER
src/ReadTester.cpp
- src/Model.cpp
)
add_executable(luci_readtester "${SRCS_READ_TESTER}")
target_link_libraries(luci_readtester PRIVATE luci_import)
target_link_libraries(luci_readtester PRIVATE luci_service)
target_link_libraries(luci_readtester PRIVATE luci_pass)
+target_link_libraries(luci_readtester PRIVATE foder)
target_link_libraries(luci_readtester PRIVATE oops)
+target_link_libraries(luci_readtester PRIVATE safemain)
set(SRCS_WRITE_TESTER
src/WriteTester.cpp
- src/Model.cpp
)
add_executable(luci_writetester "${SRCS_WRITE_TESTER}")
@@ -19,4 +25,6 @@ target_link_libraries(luci_writetester PRIVATE luci_import)
target_link_libraries(luci_writetester PRIVATE luci_service)
target_link_libraries(luci_writetester PRIVATE luci_pass)
target_link_libraries(luci_writetester PRIVATE luci_export)
+target_link_libraries(luci_writetester PRIVATE foder)
target_link_libraries(luci_writetester PRIVATE oops)
+target_link_libraries(luci_writetester PRIVATE safemain)
diff --git a/compiler/luci/tester/src/Model.cpp b/compiler/luci/tester/src/Model.cpp
deleted file mode 100644
index b02c19161..000000000
--- a/compiler/luci/tester/src/Model.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "Model.h"
-
-#include <fstream>
-#include <vector>
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-namespace
-{
-
-class FileModel final : public luci::Model
-{
-public:
- explicit FileModel(const std::string &filename) : _filename(filename) {}
-
-public:
- FileModel(const FileModel &) = delete;
- FileModel(FileModel &&) = delete;
-
-public:
- const ::circle::Model *model(void) override
- {
- std::ifstream file(_filename, std::ios::binary | std::ios::in);
- if (!file.good())
- return nullptr;
-
- file.unsetf(std::ios::skipws);
-
- std::streampos fileSize;
- file.seekg(0, std::ios::end);
- fileSize = file.tellg();
- file.seekg(0, std::ios::beg);
-
- // reserve capacity
- _data.reserve(fileSize);
-
- // read the data
- file.read(_data.data(), fileSize);
- if (file.fail())
- return nullptr;
-
- return ::circle::GetModel(_data.data());
- }
-
-private:
- const std::string _filename;
- std::vector<char> _data;
-};
-
-} // namespace
-
-namespace luci
-{
-
-std::unique_ptr<Model> load_model(const std::string &path)
-{
- return std::make_unique<FileModel>(path);
-}
-
-} // namespace luci
diff --git a/compiler/luci/tester/src/Model.h b/compiler/luci/tester/src/Model.h
deleted file mode 100644
index e40faf33e..000000000
--- a/compiler/luci/tester/src/Model.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __TESTER_MODEL_H__
-#define __TESTER_MODEL_H__
-
-#include <mio/circle/schema_generated.h>
-
-#include <memory>
-
-namespace luci
-{
-
-struct Model
-{
- virtual ~Model() = default;
-
- virtual const ::circle::Model *model(void) = 0;
-};
-
-/**
- * @brief Load Circle model (as a raw Model) from a given path
- *
- * @note May return a nullptr
- */
-std::unique_ptr<Model> load_model(const std::string &path);
-
-} // namespace luci
-
-#endif // __TESTER_MODEL_H__
diff --git a/compiler/luci/tester/src/ReadTester.cpp b/compiler/luci/tester/src/ReadTester.cpp
index c105d6ce3..a1aead1bd 100644
--- a/compiler/luci/tester/src/ReadTester.cpp
+++ b/compiler/luci/tester/src/ReadTester.cpp
@@ -1,4 +1,20 @@
-#include "Model.h"
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <foder/FileLoader.h>
#include <luci/Importer.h>
#include <luci/Service/Validate.h>
@@ -37,7 +53,7 @@ void show_error_message(const char *progname, std::ostream &os, const std::strin
* dump graph to console if set.
* i.e. "LUCI_LOG=1 luci_readtester mymodel.circle"
*/
-int main(int argc, char **argv)
+int entry(int argc, char **argv)
{
if (argc != 2)
{
@@ -50,22 +66,17 @@ int main(int argc, char **argv)
std::cout << "[INFO] Circle is '" << input_path << "'" << std::endl;
// Load model from the file
- std::unique_ptr<luci::Model> model = luci::load_model(input_path);
- if (model == nullptr)
+ foder::FileLoader file_loader{input_path};
+ std::vector<char> model_data = file_loader.load();
+ const circle::Model *circle_model = circle::GetModel(model_data.data());
+ if (circle_model == nullptr)
{
- std::cerr << "ERROR: Failed to load '" << input_path << "'" << std::endl;
- return 255;
- }
-
- const circle::Model *input_model = model->model();
- if (input_model == nullptr)
- {
- std::cerr << "ERROR: Failed to read '" << input_path << "'" << std::endl;
- return 255;
+ std::cerr << "ERROR: Failed to load circle '" << input_path << "'" << std::endl;
+ return EXIT_FAILURE;
}
luci::Importer importer;
- auto module = importer.importModule(input_model);
+ auto module = importer.importModule(circle_model);
assert(module->size() > 0);
for (size_t g = 0; g < module->size(); ++g)
diff --git a/compiler/luci/tester/src/WriteTester.cpp b/compiler/luci/tester/src/WriteTester.cpp
index 80019d1b1..aa7085c77 100644
--- a/compiler/luci/tester/src/WriteTester.cpp
+++ b/compiler/luci/tester/src/WriteTester.cpp
@@ -1,4 +1,20 @@
-#include "Model.h"
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <foder/FileLoader.h>
#include <luci/Importer.h>
#include <luci/Pass/ShapeInferencePass.h>
@@ -52,8 +68,8 @@ public:
bool store(const char *ptr, const size_t size) const final;
private:
- loco::Graph *_graph;
- luci::Module *_module;
+ loco::Graph *_graph{nullptr};
+ luci::Module *_module{nullptr};
const std::string _filepath;
};
@@ -79,7 +95,7 @@ bool CircleExpContract::store(const char *ptr, const size_t size) const
* With the graph, this will use luci_export to write to the second file
* Like ReadTester, LUCI_LOG=1 environment variable is available to dump the graph
*/
-int main(int argc, char **argv)
+int entry(int argc, char **argv)
{
if (argc != 3)
{
@@ -93,23 +109,18 @@ int main(int argc, char **argv)
std::cout << "[INFO] Circle from '" << input_path << "' to '" << output_path << "'" << std::endl;
// Load model from the file
- std::unique_ptr<luci::Model> model = luci::load_model(input_path);
- if (model == nullptr)
+ foder::FileLoader file_loader{input_path};
+ std::vector<char> model_data = file_loader.load();
+ const circle::Model *circle_model = circle::GetModel(model_data.data());
+ if (circle_model == nullptr)
{
- std::cerr << "ERROR: Failed to load '" << input_path << "'" << std::endl;
- return 255;
- }
-
- const circle::Model *input_model = model->model();
- if (input_model == nullptr)
- {
- std::cerr << "ERROR: Failed to read '" << input_path << "'" << std::endl;
- return 255;
+ std::cerr << "ERROR: Failed to load circle '" << input_path << "'" << std::endl;
+ return EXIT_FAILURE;
}
// Import from input Circle file
luci::Importer importer;
- auto module = importer.importModule(input_model);
+ auto module = importer.importModule(circle_model);
assert(module->size() > 0);
for (size_t g = 0; g < module->size(); ++g)
diff --git a/compiler/luci/tests/CMakeLists.txt b/compiler/luci/tests/CMakeLists.txt
index 4e5639047..c03835823 100644
--- a/compiler/luci/tests/CMakeLists.txt
+++ b/compiler/luci/tests/CMakeLists.txt
@@ -65,6 +65,35 @@ foreach(RECIPE IN ITEMS ${RECIPES})
list(APPEND TESTFILES "${CIRCLE_OUTPUT_FILE}")
endforeach(RECIPE)
+# Generate from res/CircleRecipes
+# NOTE duplicate names should not exist or test may be incorrect
+nncc_find_resource(CircleRecipes)
+set(CIRCLERECIPES_DIR "${CircleRecipes_DIR}")
+
+file(GLOB RECIPES2 RELATIVE ${CIRCLERECIPES_DIR} "${CIRCLERECIPES_DIR}/*/test.recipe")
+
+foreach(RECIPE IN ITEMS ${RECIPES2})
+ get_filename_component(RECIPE_PREFIX ${RECIPE} DIRECTORY)
+
+ set(RECIPE_SOURCE_FILE "${RECIPE_PREFIX}.recipe")
+ set(CIRCLE_OUTPUT_FILE "${RECIPE_PREFIX}.circle")
+
+ # Copy .recipe
+ add_custom_command(OUTPUT "${RECIPE_SOURCE_FILE}"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${CIRCLERECIPES_DIR}/${RECIPE}" "${RECIPE_SOURCE_FILE}"
+ DEPENDS "${CIRCLERECIPES_DIR}/${RECIPE}"
+ COMMENT "Generating ${RECIPE_SOURCE_FILE}")
+
+ # Generate .circle
+ add_custom_command(OUTPUT "${CIRCLE_OUTPUT_FILE}"
+ COMMAND circlechef-file "${RECIPE_SOURCE_FILE}" "${CIRCLE_OUTPUT_FILE}"
+ DEPENDS circlechef-file "${RECIPE_SOURCE_FILE}"
+ COMMENT "Generating ${CIRCLE_OUTPUT_FILE}")
+
+ list(APPEND TESTFILES "${CIRCLE_OUTPUT_FILE}")
+endforeach(RECIPE)
+
# Add a dummy target to create a target-level dependency.
# TODO Find a way to create dependency between CTest tests (added below) and generated testfiles.
add_custom_target(luci_testfiles ALL DEPENDS ${TESTFILES})
diff --git a/compiler/luci/tests/readverify.sh b/compiler/luci/tests/readverify.sh
index 3403e9c19..6d6753d39 100755
--- a/compiler/luci/tests/readverify.sh
+++ b/compiler/luci/tests/readverify.sh
@@ -7,6 +7,9 @@
# ./readverify.sh <path/to/luci_readtester> <TEST 1> <TEST 2> ...
VERIFY_SOURCE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+# set LOG enable to execute/test luci/logex codes
+export LUCI_LOG=100
+
WORKDIR="$1"; shift
VERIFY_BINARY_PATH="$1"; shift
diff --git a/compiler/luci/tests/test.lst b/compiler/luci/tests/test.lst
index 08cbd6b1a..188e29828 100644
--- a/compiler/luci/tests/test.lst
+++ b/compiler/luci/tests/test.lst
@@ -1,5 +1,8 @@
+addread(Abs_000)
addread(Add_000)
+addread(Add_001)
addread(Add_U8_000)
+addread(AddN_000)
addread(ArgMax_000)
addread(ArgMax_001)
addread(ArgMax_002)
@@ -8,44 +11,190 @@ addread(ArgMax_U8_000)
addread(ArgMax_U8_001)
addread(ArgMax_U8_002)
addread(ArgMax_U8_003)
+addread(ArgMin_000)
+addread(ArgMin_001)
+addread(ArgMin_002)
+addread(ArgMin_003)
+addread(ArgMin_U8_000)
+addread(ArgMin_U8_001)
+addread(ArgMin_U8_002)
+addread(ArgMin_U8_003)
+addread(AveragePool2D_000)
+addread(BatchMatMul_000)
+addread(BatchMatMulV2_000)
+addread(BatchMatMulV2_001)
addread(BatchToSpaceND_000)
+addread(Cast_000)
+addread(Cast_001)
+addread(Ceil_000)
addread(Concatenation_000)
addread(Concatenation_U8_000)
addread(Conv2D_000)
-addread(Conv2D_U8_000)
addread(Conv2D_002)
+addread(Conv2D_003)
+addread(Conv2D_U8_000)
addread(Cos_000)
+addread(DepthToSpace_000)
addread(DepthwiseConv2D_000)
addread(DepthwiseConv2D_U8_000)
+addread(DepthwiseConv2D_001)
addread(Div_000)
+addread(ELU_000)
addread(Equal_000)
addread(Exp_000)
+addread(ExpandDims_000)
+addread(ExpandDims_001)
+addread(ExpandDims_002)
+addread(ExpandDims_003)
+addread(Fill_000)
+addread(Fill_001)
+addread(Floor_000)
+addread(FloorDiv_000)
+addread(FloorDiv_001)
+addread(FloorMod_000)
+addread(FloorMod_001)
addread(FullyConnected_000)
addread(FullyConnected_001)
+addread(FullyConnected_002)
addread(FullyConnected_U8_000)
+addread(Gather_000)
+addread(GatherNd_000)
+addread(Greater_000)
+addread(GreaterEqual_000)
+addread(If_000)
+addread(If_001)
+addread(L2Normalize_000)
+addread(L2Pool2D_000)
+addread(L2Pool2D_U8_000)
+addread(LeakyRelu_000)
+addread(Less_000)
+addread(LessEqual_000)
+addread(LocalResponseNormalization_000)
+addread(Log_000)
+addread(LogicalAnd_000)
addread(LogicalNot_000)
addread(LogicalOr_000)
+addread(Logistic_000)
+addread(LogSoftmax_000)
+addread(MatMul_000)
+addread(MatrixDiag_000)
+addread(MatrixSetDiag_000)
+addread(Maximum_000)
addread(MaxPool2D_000)
addread(MaxPool2D_U8_000)
addread(Mean_000)
+addread(Mean_001)
+addread(Minimum_000)
+addread(MirrorPad_000)
addread(Mul_000)
addread(Mul_U8_000)
+addread(Neg_000)
+addread(NotEqual_000)
+addread(OneHot_000)
+addread(OneHot_001)
+addread(OneHot_002)
+addread(OneHot_003)
addread(Pack_000)
addread(Pack_U8_000)
addread(Pad_000)
+addread(Pow_000)
+addread(PRelu_000)
+addread(Range_000)
+addread(Rank_000)
+addread(ReduceAny_000)
+addread(ReduceAny_001)
+addread(ReduceAny_002)
+addread(ReduceAny_003)
+addread(ReduceMax_000)
+addread(ReduceMin_000)
+addread(ReduceProd_000)
+addread(ReduceProd_001)
+addread(ReduceProd_002)
+addread(ReduceProd_003)
addread(ReLU_000)
+addread(ReLU6_000)
+addread(ReLUN1To1_000)
addread(Reshape_000)
addread(Reshape_001)
+addread(Reshape_002)
+addread(Reshape_003)
addread(Reshape_U8_000)
+addread(ResizeBilinear_000)
+addread(ResizeNearestNeighbor_000)
+addread(ReverseSequence_000)
+addread(ReverseV2_000)
+addread(Round_000)
addread(Rsqrt_000)
+addread(ScatterNd_000)
+addread(SegmentSum_000)
+addread(Select_000)
+addread(Select_001)
+addread(Select_002)
+addread(SelectV2_000)
+addread(SelectV2_001)
+addread(SelectV2_002)
+addread(Shape_000)
+addread(Sin_000)
+addread(Slice_000)
addread(Softmax_000)
addread(Softmax_U8_000)
+addread(SpaceToBatchND_000)
+addread(SpaceToBatchND_001)
+addread(SpaceToBatchND_002)
+addread(SpaceToBatchND_003)
+addread(SpaceToDepth_000)
+addread(SparseToDense_000)
+addread(Split_000)
+addread(SplitV_000)
+addread(Sqrt_000)
+addread(Square_000)
+addread(SquaredDifference_000)
+addread(Squeeze_000)
+addread(StridedSlice_000)
+addread(StridedSlice_001)
+addread(StridedSlice_002)
addread(Sub_000)
addread(Sub_U8_000)
+addread(Sum_000)
+addread(Sum_001)
+addread(Tanh_000)
+addread(Tile_000)
+addread(Tile_U8_000)
+addread(TopKV2_000)
+addread(TopKV2_001)
addread(Transpose_000)
+addread(TransposeConv_000)
+addread(Unpack_000)
+addread(Unpack_001)
+addread(Unpack_002)
+addread(Unpack_003)
+addread(Where_000)
+addread(Where_001)
+addread(While_000)
+addread(While_001)
+addread(While_002)
+addread(While_003)
+addread(YUV_TO_RGB_U8_000)
+addread(ZerosLike_000)
+
+addread(Net_Dangle_001)
+addread(Net_InstanceNorm_001)
+addread(Net_InstanceNorm_002)
+addread(Net_UnpackAdd_001)
+addread(Net_ZeroDim_001)
+
+# from res/CircleRecipes
+addread(BCQFullyConnected_000)
+addread(BCQFullyConnected_001)
+addread(BCQGather_000)
+addread(CircleBatchMatMul_000)
+addread(InstanceNorm_000)
+addwrite(Abs_000)
addwrite(Add_000)
+addwrite(Add_001)
addwrite(Add_U8_000)
+addwrite(AddN_000)
addwrite(ArgMax_000)
addwrite(ArgMax_001)
addwrite(ArgMax_002)
@@ -54,38 +203,181 @@ addwrite(ArgMax_U8_000)
addwrite(ArgMax_U8_001)
addwrite(ArgMax_U8_002)
addwrite(ArgMax_U8_003)
+addwrite(ArgMin_000)
+addwrite(ArgMin_001)
+addwrite(ArgMin_002)
+addwrite(ArgMin_003)
+addwrite(ArgMin_U8_000)
+addwrite(ArgMin_U8_001)
+addwrite(ArgMin_U8_002)
+addwrite(ArgMin_U8_003)
+addwrite(AveragePool2D_000)
+addwrite(BatchMatMul_000)
+addwrite(BatchMatMulV2_000)
+addwrite(BatchMatMulV2_001)
addwrite(BatchToSpaceND_000)
+addwrite(Cast_000)
+addwrite(Cast_001)
+addwrite(Ceil_000)
addwrite(Concatenation_000)
addwrite(Concatenation_U8_000)
addwrite(Conv2D_000)
-addwrite(Conv2D_U8_000)
addwrite(Conv2D_002)
+addwrite(Conv2D_003)
+addwrite(Conv2D_U8_000)
addwrite(Cos_000)
+addwrite(DepthToSpace_000)
addwrite(DepthwiseConv2D_000)
addwrite(DepthwiseConv2D_U8_000)
+addwrite(DepthwiseConv2D_001)
addwrite(Div_000)
+addwrite(ELU_000)
addwrite(Equal_000)
addwrite(Exp_000)
+addwrite(ExpandDims_000)
+addwrite(ExpandDims_001)
+addwrite(ExpandDims_002)
+addwrite(ExpandDims_003)
+addwrite(Fill_000)
+addwrite(Fill_001)
+addwrite(Floor_000)
+addwrite(FloorDiv_000)
+addwrite(FloorDiv_001)
+addwrite(FloorMod_000)
+addwrite(FloorMod_001)
addwrite(FullyConnected_000)
addwrite(FullyConnected_001)
+addwrite(FullyConnected_002)
addwrite(FullyConnected_U8_000)
+addwrite(Gather_000)
+addwrite(GatherNd_000)
+addwrite(Greater_000)
+addwrite(GreaterEqual_000)
+addwrite(If_000)
+addwrite(If_001)
+addwrite(L2Normalize_000)
+addwrite(L2Pool2D_000)
+addwrite(L2Pool2D_U8_000)
+addwrite(LeakyRelu_000)
+addwrite(Less_000)
+addwrite(LessEqual_000)
+addwrite(LocalResponseNormalization_000)
+addwrite(Log_000)
+addwrite(LogicalAnd_000)
addwrite(LogicalNot_000)
addwrite(LogicalOr_000)
+addwrite(Logistic_000)
+addwrite(LogSoftmax_000)
+addwrite(MatMul_000)
+addwrite(MatrixDiag_000)
+addwrite(MatrixSetDiag_000)
+addwrite(Maximum_000)
addwrite(MaxPool2D_000)
addwrite(MaxPool2D_U8_000)
addwrite(Mean_000)
+addwrite(Mean_001)
+addwrite(Minimum_000)
+addwrite(MirrorPad_000)
addwrite(Mul_000)
addwrite(Mul_U8_000)
+addwrite(Neg_000)
+addwrite(NotEqual_000)
+addwrite(OneHot_000)
+addwrite(OneHot_001)
+addwrite(OneHot_002)
+addwrite(OneHot_003)
addwrite(Pack_000)
addwrite(Pack_U8_000)
addwrite(Pad_000)
+addwrite(Pow_000)
+addwrite(PRelu_000)
+addwrite(Range_000)
+addwrite(Rank_000)
+addwrite(ReduceAny_000)
+addwrite(ReduceAny_001)
+addwrite(ReduceAny_002)
+addwrite(ReduceAny_003)
+addwrite(ReduceMax_000)
+addwrite(ReduceMin_000)
+addwrite(ReduceProd_000)
+addwrite(ReduceProd_001)
+addwrite(ReduceProd_002)
+addwrite(ReduceProd_003)
addwrite(ReLU_000)
+addwrite(ReLU6_000)
+addwrite(ReLUN1To1_000)
addwrite(Reshape_000)
addwrite(Reshape_001)
+addwrite(Reshape_002)
+addwrite(Reshape_003)
addwrite(Reshape_U8_000)
+addwrite(ResizeBilinear_000)
+addwrite(ResizeNearestNeighbor_000)
+addwrite(ReverseSequence_000)
+addwrite(ReverseV2_000)
+addwrite(Round_000)
addwrite(Rsqrt_000)
+addwrite(ScatterNd_000)
+addwrite(SegmentSum_000)
+addwrite(Select_000)
+addwrite(Select_001)
+addwrite(Select_002)
+addwrite(SelectV2_000)
+addwrite(SelectV2_001)
+addwrite(SelectV2_002)
+addwrite(Shape_000)
+addwrite(Sin_000)
+addwrite(Slice_000)
addwrite(Softmax_000)
addwrite(Softmax_U8_000)
+addwrite(SpaceToBatchND_000)
+addwrite(SpaceToBatchND_001)
+addwrite(SpaceToBatchND_002)
+addwrite(SpaceToBatchND_003)
+addwrite(SpaceToDepth_000)
+addwrite(SparseToDense_000)
+addwrite(Split_000)
+addwrite(SplitV_000)
+addwrite(Sqrt_000)
+addwrite(Square_000)
+addwrite(SquaredDifference_000)
+addwrite(Squeeze_000)
+addwrite(StridedSlice_000)
+addwrite(StridedSlice_001)
+addwrite(StridedSlice_002)
addwrite(Sub_000)
addwrite(Sub_U8_000)
+addwrite(Sum_000)
+addwrite(Sum_001)
+addwrite(Tanh_000)
+addwrite(Tile_000)
+addwrite(Tile_U8_000)
+addwrite(TopKV2_000)
+addwrite(TopKV2_001)
addwrite(Transpose_000)
+addwrite(TransposeConv_000)
+addwrite(Unpack_000)
+addwrite(Unpack_001)
+addwrite(Unpack_002)
+addwrite(Unpack_003)
+addwrite(Where_000)
+addwrite(Where_001)
+addwrite(While_000)
+addwrite(While_001)
+addwrite(While_002)
+addwrite(While_003)
+addwrite(YUV_TO_RGB_U8_000)
+addwrite(ZerosLike_000)
+
+addwrite(Net_Dangle_001)
+addwrite(Net_InstanceNorm_001)
+addwrite(Net_InstanceNorm_002)
+addwrite(Net_UnpackAdd_001)
+addwrite(Net_ZeroDim_001)
+
+# from res/CircleRecipes
+addwrite(BCQFullyConnected_000)
+addwrite(BCQFullyConnected_001)
+addwrite(BCQGather_000)
+addwrite(CircleBatchMatMul_000)
+addwrite(InstanceNorm_000)