1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2016 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkCpu.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOnce.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if !defined(__has_include)
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #define __has_include(x) 0
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if defined(SK_CPU_X86)
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #if defined(SK_BUILD_FOR_WIN)
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #include <intrin.h>
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static void cpuid (uint32_t abcd[4]) { __cpuid  ((int*)abcd, 1);    }
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static void cpuid7(uint32_t abcd[4]) { __cpuidex((int*)abcd, 7, 0); }
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static uint64_t xgetbv(uint32_t xcr) { return _xgetbv(xcr); }
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #else
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #include <cpuid.h>
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #if !defined(__cpuid_count)  // Old Mac Clang doesn't have this defined.
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            #define  __cpuid_count(eax, ecx, a, b, c, d) \
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                __asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(eax), "2"(ecx))
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #endif
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static void cpuid (uint32_t abcd[4]) { __get_cpuid(1, abcd+0, abcd+1, abcd+2, abcd+3); }
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static void cpuid7(uint32_t abcd[4]) {
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            __cpuid_count(7, 0, abcd[0], abcd[1], abcd[2], abcd[3]);
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static uint64_t xgetbv(uint32_t xcr) {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint32_t eax, edx;
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            __asm__ __volatile__ ( "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return (uint64_t)(edx) << 32 | eax;
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #endif
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static uint32_t read_cpu_features() {
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t features = 0;
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t abcd[4] = {0,0,0,0};
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // You might want to refer to http://www.sandpile.org/x86/cpuid.htm
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        cpuid(abcd);
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (abcd[3] & (1<<25)) { features |= SkCpu:: SSE1; }
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (abcd[3] & (1<<26)) { features |= SkCpu:: SSE2; }
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (abcd[2] & (1<< 0)) { features |= SkCpu:: SSE3; }
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (abcd[2] & (1<< 9)) { features |= SkCpu::SSSE3; }
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (abcd[2] & (1<<19)) { features |= SkCpu::SSE41; }
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (abcd[2] & (1<<20)) { features |= SkCpu::SSE42; }
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if ((abcd[2] & (3<<26)) == (3<<26)         // XSAVE + OSXSAVE
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot             && (xgetbv(0) & (3<<1)) == (3<<1)) {  // XMM and YMM state enabled.
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (abcd[2] & (1<<28)) { features |= SkCpu:: AVX; }
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (abcd[2] & (1<<29)) { features |= SkCpu::F16C; }
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (abcd[2] & (1<<12)) { features |= SkCpu:: FMA; }
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cpuid7(abcd);
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (abcd[1] & (1<<5)) { features |= SkCpu::AVX2; }
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (abcd[1] & (1<<3)) { features |= SkCpu::BMI1; }
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (abcd[1] & (1<<8)) { features |= SkCpu::BMI2; }
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if ((xgetbv(0) & (7<<5)) == (7<<5)) {  // All ZMM state bits enabled too.
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (abcd[1] & (1<<16)) { features |= SkCpu::AVX512F; }
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (abcd[1] & (1<<17)) { features |= SkCpu::AVX512DQ; }
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (abcd[1] & (1<<21)) { features |= SkCpu::AVX512IFMA; }
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (abcd[1] & (1<<26)) { features |= SkCpu::AVX512PF; }
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (abcd[1] & (1<<27)) { features |= SkCpu::AVX512ER; }
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (abcd[1] & (1<<28)) { features |= SkCpu::AVX512CD; }
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (abcd[1] & (1<<30)) { features |= SkCpu::AVX512BW; }
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (abcd[1] & (1<<31)) { features |= SkCpu::AVX512VL; }
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return features;
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#elif defined(SK_CPU_ARM64) && __has_include(<sys/auxv.h>)
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include <sys/auxv.h>
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static uint32_t read_cpu_features() {
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint32_t kHWCAP_CRC32 = (1<<7);
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t features = 0;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t hwcaps = getauxval(AT_HWCAP);
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (hwcaps & kHWCAP_CRC32) { features |= SkCpu::CRC32; }
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return features;
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#elif defined(SK_CPU_ARM32) && __has_include(<sys/auxv.h>) && \
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    (!defined(__ANDROID_API__) || __ANDROID_API__ >= 18)
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // sys/auxv.h will always be present in the Android NDK due to unified
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //headers, but getauxval is only defined for API >= 18.
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include <sys/auxv.h>
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static uint32_t read_cpu_features() {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint32_t kHWCAP_NEON  = (1<<12);
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint32_t kHWCAP_VFPv4 = (1<<16);
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t features = 0;
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t hwcaps = getauxval(AT_HWCAP);
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (hwcaps & kHWCAP_NEON ) {
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            features |= SkCpu::NEON;
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (hwcaps & kHWCAP_VFPv4) { features |= SkCpu::NEON_FMA|SkCpu::VFP_FP16; }
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return features;
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#elif defined(SK_CPU_ARM32) && __has_include(<cpu-features.h>)
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include <cpu-features.h>
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static uint32_t read_cpu_features() {
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t features = 0;
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint64_t cpu_features = android_getCpuFeatures();
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON)     { features |= SkCpu::NEON; }
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON_FMA) { features |= SkCpu::NEON_FMA; }
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (cpu_features & ANDROID_CPU_ARM_FEATURE_VFP_FP16) { features |= SkCpu::VFP_FP16; }
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return features;
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static uint32_t read_cpu_features() {
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return 0;
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint32_t SkCpu::gCachedFeatures = 0;
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkCpu::CacheRuntimeFeatures() {
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static SkOnce once;
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    once([] { gCachedFeatures = read_cpu_features(); });
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
133