diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc index a4877c9dedb..d864f5eda3a 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.cc +++ b/runtime/vm/compiler/assembler/assembler_arm.cc @@ -419,7 +419,8 @@ void Assembler::EmitDivOp(Condition cond, int32_t encoding = opcode | (static_cast(cond) << kConditionShift) | (static_cast(rn) << kDivRnShift) | (static_cast(rd) << kDivRdShift) | B26 | B25 | - B24 | B20 | B4 | (static_cast(rm) << kDivRmShift); + B24 | B20 | B15 | B14 | B13 | B12 | B4 | + (static_cast(rm) << kDivRmShift); Emit(encoding); } diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h index 5571bca5e0f..7371cd066b9 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.h +++ b/runtime/vm/compiler/assembler/assembler_arm.h @@ -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, diff --git a/runtime/vm/compiler/assembler/assembler_arm_test.cc b/runtime/vm/compiler/assembler/assembler_arm_test.cc index 55dfe6a1d7f..8ec2f45de47 100644 --- a/runtime/vm/compiler/assembler/assembler_arm_test.cc +++ b/runtime/vm/compiler/assembler/assembler_arm_test.cc @@ -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)); } diff --git a/runtime/vm/compiler/assembler/disassembler.cc b/runtime/vm/compiler/assembler/disassembler.cc index d4f93d51d1c..d252cc016e9 100644 --- a/runtime/vm/compiler/assembler/disassembler.cc +++ b/runtime/vm/compiler/assembler/disassembler.cc @@ -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_++ = '.'; diff --git a/runtime/vm/compiler/assembler/disassembler_arm.cc b/runtime/vm/compiler/assembler/disassembler_arm.cc index 3654dbe1940..7fbdac869ec 100644 --- a/runtime/vm/compiler/assembler/disassembler_arm.cc +++ b/runtime/vm/compiler/assembler/disassembler_arm.cc @@ -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"); diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc index 1c63d1bc377..d40147b2ea0 100644 --- a/runtime/vm/cpu_arm.cc +++ b/runtime/vm/cpu_arm.cc @@ -15,10 +15,9 @@ #include #elif defined(DART_HOST_OS_WINDOWS) #include -#endif -#if !defined(DART_HOST_OS_WINDOWS) -#include /* NOLINT */ -#include /* NOLINT */ +#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) +#include +#include #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.