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
29namespace tvm {
30namespace target {
31namespace parsers {
32namespace mprofile {
33
34const TargetFeatures kNoExt = {{"has_dsp", Bool(false)}, {"has_mve", Bool(false)}};
35const TargetFeatures kHasDSP = {{"has_dsp", Bool(true)}, {"has_mve", Bool(false)}};
36const TargetFeatures kHasMVE = {{"has_dsp", Bool(true)}, {"has_mve", Bool(true)}};
37
38static const char* baseCPUs[] = {"cortex-m0", "cortex-m3"};
39static const char* dspCPUs[] = {"cortex-m55", "cortex-m4", "cortex-m7",
40 "cortex-m33", "cortex-m35p", "cortex-m85"};
41static const char* mveCPUs[] = {"cortex-m55", "cortex-m85"};
42
43template <typename Container>
44static 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
53static 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
58static inline bool HasFlag(Optional<String> attr, std::string flag) {
59 if (!attr) {
60 return false;
61 }
62 return HasFlag(attr.value(), flag);
63}
64
65static 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
76bool 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
87static 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
107static Array<String> MergeKeys(Optional<Array<String>> existing_keys) {
108 const Array<String> kExtraKeys = {"arm_cpu", "cpu"};
109
110 if (!existing_keys) {
111 return kExtraKeys;
112 }
113
114 Array<String> keys = existing_keys.value();
115 for (String key : kExtraKeys) {
116 if (std::find(keys.begin(), keys.end(), key) == keys.end()) {
117 keys.push_back(key);
118 }
119 }
120 return keys;
121}
122
123TargetJSON ParseTarget(TargetJSON target) {
124 target.Set("features", GetFeatures(target));
125 target.Set("keys", MergeKeys(Downcast<Optional<Array<String>>>(target.Get("keys"))));
126
127 return target;
128}
129
130} // namespace mprofile
131} // namespace parsers
132} // namespace target
133} // namespace tvm
134