From fc355de5555210d42709a33eea512c847d1d3bb5 Mon Sep 17 00:00:00 2001 From: Christopher Sidebottom Date: Fri, 12 Aug 2022 16:31:34 +0100 Subject: [PATCH] [Target] Add Target Parser for Arm(R) Cortex(R) M-Profile CPUs (#12319) This implements an initial Target Parser which uses the same logic as the CMSIS-NN compiler flags to update the features and keys of the `c` and `llvm` `Target`s. Refactoring of the CMSIS-NN logic will be in a separate patch. --- CMakeLists.txt | 1 + include/tvm/target/target_kind.h | 5 + python/tvm/target/target.py | 2 +- src/target/parsers/cpu.cc | 41 ++++ src/target/parsers/cpu.h | 42 ++++ src/target/parsers/mprofile.cc | 131 +++++++++++ src/target/parsers/mprofile.h | 43 ++++ src/target/target_kind.cc | 7 +- tests/cpp/target/parsers/mprofile_test.cc | 218 ++++++++++++++++++ .../python/driver/tvmc/test_target_options.py | 2 +- .../unittest/test_target_parser_mprofile.py | 60 +++++ tests/python/unittest/test_target_target.py | 1 - tests/scripts/task_python_docs.sh | 2 + 13 files changed, 550 insertions(+), 5 deletions(-) create mode 100644 src/target/parsers/cpu.cc create mode 100644 src/target/parsers/cpu.h create mode 100644 src/target/parsers/mprofile.cc create mode 100644 src/target/parsers/mprofile.h create mode 100644 tests/cpp/target/parsers/mprofile_test.cc create mode 100644 tests/python/unittest/test_target_parser_mprofile.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bc4d1823fa1..8995f9a87fb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -288,6 +288,7 @@ tvm_file_glob(GLOB_RECURSE COMPILER_SRCS tvm_file_glob(GLOB CODEGEN_SRCS src/target/*.cc src/target/source/*.cc + src/target/parsers/*.cc ) list(APPEND COMPILER_SRCS ${CODEGEN_SRCS}) diff --git a/include/tvm/target/target_kind.h b/include/tvm/target/target_kind.h index e20f8547af49..96a6f27a8672 100644 --- a/include/tvm/target/target_kind.h +++ b/include/tvm/target/target_kind.h @@ -37,6 +37,11 @@ namespace tvm { class Target; +/*! + * \brief Map containing parsed features of a specific Target + */ +using TargetFeatures = Map; + /*! * \brief TargetParser to apply on instantiation of a given TargetKind * diff --git a/python/tvm/target/target.py b/python/tvm/target/target.py index ab646ab83c63..e53c7096279c 100644 --- a/python/tvm/target/target.py +++ b/python/tvm/target/target.py @@ -442,7 +442,7 @@ def intel_graphics(model="unknown", options=None): "imxrt10xx": ["-mcpu=cortex-m7"], "mps2_an521": ["-mcpu=cortex-m33"], "mps3_an547": ["-mcpu=cortex-m55"], - "nrf52840": ["-mcpu=cortex-m4"], + "nrf52840": ["-mcpu=cortex-m4+nodsp"], "nrf5340dk": ["-mcpu=cortex-m33"], "rp2040": ["-mcpu=cortex-m0"], "sam3x8e": ["-mcpu=cortex-m3"], diff --git a/src/target/parsers/cpu.cc b/src/target/parsers/cpu.cc new file mode 100644 index 000000000000..fbf55f468313 --- /dev/null +++ b/src/target/parsers/cpu.cc @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include "cpu.h" + +#include + +#include "mprofile.h" + +namespace tvm { +namespace target { +namespace parsers { +namespace cpu { + +TargetJSON ParseTarget(TargetJSON target) { + if (mprofile::IsArch(target)) { + return mprofile::ParseTarget(target); + } + + return target; +} + +} // namespace cpu +} // namespace parsers +} // namespace target +} // namespace tvm diff --git a/src/target/parsers/cpu.h b/src/target/parsers/cpu.h new file mode 100644 index 000000000000..588f98eea043 --- /dev/null +++ b/src/target/parsers/cpu.h @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file tvm/target/parsers/cpu.h + * \brief Target Parser for CPU Target's + */ + +#ifndef TVM_TARGET_PARSERS_CPU_H_ +#define TVM_TARGET_PARSERS_CPU_H_ + +#include + +namespace tvm { +namespace target { +namespace parsers { +namespace cpu { + +TargetJSON ParseTarget(TargetJSON target); + +} // namespace cpu +} // namespace parsers +} // namespace target +} // namespace tvm + +#endif // TVM_TARGET_PARSERS_CPU_H_ diff --git a/src/target/parsers/mprofile.cc b/src/target/parsers/mprofile.cc new file mode 100644 index 000000000000..7fb61ff893b6 --- /dev/null +++ b/src/target/parsers/mprofile.cc @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file tvm/target/parsers/mprofile.cc + * \brief Target Parser for Arm(R) Cortex(R) M-Profile CPUs + */ + +#include "mprofile.h" + +#include + +namespace tvm { +namespace target { +namespace parsers { +namespace mprofile { + +const TargetFeatures kNoExt = {{"has_dsp", Bool(false)}, {"has_mve", Bool(false)}}; +const TargetFeatures kHasDSP = {{"has_dsp", Bool(true)}, {"has_mve", Bool(false)}}; +const TargetFeatures kHasMVE = {{"has_dsp", Bool(true)}, {"has_mve", Bool(true)}}; + +static const char* baseCPUs[] = {"cortex-m0", "cortex-m3"}; +static const char* dspCPUs[] = {"cortex-m55", "cortex-m4", "cortex-m7", "cortex-m33", + "cortex-m35p"}; +static const char* mveCPUs[] = {"cortex-m55"}; + +template +static inline bool MatchesCpu(Optional mcpu, const Container& cpus) { + if (!mcpu) { + return false; + } + std::string mcpu_string = mcpu.value(); + auto matches_cpu = [mcpu_string](const char* cpu) { return mcpu_string.find(cpu) == 0; }; + return std::find_if(std::begin(cpus), std::end(cpus), matches_cpu) != std::end(cpus); +} + +static inline bool HasFlag(String attr, std::string flag) { + std::string attr_str = attr; + return attr_str.find(flag) != std::string::npos; +} + +static inline bool HasFlag(Optional attr, std::string flag) { + if (!attr) { + return false; + } + return HasFlag(attr.value(), flag); +} + +static inline bool HasFlag(Optional> attr, std::string flag) { + if (!attr) { + return false; + } + Array attr_array = attr.value(); + + auto matching_attr = std::find_if(attr_array.begin(), attr_array.end(), + [flag](String attr_str) { return HasFlag(attr_str, flag); }); + return matching_attr != attr_array.end(); +} + +bool IsArch(TargetJSON attrs) { + Optional mcpu = Downcast>(attrs.Get("mcpu")); + if (mcpu) { + bool matches_base = MatchesCpu(mcpu, baseCPUs); + bool matches_dsp = MatchesCpu(mcpu, dspCPUs); + bool matches_mve = MatchesCpu(mcpu, mveCPUs); + return matches_base || matches_mve || matches_dsp; + } + return false; +} + +static TargetFeatures GetFeatures(TargetJSON target) { + Optional mcpu = Downcast>(target.Get("mcpu")); + Optional> mattr = Downcast>>(target.Get("mattr")); + + bool nomve = HasFlag(mcpu, "+nomve") || HasFlag(mattr, "+nomve"); + bool nodsp = HasFlag(mcpu, "+nodsp") || HasFlag(mattr, "+nodsp"); + + bool has_mve = MatchesCpu(mcpu, mveCPUs); + if (has_mve && !nomve && !nodsp) { + return kHasMVE; + } + + bool has_dsp = MatchesCpu(mcpu, dspCPUs); + if (has_dsp && !nodsp) { + return kHasDSP; + } + + return kNoExt; +} + +static Array MergeKeys(Optional> existing_keys) { + const String kExtraKey = "arm_cpu"; + + if (!existing_keys) { + return {kExtraKey}; + } + + Array keys = existing_keys.value(); + if (std::find(keys.begin(), keys.end(), kExtraKey) == keys.end()) { + keys.push_back(kExtraKey); + } + return keys; +} + +TargetJSON ParseTarget(TargetJSON target) { + target.Set("features", GetFeatures(target)); + target.Set("keys", MergeKeys(Downcast>>(target.Get("keys")))); + + return target; +} + +} // namespace mprofile +} // namespace parsers +} // namespace target +} // namespace tvm diff --git a/src/target/parsers/mprofile.h b/src/target/parsers/mprofile.h new file mode 100644 index 000000000000..27f0e28595b9 --- /dev/null +++ b/src/target/parsers/mprofile.h @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file tvm/target/parsers/mprofile.h + * \brief Target Parser for Arm(R) Cortex(R) M-Profile CPUs + */ + +#ifndef TVM_TARGET_PARSERS_MPROFILE_H_ +#define TVM_TARGET_PARSERS_MPROFILE_H_ + +#include + +namespace tvm { +namespace target { +namespace parsers { +namespace mprofile { + +bool IsArch(TargetJSON target); +TargetJSON ParseTarget(TargetJSON target); + +} // namespace mprofile +} // namespace parsers +} // namespace target +} // namespace tvm + +#endif // TVM_TARGET_PARSERS_MPROFILE_H_ diff --git a/src/target/target_kind.cc b/src/target/target_kind.cc index 0d3e7b0a424c..0b868627239a 100644 --- a/src/target/target_kind.cc +++ b/src/target/target_kind.cc @@ -30,6 +30,7 @@ #include #include "../node/attr_registry.h" +#include "./parsers/cpu.h" namespace tvm { @@ -281,7 +282,8 @@ TVM_REGISTER_TARGET_KIND("llvm", kDLCPU) .set_default_keys({"cpu"}) // Force the external codegen kind attribute to be registered, even if no external // codegen targets are enabled by the TVM build. - .set_attr(tvm::attr::kIsExternalCodegen, Bool(false)); + .set_attr(tvm::attr::kIsExternalCodegen, Bool(false)) + .set_target_parser(tvm::target::parsers::cpu::ParseTarget); TVM_REGISTER_TARGET_KIND("c", kDLCPU) .add_attr_option("system-lib") @@ -294,7 +296,8 @@ TVM_REGISTER_TARGET_KIND("c", kDLCPU) .add_attr_option("constants-byte-alignment") .add_attr_option("unpacked-api") .add_attr_option("interface-api") - .set_default_keys({"cpu"}); + .set_default_keys({"cpu"}) + .set_target_parser(tvm::target::parsers::cpu::ParseTarget); TVM_REGISTER_TARGET_KIND("cuda", kDLCUDA) .add_attr_option("mcpu") diff --git a/tests/cpp/target/parsers/mprofile_test.cc b/tests/cpp/target/parsers/mprofile_test.cc new file mode 100644 index 000000000000..0dcc23141ddb --- /dev/null +++ b/tests/cpp/target/parsers/mprofile_test.cc @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "../src/target/parsers/mprofile.h" + +#include + +#include +#include + +namespace tvm { +namespace target { +namespace parsers { +namespace mprofile { + +static const char* mveCPUs[] = {"cortex-m55"}; +static const char* dspCPUs[] = {"cortex-m4", "cortex-m7", "cortex-m33", "cortex-m35p"}; +static const char* noExtensions[] = {"cortex-m0", "cortex-m3"}; + +class MProfileParserMVECPUs : public testing::TestWithParam {}; +class MProfileParserDSPCPUs : public testing::TestWithParam {}; +class MProfileParserNoExtensions : public testing::TestWithParam {}; + +static TargetFeatures ParseTargetWithAttrs(String mcpu, Array mattr) { + return ParseTarget({{"mcpu", mcpu}, {"mattr", mattr}}); +} + +TEST(MProfileParser, CheckIsNotArch) { + String mcpu = "cake"; + TargetJSON fake_target = {{"mcpu", mcpu}}; + ASSERT_EQ(IsArch(fake_target), false); +} + +TEST_P(MProfileParserMVECPUs, CheckIsArch) { + String mcpu = GetParam(); + TargetJSON fake_target = {{"mcpu", mcpu}}; + ASSERT_EQ(IsArch(fake_target), true); +} + +TEST_P(MProfileParserDSPCPUs, CheckIsArch) { + String mcpu = GetParam(); + TargetJSON fake_target = {{"mcpu", mcpu}}; + ASSERT_EQ(IsArch(fake_target), true); +} + +TEST_P(MProfileParserNoExtensions, CheckIsArch) { + String mcpu = GetParam(); + TargetJSON fake_target = {{"mcpu", mcpu}}; + ASSERT_EQ(IsArch(fake_target), true); +} + +TEST(MProfileParser, ParseTarget) { + TargetJSON target = ParseTarget({}); + TargetFeatures features = Downcast(target.at("features")); + Array keys = Downcast>(target.at("keys")); + ASSERT_EQ(keys.size(), 1); + ASSERT_EQ(keys[0], "arm_cpu"); + + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); +} + +TEST(MProfileParser, ParseTargetWithExistingKeys) { + TargetJSON target = ParseTarget({ + {"keys", Array{"cpu"}}, + }); + TargetFeatures features = Downcast(target.at("features")); + Array keys = Downcast>(target.at("keys")); + ASSERT_EQ(keys.size(), 2); + ASSERT_EQ(keys[0], "cpu"); + ASSERT_EQ(keys[1], "arm_cpu"); +} + +TEST(MProfileParser, ParseTargetWithDuplicateKey) { + TargetJSON target = ParseTarget({ + {"keys", Array{"cpu", "arm_cpu"}}, + }); + TargetFeatures features = Downcast(target.at("features")); + Array keys = Downcast>(target.at("keys")); + ASSERT_EQ(keys.size(), 2); + ASSERT_EQ(keys[0], "cpu"); + ASSERT_EQ(keys[1], "arm_cpu"); +} + +TEST_P(MProfileParserMVECPUs, CheckMVESet) { + TargetJSON target = ParseTargetWithAttrs(GetParam(), {""}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), true); + ASSERT_EQ(Downcast(features.at("has_dsp")), true); +} + +TEST_P(MProfileParserMVECPUs, CheckMVEOverrideCPU) { + std::string mcpu = GetParam(); + TargetJSON target = ParseTargetWithAttrs(mcpu + "+nomve", {""}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), true); +} + +TEST_P(MProfileParserMVECPUs, CheckDSPOverrideCPU) { + std::string mcpu = GetParam(); + TargetJSON target = ParseTargetWithAttrs(mcpu + "+nodsp", {""}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); +} + +TEST_P(MProfileParserMVECPUs, CheckCombinedOverrideCPU) { + std::string mcpu = GetParam(); + TargetJSON target = ParseTargetWithAttrs(mcpu + "+nodsp+nomve", {""}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); + target = ParseTargetWithAttrs(mcpu + "+nomve+nodsp", {""}); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); +} + +TEST_P(MProfileParserMVECPUs, CheckMVEOverrideMAttr) { + TargetJSON target = ParseTargetWithAttrs(GetParam(), {"+nomve"}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), true); +} + +TEST_P(MProfileParserMVECPUs, CheckDSPOverrideMattr) { + TargetJSON target = ParseTargetWithAttrs(GetParam(), {"+nodsp"}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); +} + +TEST_P(MProfileParserMVECPUs, CheckCombinedOverrideMattr) { + TargetJSON target = ParseTargetWithAttrs(GetParam(), {"+nodsp", "+nomve"}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); + + target = ParseTargetWithAttrs(GetParam(), {"+nomve+nodsp"}); + features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); + + target = ParseTargetWithAttrs(GetParam(), {"+nomve", "+nodsp"}); + features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); + + target = ParseTargetWithAttrs(GetParam(), {"+woofles", "+nomve", "+nodsp"}); + features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); +} + +TEST_P(MProfileParserDSPCPUs, CheckDSPSet) { + TargetJSON target = ParseTargetWithAttrs(GetParam(), {""}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), true); +} + +TEST_P(MProfileParserDSPCPUs, CheckDSPOverrideCPU) { + std::string mcpu = GetParam(); + TargetJSON target = ParseTargetWithAttrs(mcpu + "+nodsp", {""}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); + + target = ParseTargetWithAttrs(mcpu + "+nodsp+woofles", {""}); + features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); +} + +TEST_P(MProfileParserDSPCPUs, CheckDSPOverrideMattr) { + TargetJSON target = ParseTargetWithAttrs(GetParam(), {"+nodsp"}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); + + target = ParseTargetWithAttrs(GetParam(), {"+nodsp", "+woofles"}); + features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); +} + +TEST_P(MProfileParserNoExtensions, CheckNoFlags) { + TargetJSON target = ParseTargetWithAttrs(GetParam(), {""}); + TargetFeatures features = Downcast(target.at("features")); + ASSERT_EQ(Downcast(features.at("has_mve")), false); + ASSERT_EQ(Downcast(features.at("has_dsp")), false); +} + +INSTANTIATE_TEST_CASE_P(MProfileParser, MProfileParserMVECPUs, ::testing::ValuesIn(mveCPUs)); +INSTANTIATE_TEST_CASE_P(MProfileParser, MProfileParserDSPCPUs, ::testing::ValuesIn(dspCPUs)); +INSTANTIATE_TEST_CASE_P(MProfileParser, MProfileParserNoExtensions, + ::testing::ValuesIn(noExtensions)); + +} // namespace mprofile +} // namespace parsers +} // namespace target +} // namespace tvm diff --git a/tests/python/driver/tvmc/test_target_options.py b/tests/python/driver/tvmc/test_target_options.py index 771d94caf146..c73dc288cdd8 100644 --- a/tests/python/driver/tvmc/test_target_options.py +++ b/tests/python/driver/tvmc/test_target_options.py @@ -86,7 +86,7 @@ def test_skip_target_from_codegen(): def test_target_recombobulation_single(): tvm_target, _ = target_from_cli("llvm", {"llvm": {"mcpu": "cortex-m3"}}) - assert str(tvm_target) == "llvm -keys=cpu -link-params=0 -mcpu=cortex-m3" + assert str(tvm_target) == "llvm -keys=arm_cpu,cpu -link-params=0 -mcpu=cortex-m3" def test_target_recombobulation_many(): diff --git a/tests/python/unittest/test_target_parser_mprofile.py b/tests/python/unittest/test_target_parser_mprofile.py new file mode 100644 index 000000000000..566b8deb0e52 --- /dev/null +++ b/tests/python/unittest/test_target_parser_mprofile.py @@ -0,0 +1,60 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +""" +Tests to verify Python interactions with Target Parsing +""" + +import pytest + +from tvm.target import Target + + +@pytest.mark.parametrize(["cpu_target"], [["c"], ["llvm"]]) +def test_target_parser_mprofile(cpu_target): + parsed_target = Target(f"{cpu_target} -mcpu=cortex-m55") + assert len(parsed_target.keys) == 2 + assert parsed_target.keys[0] == "arm_cpu" + assert parsed_target.keys[1] == "cpu" + assert parsed_target.features + assert parsed_target.features.has_dsp + assert parsed_target.features.has_mve + + +@pytest.mark.parametrize(["cpu_target"], [["c"], ["llvm"]]) +def test_target_parser_mprofile_no_mve(cpu_target): + parsed_target = Target(f"{cpu_target} -mcpu=cortex-m7") + assert len(parsed_target.keys) == 2 + assert parsed_target.keys[0] == "arm_cpu" + assert parsed_target.keys[1] == "cpu" + assert parsed_target.features + assert parsed_target.features.has_dsp + assert not parsed_target.features.has_mve + + +@pytest.mark.parametrize(["cpu_target"], [["c"], ["llvm"]]) +def test_target_parser_mprofile_no_dsp(cpu_target): + parsed_target = Target(f"{cpu_target} -mcpu=cortex-m3") + assert len(parsed_target.keys) == 2 + assert parsed_target.keys[0] == "arm_cpu" + assert parsed_target.keys[1] == "cpu" + assert parsed_target.features + assert not parsed_target.features.has_dsp + assert not parsed_target.features.has_mve + + +if __name__ == "__main__": + tvm.testing.main() diff --git a/tests/python/unittest/test_target_target.py b/tests/python/unittest/test_target_target.py index ef55abfa4dcd..702ffb44ac83 100644 --- a/tests/python/unittest/test_target_target.py +++ b/tests/python/unittest/test_target_target.py @@ -15,7 +15,6 @@ # specific language governing permissions and limitations # under the License. import json -import sys import pytest import tvm diff --git a/tests/scripts/task_python_docs.sh b/tests/scripts/task_python_docs.sh index da1a2c9c5636..8b390c962e98 100755 --- a/tests/scripts/task_python_docs.sh +++ b/tests/scripts/task_python_docs.sh @@ -81,6 +81,8 @@ IGNORED_WARNINGS=( 'gen_gallery extension is not safe for parallel' 'strategy:conv2d NHWC layout is not optimized for x86 with autotvm.' 'strategy:depthwise_conv2d NHWC layout is not optimized for x86 with autotvm.' + 'strategy:depthwise_conv2d with layout NHWC is not optimized for arm cpu.' + 'strategy:dense is not optimized for arm cpu.' 'autotvm:Cannot find config for target=llvm -keys=cpu -link-params=0' 'autotvm:One or more operators have not been tuned. Please tune your model for better performance. Use DEBUG logging level to see more details.' 'autotvm:Cannot find config for target=cuda -keys=cuda,gpu'