michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* compile-time and runtime tests for whether to use various ARM extensions */ michael@0: michael@0: #include "mozilla/NullPtr.h" michael@0: michael@0: #include "arm.h" michael@0: michael@0: #if defined(MOZILLA_ARM_HAVE_CPUID_DETECTION) michael@0: namespace { michael@0: michael@0: // arm.h has parallel #ifs which declare MOZILLA_ARM_HAVE_CPUID_DETECTION. michael@0: // We don't check it here so that we get compile errors if it's defined, but michael@0: // we don't compile one of these detection methods. The detection code here is michael@0: // based on the CPU detection in libtheora. michael@0: michael@0: # if defined(_MSC_VER) michael@0: //For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION. michael@0: # define WIN32_LEAN_AND_MEAN michael@0: # define WIN32_EXTRA_LEAN michael@0: # include michael@0: michael@0: # if !defined(MOZILLA_PRESUME_EDSP) michael@0: static bool michael@0: check_edsp(void) michael@0: { michael@0: # if defined(MOZILLA_MAY_SUPPORT_EDSP) michael@0: __try michael@0: { michael@0: //PLD [r13] michael@0: __emit(0xF5DDF000); michael@0: return true; michael@0: } michael@0: __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION) michael@0: { michael@0: //Ignore exception. michael@0: } michael@0: # endif michael@0: return false; michael@0: } michael@0: # endif // !MOZILLA_PRESUME_EDSP michael@0: michael@0: # if !defined(MOZILLA_PRESUME_ARMV6) michael@0: static bool michael@0: check_armv6(void) michael@0: { michael@0: # if defined(MOZILLA_MAY_SUPPORT_ARMV6) michael@0: __try michael@0: { michael@0: //SHADD8 r3,r3,r3 michael@0: __emit(0xE6333F93); michael@0: return true; michael@0: } michael@0: __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION) michael@0: { michael@0: //Ignore exception. michael@0: } michael@0: # endif michael@0: return false; michael@0: } michael@0: # endif // !MOZILLA_PRESUME_ARMV6 michael@0: michael@0: # if !defined(MOZILLA_PRESUME_ARMV7) michael@0: static bool michael@0: check_armv7(void) michael@0: { michael@0: # if defined(MOZILLA_MAY_SUPPORT_ARMV7) michael@0: __try michael@0: { michael@0: // ARMv7 DMB (Data Memory Barrier) for stores (DMB.ST) michael@0: // The Data Memory Barrier existed before ARMv7 as a michael@0: // cp15 operation, but ARMv7 introduced a dedicated michael@0: // instruction, DMB. michael@0: emit(0xF57FF05E); michael@0: return true; michael@0: } michael@0: __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION) michael@0: { michael@0: //Ignore exception. michael@0: } michael@0: # endif michael@0: return false; michael@0: } michael@0: # endif // !MOZILLA_PRESUME_ARMV7 michael@0: michael@0: # if !defined(MOZILLA_PRESUME_NEON) michael@0: static bool michael@0: check_neon(void) michael@0: { michael@0: # if defined(MOZILLA_MAY_SUPPORT_NEON) michael@0: __try michael@0: { michael@0: //VORR q0,q0,q0 michael@0: __emit(0xF2200150); michael@0: return true; michael@0: } michael@0: __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION) michael@0: { michael@0: //Ignore exception. michael@0: } michael@0: # endif michael@0: return false; michael@0: } michael@0: # endif // !MOZILLA_PRESUME_NEON michael@0: michael@0: # elif defined(__linux__) || defined(ANDROID) michael@0: # include michael@0: # include michael@0: # include michael@0: michael@0: enum{ michael@0: MOZILLA_HAS_EDSP_FLAG=1, michael@0: MOZILLA_HAS_ARMV6_FLAG=2, michael@0: MOZILLA_HAS_ARMV7_FLAG=4, michael@0: MOZILLA_HAS_NEON_FLAG=8 michael@0: }; michael@0: michael@0: static unsigned michael@0: get_arm_cpu_flags(void) michael@0: { michael@0: unsigned flags; michael@0: FILE *fin; michael@0: bool armv6_processor = false; michael@0: flags = 0; michael@0: /*Reading /proc/self/auxv would be easier, but that doesn't work reliably on michael@0: Android. This also means that detection will fail in Scratchbox, which is michael@0: desirable, as NEON does not work in the qemu shipped with the Maemo 5 SDK. michael@0: I don't know if /proc/self/auxv would do any better in that case, anyway, michael@0: or if it would return random flags from the host CPU.*/ michael@0: fin = fopen ("/proc/cpuinfo","r"); michael@0: if (fin != nullptr) michael@0: { michael@0: /*512 should be enough for anybody (it's even enough for all the flags that michael@0: x86 has accumulated... so far).*/ michael@0: char buf[512]; michael@0: while (fgets(buf, 511, fin) != nullptr) michael@0: { michael@0: if (memcmp(buf, "Features", 8) == 0) michael@0: { michael@0: char *p; michael@0: p = strstr(buf, " edsp"); michael@0: if (p != nullptr && (p[5] == ' ' || p[5] == '\n')) michael@0: flags |= MOZILLA_HAS_EDSP_FLAG; michael@0: p = strstr(buf, " neon"); michael@0: if( p != nullptr && (p[5] == ' ' || p[5] == '\n')) michael@0: flags |= MOZILLA_HAS_NEON_FLAG; michael@0: } michael@0: if (memcmp(buf, "CPU architecture:", 17) == 0) michael@0: { michael@0: int version; michael@0: version = atoi(buf + 17); michael@0: if (version >= 6) michael@0: flags |= MOZILLA_HAS_ARMV6_FLAG; michael@0: if (version >= 7) michael@0: flags |= MOZILLA_HAS_ARMV7_FLAG; michael@0: } michael@0: /* media/webrtc/trunk/src/system_wrappers/source/cpu_features_arm.c michael@0: * Unfortunately, it seems that certain ARMv6-based CPUs michael@0: * report an incorrect architecture number of 7! michael@0: * michael@0: * We try to correct this by looking at the 'elf_format' michael@0: * field reported by the 'Processor' field, which is of the michael@0: * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for michael@0: * an ARMv6-one. michael@0: */ michael@0: if (memcmp(buf, "Processor\t:", 11) == 0) { michael@0: if (strstr(buf, "(v6l)") != 0) { michael@0: armv6_processor = true; michael@0: } michael@0: } michael@0: } michael@0: fclose(fin); michael@0: } michael@0: if (armv6_processor) { michael@0: // ARMv6 pretending to be ARMv7? clear flag michael@0: if (flags & MOZILLA_HAS_ARMV7_FLAG) { michael@0: flags &= ~MOZILLA_HAS_ARMV7_FLAG; michael@0: } michael@0: } michael@0: return flags; michael@0: } michael@0: michael@0: // Cache a local copy so we only have to read /proc/cpuinfo once. michael@0: static unsigned arm_cpu_flags = get_arm_cpu_flags(); michael@0: michael@0: # if !defined(MOZILLA_PRESUME_EDSP) michael@0: static bool michael@0: check_edsp(void) michael@0: { michael@0: return (arm_cpu_flags & MOZILLA_HAS_EDSP_FLAG) != 0; michael@0: } michael@0: # endif michael@0: michael@0: # if !defined(MOZILLA_PRESUME_ARMV6) michael@0: static bool michael@0: check_armv6(void) michael@0: { michael@0: return (arm_cpu_flags & MOZILLA_HAS_ARMV6_FLAG) != 0; michael@0: } michael@0: # endif michael@0: michael@0: # if !defined(MOZILLA_PRESUME_ARMV7) michael@0: static bool michael@0: check_armv7(void) michael@0: { michael@0: return (arm_cpu_flags & MOZILLA_HAS_ARMV7_FLAG) != 0; michael@0: } michael@0: # endif michael@0: michael@0: # if !defined(MOZILLA_PRESUME_NEON) michael@0: static bool michael@0: check_neon(void) michael@0: { michael@0: return (arm_cpu_flags & MOZILLA_HAS_NEON_FLAG) != 0; michael@0: } michael@0: # endif michael@0: michael@0: # endif // defined(__linux__) || defined(ANDROID) michael@0: michael@0: } michael@0: michael@0: namespace mozilla { michael@0: namespace arm_private { michael@0: # if !defined(MOZILLA_PRESUME_EDSP) michael@0: bool edsp_enabled = check_edsp(); michael@0: # endif michael@0: # if !defined(MOZILLA_PRESUME_ARMV6) michael@0: bool armv6_enabled = check_armv6(); michael@0: # endif michael@0: # if !defined(MOZILLA_PRESUME_ARMV7) michael@0: bool armv7_enabled = check_armv7(); michael@0: # endif michael@0: # if !defined(MOZILLA_PRESUME_NEON) michael@0: bool neon_enabled = check_neon(); michael@0: # endif michael@0: } // namespace arm_private michael@0: } // namespace mozilla michael@0: michael@0: #endif // MOZILLA_ARM_HAVE_CPUID_DETECTION