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" , |
40 | "cortex-m33" , "cortex-m35p" , "cortex-m85" }; |
41 | static const char* mveCPUs[] = {"cortex-m55" , "cortex-m85" }; |
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 Array<String> = {"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 | |
123 | TargetJSON 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 | |