mirror of
https://github.com/dart-lang/sdk
synced 2024-10-15 00:28:05 +00:00
[vm] Use AT_HWCAP instead of /proc/cpuinfo for most ARM feature detection.
Under user-space emulation or 32-bit ARM on a 64-bit ARM system, /proc/cpuinfo describes the host CPU instead of the emulated ARM CPU. Also fix the encoding of sdiv. Apparently QEMU is stricter than hardware. TEST=ci Bug: https://github.com/dart-lang/sdk/issues/29270 Bug: https://github.com/dart-lang/sdk/issues/54909 Change-Id: Icadf1a276e468dbb8142da49f961f33bca499d27 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/352680 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Slava Egorov <vegorov@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
19aa44bd10
commit
688917045f
|
@ -419,7 +419,8 @@ void Assembler::EmitDivOp(Condition cond,
|
|||
int32_t encoding = opcode | (static_cast<int32_t>(cond) << kConditionShift) |
|
||||
(static_cast<int32_t>(rn) << kDivRnShift) |
|
||||
(static_cast<int32_t>(rd) << kDivRdShift) | B26 | B25 |
|
||||
B24 | B20 | B4 | (static_cast<int32_t>(rm) << kDivRmShift);
|
||||
B24 | B20 | B15 | B14 | B13 | B12 | B4 |
|
||||
(static_cast<int32_t>(rm) << kDivRmShift);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,9 @@ enum {
|
|||
B10 = 1 << 10,
|
||||
B11 = 1 << 11,
|
||||
B12 = 1 << 12,
|
||||
B13 = 1 << 13,
|
||||
B14 = 1 << 14,
|
||||
B15 = 1 << 15,
|
||||
B16 = 1 << 16,
|
||||
B17 = 1 << 17,
|
||||
B18 = 1 << 18,
|
||||
|
|
|
@ -65,6 +65,13 @@ TEST_CASE(ReciprocalOps) {
|
|||
|
||||
#define __ assembler->
|
||||
|
||||
#if defined(PRODUCT)
|
||||
#define EXPECT_DISASSEMBLY(expected)
|
||||
#else
|
||||
#define EXPECT_DISASSEMBLY(expected) \
|
||||
EXPECT_STREQ(expected, test->RelativeDisassembly())
|
||||
#endif
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Simple, assembler) {
|
||||
__ mov(R0, Operand(42));
|
||||
__ Ret();
|
||||
|
@ -1746,6 +1753,12 @@ ASSEMBLER_TEST_RUN(Udiv, test) {
|
|||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
typedef int (*Tst)() DART_UNUSED;
|
||||
EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
|
||||
EXPECT_DISASSEMBLY(
|
||||
"e3a0001b mov r0, #27\n"
|
||||
"e3a01009 mov r1, #9\n"
|
||||
"e732f110 udiv r2, r0, r1\n"
|
||||
"e1a00002 mov r0, r2\n"
|
||||
"e12fff1e bx lr\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1764,6 +1777,12 @@ ASSEMBLER_TEST_RUN(Sdiv, test) {
|
|||
if (TargetCPUFeatures::integer_division_supported()) {
|
||||
typedef int (*Tst)() DART_UNUSED;
|
||||
EXPECT_EQ(-3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
|
||||
EXPECT_DISASSEMBLY(
|
||||
"e3a0001b mov r0, #27\n"
|
||||
"e3e01008 mvn r1, #8\n"
|
||||
"e712f110 sdiv r2, r0, r1\n"
|
||||
"e1a00002 mov r0, r2\n"
|
||||
"e12fff1e bx lr\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3423,7 +3442,7 @@ ASSEMBLER_TEST_GENERATE(Vminqs_zero, assembler) {
|
|||
ASSEMBLER_TEST_RUN(Vminqs_zero, test) {
|
||||
EXPECT(test != nullptr);
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
typedef int (*Tst)() DART_UNUSED;
|
||||
typedef float (*Tst)() DART_UNUSED;
|
||||
float res = EXECUTE_TEST_CODE_FLOAT(Tst, test->entry());
|
||||
EXPECT_EQ(true, signbit(res) && (res == 0.0));
|
||||
}
|
||||
|
@ -3474,7 +3493,7 @@ ASSEMBLER_TEST_GENERATE(Vmaxqs_zero, assembler) {
|
|||
ASSEMBLER_TEST_RUN(Vmaxqs_zero, test) {
|
||||
EXPECT(test != nullptr);
|
||||
if (TargetCPUFeatures::neon_supported()) {
|
||||
typedef int (*Tst)() DART_UNUSED;
|
||||
typedef float (*Tst)() DART_UNUSED;
|
||||
float res = EXECUTE_TEST_CODE_FLOAT(Tst, test->entry());
|
||||
EXPECT_EQ(true, !signbit(res) && (res == 0.0));
|
||||
}
|
||||
|
|
|
@ -75,7 +75,8 @@ void DisassembleToMemory::ConsumeInstruction(char* hex_buffer,
|
|||
|
||||
// TODO(compiler): Update assembler tests for other architectures so there is
|
||||
// coverage of encodings, not just mnemonics.
|
||||
#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
|
||||
#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64) || \
|
||||
defined(TARGET_ARCH_ARM)
|
||||
len = strlen(hex_buffer);
|
||||
if (remaining_ < len + 100) {
|
||||
*buffer_++ = '.';
|
||||
|
|
|
@ -947,9 +947,9 @@ void ARMDecoder::DecodeType3(Instr* instr) {
|
|||
static_assert(kDivRnShift == kRmShift,
|
||||
"div 'rn does not correspond to 'rm");
|
||||
if (instr->IsDivUnsigned()) {
|
||||
Format(instr, "udiv'cond 'rn, 'rs, 'rm");
|
||||
Format(instr, "udiv'cond 'rn, 'rm, 'rs");
|
||||
} else {
|
||||
Format(instr, "sdiv'cond 'rn, 'rs, 'rm");
|
||||
Format(instr, "sdiv'cond 'rn, 'rm, 'rs");
|
||||
}
|
||||
} else if (instr->IsRbit()) {
|
||||
Format(instr, "rbit'cond 'rd, 'rm");
|
||||
|
|
|
@ -15,10 +15,9 @@
|
|||
#include <libkern/OSCacheControl.h>
|
||||
#elif defined(DART_HOST_OS_WINDOWS)
|
||||
#include <processthreadsapi.h>
|
||||
#endif
|
||||
#if !defined(DART_HOST_OS_WINDOWS)
|
||||
#include <string.h> /* NOLINT */
|
||||
#include <sys/utsname.h> /* NOLINT */
|
||||
#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
#include <asm/hwcap.h>
|
||||
#include <sys/auxv.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -140,72 +139,37 @@ void HostCPUFeatures::Init() {
|
|||
}
|
||||
#else // DART_HOST_OS_IOS
|
||||
void HostCPUFeatures::Init() {
|
||||
bool is_arm64 = false;
|
||||
// Reading /proc/cpuinfo under QEMU can report the host CPU instead of the
|
||||
// emulated CPU.
|
||||
unsigned long hwcap = getauxval(AT_HWCAP); // NOLINT
|
||||
integer_division_supported_ = (hwcap & HWCAP_IDIVA) != 0;
|
||||
neon_supported_ = (hwcap & HWCAP_NEON) != 0;
|
||||
|
||||
CpuInfo::Init();
|
||||
hardware_ = CpuInfo::GetCpuModel();
|
||||
|
||||
// QEMU may report host cpuinfo instead of emulated cpuinfo, use uname as a
|
||||
// fallback for checking if CPU is AArch64 or ARMv7.
|
||||
struct utsname uname_;
|
||||
int ret_ = uname(&uname_);
|
||||
|
||||
// Check for ARMv7, or aarch64.
|
||||
// It can be in either the Processor or Model information fields.
|
||||
if (CpuInfo::FieldContains(kCpuInfoProcessor, "aarch64") ||
|
||||
CpuInfo::FieldContains(kCpuInfoModel, "aarch64") ||
|
||||
CpuInfo::FieldContains(kCpuInfoArchitecture, "8") ||
|
||||
CpuInfo::FieldContains(kCpuInfoArchitecture, "AArch64") ||
|
||||
(ret_ == 0 && (strstr(uname_.machine, "aarch64") != nullptr ||
|
||||
strstr(uname_.machine, "arm64") != nullptr ||
|
||||
strstr(uname_.machine, "armv8") != nullptr))) {
|
||||
// pretend that this arm64 cpu is really an ARMv7
|
||||
is_arm64 = true;
|
||||
} else if (!CpuInfo::FieldContains(kCpuInfoProcessor, "ARMv7") &&
|
||||
!CpuInfo::FieldContains(kCpuInfoModel, "ARMv7") &&
|
||||
!CpuInfo::FieldContains(kCpuInfoArchitecture, "7") &&
|
||||
!(ret_ == 0 && strstr(uname_.machine, "armv7") != nullptr)) {
|
||||
FATAL("Unrecognized ARM CPU architecture.");
|
||||
// Qualcomm Krait CPUs (QCT APQ8064) in Nexus 4 and 7 incorrectly report that
|
||||
// they lack integer division.
|
||||
if (CpuInfo::FieldContains(kCpuInfoHardware, "QCT APQ8064")) {
|
||||
integer_division_supported_ = true;
|
||||
}
|
||||
// Marvell Armada 370/XP incorrectly reports that it has integer division.
|
||||
if (CpuInfo::FieldContains(kCpuInfoHardware, "Marvell Armada 370/XP")) {
|
||||
integer_division_supported_ = false;
|
||||
}
|
||||
// Some Android ARM emulators claim support for integer division but do not
|
||||
// actually support it.
|
||||
if (CpuInfo::FieldContains(kCpuInfoHardware, "Dummy Virtual Machine")) {
|
||||
integer_division_supported_ = false;
|
||||
}
|
||||
|
||||
// Has integer division.
|
||||
// Special cases:
|
||||
// - Qualcomm Krait CPUs (QCT APQ8064) in Nexus 4 and 7 incorrectly report
|
||||
// that they lack integer division.
|
||||
// - Marvell Armada 370/XP incorrectly reports that it has integer division.
|
||||
bool is_krait = CpuInfo::FieldContains(kCpuInfoHardware, "QCT APQ8064");
|
||||
bool is_armada_370xp =
|
||||
CpuInfo::FieldContains(kCpuInfoHardware, "Marvell Armada 370/XP");
|
||||
bool is_virtual_machine =
|
||||
CpuInfo::FieldContains(kCpuInfoHardware, "Dummy Virtual Machine");
|
||||
#if defined(DART_HOST_OS_ANDROID)
|
||||
bool is_android = true;
|
||||
#else
|
||||
bool is_android = false;
|
||||
#endif
|
||||
if (is_krait) {
|
||||
integer_division_supported_ = FLAG_use_integer_division;
|
||||
} else if (is_android && is_arm64) {
|
||||
// Various Android ARM64 devices, including the Qualcomm Snapdragon 820/821
|
||||
// CPUs (MSM 8996 and MSM8996pro) in Xiaomi MI5 and Pixel lack integer
|
||||
// division even though ARMv8 requires it in A32. Instead of attempting to
|
||||
// track all of these devices, we conservatively disable use of integer
|
||||
// division on Android ARM64 devices.
|
||||
// TODO(29270): /proc/self/auxv might be more reliable here.
|
||||
// Allow flags to override feature detection.
|
||||
if (!FLAG_use_integer_division) {
|
||||
integer_division_supported_ = false;
|
||||
} else if (is_armada_370xp) {
|
||||
integer_division_supported_ = false;
|
||||
} else if (is_android && !is_arm64 && is_virtual_machine) {
|
||||
// Some Android ARM emulators claim support for integer division in
|
||||
// /proc/cpuinfo but do not actually support it.
|
||||
integer_division_supported_ = false;
|
||||
} else {
|
||||
integer_division_supported_ =
|
||||
(CpuInfo::FieldContains(kCpuInfoFeatures, "idiva") || is_arm64) &&
|
||||
FLAG_use_integer_division;
|
||||
}
|
||||
neon_supported_ =
|
||||
(CpuInfo::FieldContains(kCpuInfoFeatures, "neon") || is_arm64) &&
|
||||
FLAG_use_neon;
|
||||
if (!FLAG_use_neon) {
|
||||
neon_supported_ = false;
|
||||
}
|
||||
|
||||
// Use the cross-compiler's predefined macros to determine whether we should
|
||||
// use the hard or soft float ABI.
|
||||
|
|
Loading…
Reference in a new issue