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
39namespace dnnl {
40
41#if DNNL_X64 && (DNNL_CPU_RUNTIME != DNNL_RUNTIME_NONE)
42
43inline 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
78inline 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
91inline std::set<std::pair<impl::cpu::x64::cpu_isa_t, impl::cpu::x64::cpu_isa_t>>
92hints_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
109inline 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
120inline 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
174inline 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
179inline 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
184inline bool mayiuse(impl::cpu::x64::cpu_isa_t isa, bool soft = false) {
185 return impl::cpu::x64::mayiuse(isa, soft);
186}
187
188inline bool mayiuse(cpu_isa isa, bool soft = false) {
189 return mayiuse(cvt_to_internal_cpu_isa(isa), soft);
190}
191
192inline bool mayiuse(dnnl_cpu_isa_t isa, bool soft = false) {
193 return mayiuse(static_cast<cpu_isa>(isa), soft);
194}
195
196inline 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
205inline 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
211inline 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