1
2
3 /**
4 * Copyright 2022 Huawei Technologies Co., Ltd
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * 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, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "nnacl/intrinsics/ms_simd_cpu_info.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "nnacl/errorcode.h"
24
25 typedef unsigned int DWORD;
26 struct X86CpuInfoContext {
27 bool fma_flag_;
28 bool sse4_1_flag_;
29 bool avx2_flag_;
30 bool avx512_flag_;
31 };
32
33 static struct X86CpuInfoContext g_x86_cpu_info_context_;
34
X86_Fma_Support(void)35 inline const bool X86_Fma_Support(void) { return g_x86_cpu_info_context_.fma_flag_; }
36
X86_Sse_Support(void)37 inline const bool X86_Sse_Support(void) {
38 #ifdef ENABLE_SSE
39 return g_x86_cpu_info_context_.sse4_1_flag_;
40 #else
41 return false;
42 #endif
43 }
44
X86_Avx_Support(void)45 inline const bool X86_Avx_Support(void) {
46 #ifdef ENABLE_AVX
47 return g_x86_cpu_info_context_.avx2_flag_;
48 #else
49 return false;
50 #endif
51 }
52
X86_Avx512_Support(void)53 inline const bool X86_Avx512_Support(void) {
54 #ifdef ENABLE_AVX512
55 return g_x86_cpu_info_context_.avx512_flag_;
56 #else
57 return false;
58 #endif
59 }
60
ExecuteCpuIdCmd(DWORD cmd_code,DWORD * eax_data,DWORD * ebx_data,DWORD * ecx_data,DWORD * edx_data)61 void ExecuteCpuIdCmd(DWORD cmd_code, DWORD *eax_data, DWORD *ebx_data, DWORD *ecx_data, DWORD *edx_data) {
62 DWORD deax, debx, decx, dedx;
63 asm volatile(
64 "movl %4, %%eax;\n"
65 "movl $0, %%ecx;\n"
66 "cpuid;\n"
67 "movl %%eax, %0;\n"
68 "movl %%ebx, %1;\n"
69 "movl %%ecx, %2;\n"
70 "movl %%edx, %3;\n"
71 : "=r"(deax), "=r"(debx), "=r"(decx), "=r"(dedx)
72 : "r"(cmd_code)
73 : "%eax", "%ebx", "%ecx", "%edx");
74
75 *eax_data = deax;
76 *ebx_data = debx;
77 *ecx_data = decx;
78 *edx_data = dedx;
79 }
80
IsIntelX86Platform(void)81 bool IsIntelX86Platform(void) {
82 DWORD eax_data, ebx_data, ecx_data, edx_data;
83
84 const int vid_info_size = 13;
85 char *vid_info = malloc(sizeof(char) * vid_info_size);
86 memset(vid_info, 0, vid_info_size);
87
88 ExecuteCpuIdCmd(0, &eax_data, &ebx_data, &ecx_data, &edx_data); // eax = 0, execute cpuid to get vid info
89
90 memcpy(vid_info, &ebx_data, 4); // Copy the first 4 characters to the array[0:3]
91 memcpy(vid_info + 4, &edx_data, 4); // Copy the middle 4 characters to the array[4:8]
92 memcpy(vid_info + 8, &ecx_data, 4); // Copy the last 4 characters to the array[8:12]
93
94 int x86_intel_flag = (strcmp(vid_info, "GenuineIntel") == 0 || strcmp(vid_info, "AuthenticAMD") == 0) ? 1 : 0;
95
96 free(vid_info);
97 return x86_intel_flag;
98 }
99
IntelX86CpuInfoInit(void)100 int IntelX86CpuInfoInit(void) {
101 if (!IsIntelX86Platform()) {
102 return NNACL_ERR;
103 }
104 DWORD eax_data, ebx_data, ecx_data, edx_data;
105 ExecuteCpuIdCmd(1, &eax_data, &ebx_data, &ecx_data, &edx_data); // eax = 1, execute cpuid to get sse/fma flag
106 g_x86_cpu_info_context_.sse4_1_flag_ = (ecx_data & (1 << 19)) == 0 ? false : true; // sse flag is ecx 19 bit
107 g_x86_cpu_info_context_.fma_flag_ = (ecx_data & (1 << 12)) == 0 ? false : true; // fma flag is ecx 12 bit
108
109 ExecuteCpuIdCmd(7, &eax_data, &ebx_data, &ecx_data, &edx_data); // eax = 7, execute cpuid to get avx2/avx512 flag
110 g_x86_cpu_info_context_.avx2_flag_ = (ebx_data & (1 << 5)) == 0 ? false : true; // avx2 flag is ecx 5 bit
111 g_x86_cpu_info_context_.avx512_flag_ = (ebx_data & (1 << 16)) == 0 ? false : true; // avx512 flag is ecx 16 bit
112
113 return NNACL_OK;
114 }
115
IntelX86InstructionSetSupportCheck(void)116 X86CpuInfoErrorCodeEnum IntelX86InstructionSetSupportCheck(void) {
117 if (IntelX86CpuInfoInit() != NNACL_OK) {
118 return X86CPUINFO_PLATFORM_ERR;
119 }
120 #if defined(ENABLE_AVX512) && !defined(AVX512_HARDWARE_SELF_AWARENESS)
121 if (!X86_Avx512_Support()) {
122 return X86CPUINFO_AVX512_ERR;
123 }
124 #endif
125
126 #ifdef ENABLE_AVX
127 if (!X86_Avx_Support()) {
128 return X86CPUINFO_AVX_ERR;
129 }
130 #endif
131
132 #ifdef ENABLE_SSE
133 if (!X86_Sse_Support()) {
134 return X86CPUINFO_SSE_ERR;
135 }
136 #endif
137 return X86CPUINFO_OK;
138 }
139