Skip to content

Commit 1de32b5

Browse files
authored
[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.
1 parent d874a8e commit 1de32b5

File tree

13 files changed

+550
-5
lines changed

13 files changed

+550
-5
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ tvm_file_glob(GLOB_RECURSE COMPILER_SRCS
288288
tvm_file_glob(GLOB CODEGEN_SRCS
289289
src/target/*.cc
290290
src/target/source/*.cc
291+
src/target/parsers/*.cc
291292
)
292293

293294
list(APPEND COMPILER_SRCS ${CODEGEN_SRCS})

include/tvm/target/target_kind.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ namespace tvm {
3737

3838
class Target;
3939

40+
/*!
41+
* \brief Map containing parsed features of a specific Target
42+
*/
43+
using TargetFeatures = Map<String, ObjectRef>;
44+
4045
/*!
4146
* \brief TargetParser to apply on instantiation of a given TargetKind
4247
*

python/tvm/target/target.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ def intel_graphics(model="unknown", options=None):
442442
"imxrt10xx": ["-mcpu=cortex-m7"],
443443
"mps2_an521": ["-mcpu=cortex-m33"],
444444
"mps3_an547": ["-mcpu=cortex-m55"],
445-
"nrf52840": ["-mcpu=cortex-m4"],
445+
"nrf52840": ["-mcpu=cortex-m4+nodsp"],
446446
"nrf5340dk": ["-mcpu=cortex-m33"],
447447
"rp2040": ["-mcpu=cortex-m0"],
448448
"sam3x8e": ["-mcpu=cortex-m3"],

src/target/parsers/cpu.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
#include "cpu.h"
20+
21+
#include <string>
22+
23+
#include "mprofile.h"
24+
25+
namespace tvm {
26+
namespace target {
27+
namespace parsers {
28+
namespace cpu {
29+
30+
TargetJSON ParseTarget(TargetJSON target) {
31+
if (mprofile::IsArch(target)) {
32+
return mprofile::ParseTarget(target);
33+
}
34+
35+
return target;
36+
}
37+
38+
} // namespace cpu
39+
} // namespace parsers
40+
} // namespace target
41+
} // namespace tvm

src/target/parsers/cpu.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* \file tvm/target/parsers/cpu.h
22+
* \brief Target Parser for CPU Target's
23+
*/
24+
25+
#ifndef TVM_TARGET_PARSERS_CPU_H_
26+
#define TVM_TARGET_PARSERS_CPU_H_
27+
28+
#include <tvm/target/target.h>
29+
30+
namespace tvm {
31+
namespace target {
32+
namespace parsers {
33+
namespace cpu {
34+
35+
TargetJSON ParseTarget(TargetJSON target);
36+
37+
} // namespace cpu
38+
} // namespace parsers
39+
} // namespace target
40+
} // namespace tvm
41+
42+
#endif // TVM_TARGET_PARSERS_CPU_H_

src/target/parsers/mprofile.cc

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* \file tvm/target/parsers/mprofile.cc
22+
* \brief Target Parser for Arm(R) Cortex(R) M-Profile CPUs
23+
*/
24+
25+
#include "mprofile.h"
26+
27+
#include <string>
28+
29+
namespace tvm {
30+
namespace target {
31+
namespace parsers {
32+
namespace mprofile {
33+
34+
const TargetFeatures kNoExt = {{"has_dsp", Bool(false)}, {"has_mve", Bool(false)}};
35+
const TargetFeatures kHasDSP = {{"has_dsp", Bool(true)}, {"has_mve", Bool(false)}};
36+
const TargetFeatures kHasMVE = {{"has_dsp", Bool(true)}, {"has_mve", Bool(true)}};
37+
38+
static const char* baseCPUs[] = {"cortex-m0", "cortex-m3"};
39+
static const char* dspCPUs[] = {"cortex-m55", "cortex-m4", "cortex-m7", "cortex-m33",
40+
"cortex-m35p"};
41+
static const char* mveCPUs[] = {"cortex-m55"};
42+
43+
template <typename Container>
44+
static inline bool MatchesCpu(Optional<String> mcpu, const Container& cpus) {
45+
if (!mcpu) {
46+
return false;
47+
}
48+
std::string mcpu_string = mcpu.value();
49+
auto matches_cpu = [mcpu_string](const char* cpu) { return mcpu_string.find(cpu) == 0; };
50+
return std::find_if(std::begin(cpus), std::end(cpus), matches_cpu) != std::end(cpus);
51+
}
52+
53+
static inline bool HasFlag(String attr, std::string flag) {
54+
std::string attr_str = attr;
55+
return attr_str.find(flag) != std::string::npos;
56+
}
57+
58+
static inline bool HasFlag(Optional<String> attr, std::string flag) {
59+
if (!attr) {
60+
return false;
61+
}
62+
return HasFlag(attr.value(), flag);
63+
}
64+
65+
static inline bool HasFlag(Optional<Array<String>> attr, std::string flag) {
66+
if (!attr) {
67+
return false;
68+
}
69+
Array<String> attr_array = attr.value();
70+
71+
auto matching_attr = std::find_if(attr_array.begin(), attr_array.end(),
72+
[flag](String attr_str) { return HasFlag(attr_str, flag); });
73+
return matching_attr != attr_array.end();
74+
}
75+
76+
bool IsArch(TargetJSON attrs) {
77+
Optional<String> mcpu = Downcast<Optional<String>>(attrs.Get("mcpu"));
78+
if (mcpu) {
79+
bool matches_base = MatchesCpu(mcpu, baseCPUs);
80+
bool matches_dsp = MatchesCpu(mcpu, dspCPUs);
81+
bool matches_mve = MatchesCpu(mcpu, mveCPUs);
82+
return matches_base || matches_mve || matches_dsp;
83+
}
84+
return false;
85+
}
86+
87+
static TargetFeatures GetFeatures(TargetJSON target) {
88+
Optional<String> mcpu = Downcast<Optional<String>>(target.Get("mcpu"));
89+
Optional<Array<String>> mattr = Downcast<Optional<Array<String>>>(target.Get("mattr"));
90+
91+
bool nomve = HasFlag(mcpu, "+nomve") || HasFlag(mattr, "+nomve");
92+
bool nodsp = HasFlag(mcpu, "+nodsp") || HasFlag(mattr, "+nodsp");
93+
94+
bool has_mve = MatchesCpu(mcpu, mveCPUs);
95+
if (has_mve && !nomve && !nodsp) {
96+
return kHasMVE;
97+
}
98+
99+
bool has_dsp = MatchesCpu(mcpu, dspCPUs);
100+
if (has_dsp && !nodsp) {
101+
return kHasDSP;
102+
}
103+
104+
return kNoExt;
105+
}
106+
107+
static Array<String> MergeKeys(Optional<Array<String>> existing_keys) {
108+
const String kExtraKey = "arm_cpu";
109+
110+
if (!existing_keys) {
111+
return {kExtraKey};
112+
}
113+
114+
Array<String> keys = existing_keys.value();
115+
if (std::find(keys.begin(), keys.end(), kExtraKey) == keys.end()) {
116+
keys.push_back(kExtraKey);
117+
}
118+
return keys;
119+
}
120+
121+
TargetJSON ParseTarget(TargetJSON target) {
122+
target.Set("features", GetFeatures(target));
123+
target.Set("keys", MergeKeys(Downcast<Optional<Array<String>>>(target.Get("keys"))));
124+
125+
return target;
126+
}
127+
128+
} // namespace mprofile
129+
} // namespace parsers
130+
} // namespace target
131+
} // namespace tvm

src/target/parsers/mprofile.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* \file tvm/target/parsers/mprofile.h
22+
* \brief Target Parser for Arm(R) Cortex(R) M-Profile CPUs
23+
*/
24+
25+
#ifndef TVM_TARGET_PARSERS_MPROFILE_H_
26+
#define TVM_TARGET_PARSERS_MPROFILE_H_
27+
28+
#include <tvm/target/target.h>
29+
30+
namespace tvm {
31+
namespace target {
32+
namespace parsers {
33+
namespace mprofile {
34+
35+
bool IsArch(TargetJSON target);
36+
TargetJSON ParseTarget(TargetJSON target);
37+
38+
} // namespace mprofile
39+
} // namespace parsers
40+
} // namespace target
41+
} // namespace tvm
42+
43+
#endif // TVM_TARGET_PARSERS_MPROFILE_H_

src/target/target_kind.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <algorithm>
3131

3232
#include "../node/attr_registry.h"
33+
#include "./parsers/cpu.h"
3334

3435
namespace tvm {
3536

@@ -281,7 +282,8 @@ TVM_REGISTER_TARGET_KIND("llvm", kDLCPU)
281282
.set_default_keys({"cpu"})
282283
// Force the external codegen kind attribute to be registered, even if no external
283284
// codegen targets are enabled by the TVM build.
284-
.set_attr<Bool>(tvm::attr::kIsExternalCodegen, Bool(false));
285+
.set_attr<Bool>(tvm::attr::kIsExternalCodegen, Bool(false))
286+
.set_target_parser(tvm::target::parsers::cpu::ParseTarget);
285287

286288
TVM_REGISTER_TARGET_KIND("c", kDLCPU)
287289
.add_attr_option<Bool>("system-lib")
@@ -294,7 +296,8 @@ TVM_REGISTER_TARGET_KIND("c", kDLCPU)
294296
.add_attr_option<Integer>("constants-byte-alignment")
295297
.add_attr_option<Bool>("unpacked-api")
296298
.add_attr_option<String>("interface-api")
297-
.set_default_keys({"cpu"});
299+
.set_default_keys({"cpu"})
300+
.set_target_parser(tvm::target::parsers::cpu::ParseTarget);
298301

299302
TVM_REGISTER_TARGET_KIND("cuda", kDLCUDA)
300303
.add_attr_option<String>("mcpu")

0 commit comments

Comments
 (0)