diff -r 000000000000 -r 6474c204b198 js/src/jit/arm/Architecture-arm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/jit/arm/Architecture-arm.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/arm/Architecture-arm.h" + +#ifndef JS_ARM_SIMULATOR +#include +#endif + +#include +#include + +#include "jit/arm/Assembler-arm.h" + +#define HWCAP_USE_HARDFP_ABI (1 << 28) + +#if !(defined(ANDROID) || defined(MOZ_B2G)) && !defined(JS_ARM_SIMULATOR) +#define HWCAP_ARMv7 (1 << 29) +#include +#else +#define HWCAP_VFP (1<<0) +#define HWCAP_VFPv3 (1<<1) +#define HWCAP_VFPv3D16 (1<<2) +#define HWCAP_VFPv4 (1<<3) +#define HWCAP_IDIVA (1<<4) +#define HWCAP_IDIVT (1<<5) +#define HWCAP_NEON (1<<6) +#define HWCAP_ARMv7 (1<<7) +#endif + +namespace js { +namespace jit { + +uint32_t GetARMFlags() +{ + static bool isSet = false; + static uint32_t flags = 0; + if (isSet) + return flags; + +#ifdef JS_CODEGEN_ARM_HARDFP + flags |= HWCAP_USE_HARDFP_ABI; +#endif + + static const char *env = getenv("ARMHWCAP"); + + if (env && env[0]) { + if (strstr(env, "help")) { + fflush(NULL); + printf( + "\n" + "usage: ARMHWCAP=option,option,option,... where options can be:\n" + "\n" + " armv7 \n" + " vfp \n" + " neon \n" + " vfpv3 \n" + " vfpv3d16 \n" + " vfpv4 \n" + " idiva \n" + " idivt \n" +#if defined(JS_ARM_SIMULATOR) + " hardfp \n" +#endif + "\n" + ); + exit(0); + /*NOTREACHED*/ + } else { + // Canonicalize each token to have a leading and trailing space. + const char *start = env; // Token start. + for (;;) { + char ch = *start; + if (!ch) { + // End of string. + break; + } + if (ch == ' ' || ch == ',') { + // Skip separator characters. + start++; + continue; + } + // Find the end of the token. + const char *end = start + 1; + for (; ; end++) { + ch = *end; + if (!ch || ch == ' ' || ch == ',') + break; + } + size_t count = end - start; + if (count == 3 && strncmp(start, "vfp", 3) == 0) + flags |= HWCAP_VFP; + else if (count == 5 && strncmp(start, "vfpv3", 5) == 0) + flags |= HWCAP_VFPv3; + else if (count == 8 && strncmp(start, "vfpv3d16", 8) == 0) + flags |= HWCAP_VFPv3D16; + else if (count == 5 && strncmp(start, "vfpv4", 5) == 0) + flags |= HWCAP_VFPv4; + else if (count == 5 && strncmp(start, "idiva", 5) == 0) + flags |= HWCAP_IDIVA; + else if (count == 5 && strncmp(start, "idivt", 5) == 0) + flags |= HWCAP_IDIVT; + else if (count == 4 && strncmp(start, "neon", 4) == 0) + flags |= HWCAP_NEON; + else if (count == 5 && strncmp(start, "armv7", 5) == 0) + flags |= HWCAP_ARMv7; +#if defined(JS_ARM_SIMULATOR) + else if (count == 6 && strncmp(start, "hardfp", 6) == 0) + flags |= HWCAP_USE_HARDFP_ABI; +#endif + else + fprintf(stderr, "Warning: unexpected ARMHWCAP flag at: %s\n", start); + start = end; + } +#ifdef DEBUG + IonSpew(IonSpew_Codegen, "ARMHWCAP: '%s'\n flags: 0x%x\n", env, flags); +#endif + isSet = true; + return flags; + } + } + +#ifdef JS_ARM_SIMULATOR + isSet = true; + flags = HWCAP_ARMv7 | HWCAP_VFP | HWCAP_VFPv3 | HWCAP_VFPv4 | HWCAP_NEON; + return flags; +#else + +#if WTF_OS_LINUX + int fd = open("/proc/self/auxv", O_RDONLY); + if (fd > 0) { + Elf32_auxv_t aux; + while (read(fd, &aux, sizeof(Elf32_auxv_t))) { + if (aux.a_type == AT_HWCAP) { + close(fd); + flags = aux.a_un.a_val; + isSet = true; +#if defined(__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__) + // this should really be detected at runtime, but + // /proc/*/auxv doesn't seem to carry the ISA + // I could look in /proc/cpuinfo as well, but + // the chances that it will be different from this + // are low. + flags |= HWCAP_ARMv7; +#endif + return flags; + } + } + close(fd); + } + +#if defined(__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__) + flags = HWCAP_ARMv7; +#endif + isSet = true; + return flags; + +#elif defined(WTF_OS_ANDROID) || defined(MOZ_B2G) + FILE *fp = fopen("/proc/cpuinfo", "r"); + if (!fp) + return false; + + char buf[1024]; + memset(buf, 0, sizeof(buf)); + size_t len = fread(buf, sizeof(char), sizeof(buf) - 2, fp); + fclose(fp); + // Canonicalize each token to have a leading and trailing space. + buf[len] = ' '; + buf[len + 1] = '\0'; + for (size_t i = 0; i < len; i++) { + char ch = buf[i]; + if (!ch) + break; + else if (ch == '\n') + buf[i] = 0x20; + else + buf[i] = ch; + } + + if (strstr(buf, " vfp ")) + flags |= HWCAP_VFP; + + if (strstr(buf, " vfpv3 ")) + flags |= HWCAP_VFPv3; + + if (strstr(buf, " vfpv3d16 ")) + flags |= HWCAP_VFPv3D16; + + if (strstr(buf, " vfpv4 ")) + flags |= HWCAP_VFPv4; + + if (strstr(buf, " idiva ")) + flags |= HWCAP_IDIVA; + + if (strstr(buf, " idivt ")) + flags |= HWCAP_IDIVT; + + if (strstr(buf, " neon ")) + flags |= HWCAP_NEON; + + // not part of the HWCAP flag, but I need to know this, and we're not using + // that bit, so... I'm using it + if (strstr(buf, "ARMv7")) + flags |= HWCAP_ARMv7; + +#ifdef DEBUG + IonSpew(IonSpew_Codegen, "ARMHWCAP: '%s'\n flags: 0x%x\n", buf, flags); +#endif + + isSet = true; + return flags; +#endif + + return 0; +#endif // JS_ARM_SIMULATOR +} + +bool hasMOVWT() +{ + return GetARMFlags() & HWCAP_ARMv7; +} +bool hasVFPv3() +{ + return GetARMFlags() & HWCAP_VFPv3; +} +bool hasVFP() +{ + return GetARMFlags() & HWCAP_VFP; +} + +bool has32DP() +{ + return !(GetARMFlags() & HWCAP_VFPv3D16 && !(GetARMFlags() & HWCAP_NEON)); +} +bool useConvReg() +{ + return has32DP(); +} + +bool hasIDIV() +{ +#if defined HWCAP_IDIVA + return GetARMFlags() & HWCAP_IDIVA; +#else + return false; +#endif +} + +// This is defined in the header and inlined when not using the simulator. +#if defined(JS_ARM_SIMULATOR) +bool useHardFpABI() +{ + return GetARMFlags() & HWCAP_USE_HARDFP_ABI; +} +#endif + +Registers::Code +Registers::FromName(const char *name) +{ + // Check for some register aliases first. + if (strcmp(name, "ip") == 0) + return ip; + if (strcmp(name, "r13") == 0) + return r13; + if (strcmp(name, "lr") == 0) + return lr; + if (strcmp(name, "r15") == 0) + return r15; + + for (size_t i = 0; i < Total; i++) { + if (strcmp(GetName(i), name) == 0) + return Code(i); + } + + return Invalid; +} + +FloatRegisters::Code +FloatRegisters::FromName(const char *name) +{ + for (size_t i = 0; i < Total; i++) { + if (strcmp(GetName(i), name) == 0) + return Code(i); + } + + return Invalid; +} + +} // namespace jit +} // namespace js