• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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