summaryrefslogtreecommitdiff
path: root/Runtime/Misc/CPUInfo.cpp
blob: 0d67baf525d2a2692f3e350478aa390624dd9335 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "UnityPrefix.h"
#include "CPUInfo.h"
#if UNITY_ANDROID
	#include <cpu-features.h>
#endif

bool CPUInfo::m_Initialized = false;
bool CPUInfo::m_IsSSESupported = false;
bool CPUInfo::m_IsSSE2Supported = false;
bool CPUInfo::m_IsSSE3Supported = false;
bool CPUInfo::m_IsSupplementalSSE3Supported = false;
bool CPUInfo::m_IsSSE41Supported = false;
bool CPUInfo::m_IsSSE42Supported = false;
bool CPUInfo::m_IsAVXSupported = false;
bool CPUInfo::m_IsAVX2Supported = false;
bool CPUInfo::m_IsAVX512Supported = false;
bool CPUInfo::m_IsFP16CSupported = false;
bool CPUInfo::m_IsFMASupported = false;
bool CPUInfo::m_IsNEONSupported = false;

unsigned int CPUInfo::m_CPUIDFeatures = 0;


#if UNITY_SUPPORTS_SSE

static inline UInt64 xgetbv_impl()
{
#	if defined(__GNUC__) || defined(__clang__)
	UInt32 eax, edx;

	__asm __volatile (
	".byte 0x0f, 0x01, 0xd0" // xgetbv instruction isn't supported by some older assemblers, so just emit it raw
		: "=a"(eax), "=d"(edx) : "c"(0)
	);

	return ((UInt64)edx << 32) | eax;
#	elif defined(_MSC_VER) && !UNITY_XENON
	return _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
#	else
	return 0;
#	endif
}

static void cpuid_ex_impl(UInt32 eax, UInt32 ecx, UInt32* abcd)
{
	#if defined(_MSC_VER)

		__cpuidex((int*)abcd, eax, ecx);

	#else
		UInt32 ebx, edx;
		#if defined(__i386__) && defined (__PIC__)
			// for PIC under 32 bit: EBX can't be modified
			__asm__ ("movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi" : "=D" (ebx), "+a" (eax), "+c" (ecx), "=d" (edx));
		#else
			__asm__ ("cpuid" : "+b" (ebx), "+a" (eax), "+c" (ecx), "=d" (edx));
		#endif
		abcd[0] = eax; abcd[1] = ebx; abcd[2] = ecx; abcd[3] = edx;
	#endif
}

#endif // UNITY_SUPPORTS_SSE


CPUInfo::CPUInfo()
{
#if UNITY_SUPPORTS_SSE
	int data[4] = {0};

	// Add more code here to extract vendor string or what ever is needed
	__cpuid (data, 0);
	unsigned int cpuData0 = data[0];
	unsigned int cpuInfo2 = 0;
	if (cpuData0 >= 1) {
		__cpuid(data, 1);
		cpuInfo2 = data[2];
		m_CPUIDFeatures = data[3];
	}

	// SSE/2 support
	m_IsSSESupported = (m_CPUIDFeatures & CPUID_FEATURES_SSE) != 0;
	m_IsSSE2Supported = (m_CPUIDFeatures & CPUID_FEATURES_SSE2) != 0;
	
	// SSE 3.x
	m_IsSSE3Supported = ((cpuInfo2 & (1<<0)) != 0);
	m_IsSupplementalSSE3Supported = ((cpuInfo2 & (1<<9)) != 0);

	// SSE 4.x support
	m_IsSSE41Supported = ((cpuInfo2 & (1<<19)) != 0);
	m_IsSSE42Supported = ((cpuInfo2 & (1<<20)) != 0);

	// AVX support
	m_IsAVXSupported =
		((cpuInfo2 & (1<<28)) != 0) && // AVX support in CPU
		((cpuInfo2 & (1<<27)) != 0) && // OS support for AVX (XSAVE/XRESTORE on context switches)
		((xgetbv_impl() & 6) == 6); // XMM & YMM registers will be preserved on context switches
	
	if (m_IsAVXSupported)
	{
		if (cpuData0 >= 7)
		{
			UInt32 regs7[4] = {0};
			cpuid_ex_impl(0x7, 0, regs7);
			m_IsAVX2Supported = ((regs7[1] & (1<<5)) != 0);
			m_IsAVX512Supported = ((regs7[1] & (1<<16)) != 0);
		}
	}

	m_IsFP16CSupported = ((cpuInfo2 & (1<<29)) != 0);
	m_IsFMASupported = ((cpuInfo2 & (1<<12)) != 0);

#elif UNITY_ANDROID && UNITY_SUPPORTS_NEON
	m_CPUIDFeatures = android_getCpuFeatures();
	m_IsNEONSupported = (m_CPUIDFeatures & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
#endif

	m_Initialized = true;
}

CPUInfo g_cpuInfo;