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