1 | /******************************************************************************* |
2 | * Copyright 2021-2022 Intel Corporation |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | *******************************************************************************/ |
16 | |
17 | #ifndef TEST_ISA_COMMON_HPP |
18 | #define TEST_ISA_COMMON_HPP |
19 | |
20 | #include <cassert> |
21 | #include <map> |
22 | #include <set> |
23 | #include <utility> |
24 | #include <type_traits> |
25 | |
26 | // prevent earlier inclusion of dnnl_threads |
27 | #include "test_thread.hpp" |
28 | |
29 | #include "oneapi/dnnl/dnnl.h" |
30 | #include "oneapi/dnnl/dnnl.hpp" |
31 | |
32 | #include "src/cpu/platform.hpp" |
33 | |
34 | #if DNNL_X64 && (DNNL_CPU_RUNTIME != DNNL_RUNTIME_NONE) |
35 | #include "src/cpu/x64/amx_tile_configure.hpp" |
36 | #include "src/cpu/x64/cpu_isa_traits.hpp" |
37 | #endif |
38 | |
39 | namespace dnnl { |
40 | |
41 | #if DNNL_X64 && (DNNL_CPU_RUNTIME != DNNL_RUNTIME_NONE) |
42 | |
43 | inline impl::cpu::x64::cpu_isa_t cvt_to_internal_cpu_isa(cpu_isa input_isa) { |
44 | #define HANDLE_ISA(isa) \ |
45 | case cpu_isa::isa: return impl::cpu::x64::cpu_isa_t::isa; break |
46 | |
47 | switch (input_isa) { |
48 | HANDLE_ISA(sse41); |
49 | HANDLE_ISA(avx); |
50 | HANDLE_ISA(avx2); |
51 | HANDLE_ISA(avx512_core); |
52 | HANDLE_ISA(avx512_core_vnni); |
53 | HANDLE_ISA(avx512_core_bf16); |
54 | HANDLE_ISA(avx512_core_amx); |
55 | HANDLE_ISA(avx2_vnni); |
56 | HANDLE_ISA(avx512_core_fp16); |
57 | HANDLE_ISA(avx2_vnni_2); |
58 | HANDLE_ISA(avx512_core_amx_fp16); |
59 | default: |
60 | assert(input_isa == cpu_isa::isa_default); |
61 | return impl::cpu::x64::cpu_isa_t::isa_all; |
62 | break; |
63 | } |
64 | #undef HANDLE_ISA |
65 | } |
66 | |
67 | // There is no 1-1 correspondence between cpu_isa and internal cpu_isa_t |
68 | // In particular, individual cpu_isa can correspond to more than one cpu_isa_t |
69 | // distinguished by varying combination of feature bits. |
70 | // |
71 | // Note that, for two cpu_isa namely, isa_1 and isa_2 such that isa_1 <= isa_2 |
72 | // the masked_internal_cpu_isa list corresponding to isa_1 will be disjoint from |
73 | // the masked_internal_cpu_isa list for isa_2. This is done so as to avoid |
74 | // the unnecessary duplication. |
75 | // |
76 | // Moreover, by default we don't differentiate internal cpu_isa_t according to |
77 | // the CPU ISA hints |
78 | inline std::set<impl::cpu::x64::cpu_isa_t> masked_internal_cpu_isa( |
79 | cpu_isa isa) { |
80 | using namespace impl::cpu::x64; |
81 | |
82 | cpu_isa_t internal_isa = cvt_to_internal_cpu_isa(isa); |
83 | |
84 | static const std::set<cpu_isa_t> amx_isa_list { |
85 | avx512_core_amx, amx_bf16, amx_int8, amx_tile}; |
86 | |
87 | if (internal_isa == avx512_core_amx) return amx_isa_list; |
88 | return {internal_isa}; |
89 | } |
90 | |
91 | inline std::set<std::pair<impl::cpu::x64::cpu_isa_t, impl::cpu::x64::cpu_isa_t>> |
92 | hints_masked_internal_cpu_isa(cpu_isa_hints hints) { |
93 | using namespace impl::cpu::x64; |
94 | using mask_pair = std::pair<cpu_isa_t, cpu_isa_t>; |
95 | |
96 | switch (hints) { |
97 | case cpu_isa_hints::no_hints: return std::set<mask_pair> {}; break; |
98 | case cpu_isa_hints::prefer_ymm: |
99 | return std::set<mask_pair> { |
100 | {avx512_core_bf16, avx512_core_bf16_ymm}}; |
101 | break; |
102 | default: |
103 | assert(!"unknown CPU ISA hint" ); |
104 | return std::set<mask_pair> {}; |
105 | break; |
106 | } |
107 | } |
108 | |
109 | inline const std::set<cpu_isa> &cpu_isa_list() { |
110 | static const std::set<cpu_isa> isa_list {cpu_isa::sse41, cpu_isa::avx, |
111 | cpu_isa::avx2, cpu_isa::avx2_vnni, cpu_isa::avx2_vnni_2, |
112 | cpu_isa::avx512_core, cpu_isa::avx512_core_vnni, |
113 | cpu_isa::avx512_core_bf16, cpu_isa::avx512_core_fp16, |
114 | cpu_isa::avx512_core_amx, cpu_isa::avx512_core_amx_fp16, |
115 | cpu_isa::isa_default}; |
116 | |
117 | return isa_list; |
118 | } |
119 | |
120 | inline const std::set<cpu_isa> &compatible_cpu_isa(cpu_isa input_isa) { |
121 | // Do not use internal `is_superset` routine as this is used to verify |
122 | // the correctness of cpu_isa_traits routines |
123 | static const std::map<cpu_isa, const std::set<cpu_isa>> isa_cmpt_info { |
124 | {cpu_isa::isa_default, |
125 | {cpu_isa::isa_default, cpu_isa::avx512_core_amx_fp16, |
126 | cpu_isa::avx512_core_amx, cpu_isa::avx512_core_fp16, |
127 | cpu_isa::avx512_core_bf16, |
128 | cpu_isa::avx512_core_vnni, cpu_isa::avx512_core, |
129 | cpu_isa::avx2_vnni_2, cpu_isa::avx2_vnni, |
130 | cpu_isa::avx2, cpu_isa::avx, cpu_isa::sse41}}, |
131 | {cpu_isa::sse41, {cpu_isa::sse41}}, |
132 | {cpu_isa::avx, {cpu_isa::avx, cpu_isa::sse41}}, |
133 | {cpu_isa::avx2, {cpu_isa::avx2, cpu_isa::avx, cpu_isa::sse41}}, |
134 | {cpu_isa::avx2_vnni, |
135 | {cpu_isa::avx2_vnni, cpu_isa::avx2, cpu_isa::avx, |
136 | cpu_isa::sse41}}, |
137 | {cpu_isa::avx2_vnni_2, |
138 | {cpu_isa::avx2_vnni_2, cpu_isa::avx2_vnni, cpu_isa::avx2, |
139 | cpu_isa::avx, cpu_isa::sse41}}, |
140 | {cpu_isa::avx512_core, |
141 | {cpu_isa::avx512_core, cpu_isa::avx2, cpu_isa::avx, |
142 | cpu_isa::sse41}}, |
143 | {cpu_isa::avx512_core_vnni, |
144 | {cpu_isa::avx512_core_vnni, cpu_isa::avx512_core, |
145 | cpu_isa::avx2, cpu_isa::avx, cpu_isa::sse41}}, |
146 | {cpu_isa::avx512_core_bf16, |
147 | {cpu_isa::avx512_core_bf16, cpu_isa::avx512_core_vnni, |
148 | cpu_isa::avx512_core, cpu_isa::avx2, cpu_isa::avx, |
149 | cpu_isa::sse41}}, |
150 | {cpu_isa::avx512_core_fp16, |
151 | {cpu_isa::avx512_core_fp16, cpu_isa::avx512_core_bf16, |
152 | cpu_isa::avx512_core_vnni, cpu_isa::avx512_core, |
153 | cpu_isa::avx2_vnni, cpu_isa::avx2, cpu_isa::avx, |
154 | cpu_isa::sse41}}, |
155 | {cpu_isa::avx512_core_amx, |
156 | {cpu_isa::avx512_core_amx, cpu_isa::avx512_core_fp16, |
157 | cpu_isa::avx512_core_bf16, |
158 | cpu_isa::avx512_core_vnni, cpu_isa::avx512_core, |
159 | cpu_isa::avx2_vnni, cpu_isa::avx2, cpu_isa::avx, |
160 | cpu_isa::sse41}}, |
161 | {cpu_isa::avx512_core_amx_fp16, |
162 | {cpu_isa::avx512_core_amx_fp16, cpu_isa::avx512_core_amx, |
163 | cpu_isa::avx512_core_fp16, |
164 | cpu_isa::avx512_core_bf16, |
165 | cpu_isa::avx512_core_vnni, cpu_isa::avx512_core, |
166 | cpu_isa::avx2_vnni, cpu_isa::avx2, cpu_isa::avx, |
167 | cpu_isa::sse41}}}; |
168 | |
169 | auto iter = isa_cmpt_info.find(input_isa); |
170 | assert(iter != isa_cmpt_info.end()); |
171 | return iter->second; |
172 | } |
173 | |
174 | inline bool is_superset(cpu_isa isa_1, cpu_isa isa_2) { |
175 | const auto &cmpt_list = compatible_cpu_isa(isa_1); |
176 | return cmpt_list.find(isa_2) != cmpt_list.end(); |
177 | } |
178 | |
179 | inline bool is_superset(dnnl_cpu_isa_t isa_1, dnnl_cpu_isa_t isa_2) { |
180 | return is_superset( |
181 | static_cast<cpu_isa>(isa_1), static_cast<cpu_isa>(isa_2)); |
182 | } |
183 | |
184 | inline bool mayiuse(impl::cpu::x64::cpu_isa_t isa, bool soft = false) { |
185 | return impl::cpu::x64::mayiuse(isa, soft); |
186 | } |
187 | |
188 | inline bool mayiuse(cpu_isa isa, bool soft = false) { |
189 | return mayiuse(cvt_to_internal_cpu_isa(isa), soft); |
190 | } |
191 | |
192 | inline bool mayiuse(dnnl_cpu_isa_t isa, bool soft = false) { |
193 | return mayiuse(static_cast<cpu_isa>(isa), soft); |
194 | } |
195 | |
196 | inline cpu_isa get_max_cpu_isa(bool soft = false) { |
197 | for (auto it = cpu_isa_list().crbegin(); it != cpu_isa_list().crend(); |
198 | it++) { |
199 | if (mayiuse(*it, soft)) return *it; |
200 | } |
201 | |
202 | return cpu_isa::isa_default; |
203 | } |
204 | |
205 | inline impl::cpu::x64::cpu_isa_t get_max_cpu_isa_mask(bool soft = false) { |
206 | return impl::cpu::x64::get_max_cpu_isa_mask(soft); |
207 | } |
208 | |
209 | #else |
210 | |
211 | inline bool is_superset(dnnl_cpu_isa_t isa_1, dnnl_cpu_isa_t isa_2) { |
212 | return false; |
213 | } |
214 | |
215 | #endif |
216 | |
217 | } // namespace dnnl |
218 | #endif |
219 | |